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:
parent
5aa424fa3d
commit
a9607ba090
3 changed files with 155 additions and 6 deletions
59
datatypes.go
59
datatypes.go
|
@ -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)
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
// TODO: Implement marshalling for Placement
|
||||
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
|
||||
|
||||
|
@ -38,8 +82,10 @@ type Ptr struct {
|
|||
unit *Unit
|
||||
}
|
||||
|
||||
func (p Ptr) CanResolve() bool { return strings.HasPrefix(p.Target, ".") }
|
||||
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
51
helpers.go
Normal 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
51
helpers_test.go
Normal 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)
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue