• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

mlange-42 / arche-serde / 7492902207

11 Jan 2024 06:20PM CUT coverage: 83.929% (+0.2%) from 83.766%
7492902207

Pull #3

github

web-flow
Merge 26a1fd02e into 8937cb386
Pull Request #3: Serialize entity relations

188 of 224 relevant lines covered (83.93%)

31.19 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

76.09
/deserialize.go
1
package archeserde
2

3
import (
4
        "encoding/json"
5
        "fmt"
6
        "reflect"
7

8
        "github.com/mlange-42/arche/ecs"
9
)
10

11
// Deserialize an Arche [ecs.World] from JSON.
12
//
13
// The world must be prepared the following way:
14
//   - All required component types must be registered using [ecs.ComponentID]
15
//   - All required resources must be added using [ecs.AddResource]
16
//
17
// After deserialization, it is not guaranteed that entity iteration order in queries is the same as before.
18
func Deserialize(jsonData []byte, world *ecs.World) error {
3✔
19
        deserial := deserializer{}
3✔
20
        if err := json.Unmarshal(jsonData, &deserial); err != nil {
3✔
21
                return err
×
22
        }
×
23

24
        world.SetEntityData(&deserial.World)
3✔
25

3✔
26
        if err := deserializeComponents(world, &deserial); err != nil {
3✔
27
                return err
×
28
        }
×
29
        if err := deserializeResources(world, &deserial); err != nil {
3✔
30
                return err
×
31
        }
×
32

33
        return nil
3✔
34
}
35

36
func deserializeComponents(world *ecs.World, deserial *deserializer) error {
3✔
37
        infos := map[ecs.ID]ecs.CompInfo{}
3✔
38
        ids := map[string]ecs.ID{}
3✔
39
        for i := 0; i < ecs.MaskTotalBits; i++ {
771✔
40
                if info, ok := ecs.ComponentInfo(world, ecs.ID(i)); ok {
773✔
41
                        infos[ecs.ID(i)] = info
5✔
42
                        ids[info.Type.String()] = ecs.ID(i)
5✔
43
                }
5✔
44
        }
45

46
        for _, tp := range deserial.Types {
8✔
47
                if _, ok := ids[tp]; !ok {
5✔
48
                        return fmt.Errorf("component type is not registered: %s", tp)
×
49
                }
×
50
        }
51

52
        for i, comps := range deserial.Components {
8✔
53
                entity := deserial.World.Entities[deserial.World.Alive[i]]
5✔
54

5✔
55
                mp := map[string]entry{}
5✔
56

5✔
57
                if err := json.Unmarshal(comps.Bytes, &mp); err != nil {
5✔
58
                        return err
×
59
                }
×
60

61
                target := ecs.Entity{}
5✔
62
                var targetComp ecs.ID
5✔
63
                components := []ecs.Component{}
5✔
64
                for tpName, value := range mp {
16✔
65
                        if tpName == targetTag {
13✔
66
                                if err := json.Unmarshal(value.Bytes, &target); err != nil {
2✔
67
                                        return err
×
68
                                }
×
69
                                continue
2✔
70
                        }
71

72
                        id := ids[tpName]
9✔
73
                        info := infos[id]
9✔
74

9✔
75
                        if info.IsRelation {
11✔
76
                                targetComp = id
2✔
77
                        }
2✔
78

79
                        component := reflect.New(info.Type).Interface()
9✔
80
                        if err := json.Unmarshal(value.Bytes, &component); err != nil {
9✔
81
                                return err
×
82
                        }
×
83
                        components = append(components, ecs.Component{
9✔
84
                                ID:   id,
9✔
85
                                Comp: component,
9✔
86
                        })
9✔
87
                }
88

89
                world.Assign(entity, components...)
5✔
90
                if !target.IsZero() {
6✔
91
                        world.Relations().Set(entity, targetComp, target)
1✔
92
                }
1✔
93
        }
94
        return nil
3✔
95
}
96

97
func deserializeResources(world *ecs.World, deserial *deserializer) error {
3✔
98
        resTypes := map[ecs.ResID]reflect.Type{}
3✔
99
        resIds := map[string]ecs.ResID{}
3✔
100
        for i := 0; i < ecs.MaskTotalBits; i++ {
771✔
101
                if tp, ok := ecs.ResourceType(world, ecs.ResID(i)); ok {
770✔
102
                        resTypes[ecs.ResID(i)] = tp
2✔
103
                        resIds[tp.String()] = ecs.ResID(i)
2✔
104
                }
2✔
105
        }
106

107
        for tpName, res := range deserial.Resources {
5✔
108
                resID, ok := resIds[tpName]
2✔
109
                if !ok {
2✔
110
                        return fmt.Errorf("resource type is not registered: %s", tpName)
×
111
                }
×
112

113
                tp := resTypes[resID]
2✔
114
                resource := reflect.New(tp).Interface()
2✔
115
                if err := json.Unmarshal(res.Bytes, &resource); err != nil {
2✔
116
                        return err
×
117
                }
×
118

119
                resLoc := world.Resources().Get(resID)
2✔
120
                if resLoc == nil {
2✔
121
                        return fmt.Errorf("resource type registered but nil: %s", tpName)
×
122
                }
×
123

124
                rValue := reflect.ValueOf(resLoc)
2✔
125
                ptr := rValue.UnsafePointer()
2✔
126
                value := reflect.NewAt(tp, ptr).Interface()
2✔
127

2✔
128
                if err := json.Unmarshal(res.Bytes, &value); err != nil {
2✔
129
                        return err
×
130
                }
×
131
        }
132
        return nil
3✔
133
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc