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

Add placement reading

Signed-off-by: Knut Ahlers <knut@ahlers.me>
This commit is contained in:
Knut Ahlers 2019-11-06 14:51:29 +01:00
parent 5aa424fa3d
commit a9607ba090
Signed by: luzifer
GPG key ID: DC2729FDD34BE99E
3 changed files with 155 additions and 6 deletions

View file

@ -1,6 +1,12 @@
package sii
import "strings"
import (
"bytes"
"regexp"
"strings"
"github.com/pkg/errors"
)
// See https://modding.scssoft.com/wiki/Documentation/Engine/Units
@ -10,12 +16,50 @@ import "strings"
// float2-4 => [2]float - [4]float
type Placement struct {
X, Y, Z float64
W, X2, Y2, Z2 float64
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 = [][]byte{}
for _, f := range p {
b, err := float2sii(f)
if err != nil {
return nil, errors.Wrap(err, "Unable to encode float")
}
siiFloats = append(siiFloats, b)
}
// TODO: Implement marshalling for Placement
var buf = new(bytes.Buffer)
buf.Write([]byte("("))
bytes.Join(siiFloats[0:3], []byte(", "))
buf.Write([]byte(") ("))
buf.Write(siiFloats[3])
buf.Write([]byte("; "))
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
@ -39,7 +83,9 @@ type Ptr struct {
}
func (p Ptr) CanResolve() bool { return strings.HasPrefix(p.Target, ".") }
func (p Ptr) MarshalSII() []byte { return []byte(p.Target) }
func (p Ptr) Resolve() Block {
if p.Target == "null" {
return nil
@ -52,6 +98,7 @@ func (p Ptr) Resolve() Block {
}
return nil
}
func (p *Ptr) UnmarshalSII(in []byte) error {
p.Target = string(in)
return nil

51
helpers.go Normal file
View file

@ -0,0 +1,51 @@
package sii
import (
"bytes"
"encoding/binary"
"encoding/hex"
"strconv"
"github.com/pkg/errors"
)
func float2sii(f float32) ([]byte, error) {
var (
buf = new(bytes.Buffer)
err error
)
err = binary.Write(buf, binary.BigEndian, f)
if err != nil {
return nil, errors.Wrap(err, "Unable to encode float")
}
dst := make([]byte, hex.EncodedLen(buf.Len()))
hex.Encode(dst, buf.Bytes())
return append([]byte("&"), dst...), nil
}
func sii2float(f []byte) (float32, error) {
if f[0] != '&' {
out, err := strconv.ParseFloat(string(f), 32)
return float32(out), err
}
// Strip leading '&'
f = f[1:]
var (
err error
out float32
)
dst := make([]byte, hex.DecodedLen(len(f)))
_, err = hex.Decode(dst, f)
if err != nil {
return 0, errors.Wrap(err, "Unable to read hex format")
}
err = binary.Read(bytes.NewReader(dst), binary.BigEndian, &out)
return out, errors.Wrap(err, "Unable to decode hex notation")
}

51
helpers_test.go Normal file
View file

@ -0,0 +1,51 @@
package sii
import "testing"
func TestSii2FloatConversion(t *testing.T) {
var (
err error
f float32
)
for b, exp := range map[string]float32{
"0.00250711967": 0.00250711967,
"1.0": 1.0,
"&3b244e7d": 0.00250711967,
"&3f46da61": 0.7767697,
"&47135818": 37720.0938,
} {
f, err = sii2float([]byte(b))
if err != nil {
t.Errorf("Conversion of %q failed: %s", b, err)
continue
}
if f != exp {
t.Errorf("Conversion of %q has unxpected result: %f != %f", b, f, exp)
}
}
}
func TestFloat2SiiConversion(t *testing.T) {
var (
err error
f []byte
)
for b, exp := range map[float32]string{
0.00250711967: "&3b244e7d",
0.7767697: "&3f46da61",
37720.0938: "&47135818",
} {
f, err = float2sii(b)
if err != nil {
t.Errorf("Conversion of %f failed: %s", b, err)
continue
}
if string(f) != exp {
t.Errorf("Conversion of %f has unxpected result: %s != %s", b, f, exp)
}
}
}