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

mlange-42 / arche-serde / 7494943208

11 Jan 2024 09:50PM CUT coverage: 84.141% (+0.2%) from 83.929%
7494943208

push

github

web-flow
Entity builder for relations (#4)

Use an `ecs.Builder` to create entities with targets in one command.

This should (?) result in an initial entity/query order exactly like in the serialized world.
Over time, however, the query iteration order will deviate in both worlds.

191 of 227 relevant lines covered (84.14%)

30.83 hits per line

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

89.06
/serialize.go
1
package archeserde
2

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

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

12
const targetTag = "arche.relation.Target"
13

14
// Serialize an Arche [ecs.World] to JSON.
15
//
16
// Serializes the following:
17
//   - Entities and the entity pool
18
//   - All components of all entities
19
//   - All resources
20
//
21
// All components and resources must be "JSON-able" with [encoding/json].
22
func Serialize(world *ecs.World) ([]byte, error) {
3✔
23
        builder := strings.Builder{}
3✔
24

3✔
25
        builder.WriteString("{\n")
3✔
26

3✔
27
        if err := serializeWorld(world, &builder); err != nil {
3✔
28
                return nil, err
×
29
        }
×
30
        builder.WriteString(",\n")
3✔
31

3✔
32
        serializeTypes(world, &builder)
3✔
33
        builder.WriteString(",\n")
3✔
34

3✔
35
        if err := serializeComponents(world, &builder); err != nil {
3✔
36
                return nil, err
×
37
        }
×
38
        builder.WriteString(",\n")
3✔
39

3✔
40
        if err := serializeResources(world, &builder); err != nil {
3✔
41
                return nil, err
×
42
        }
×
43
        builder.WriteString("}\n")
3✔
44

3✔
45
        return []byte(builder.String()), nil
3✔
46
}
47

48
func serializeWorld(world *ecs.World, builder *strings.Builder) error {
3✔
49
        entities := world.GetEntityData()
3✔
50

3✔
51
        jsonData, err := json.Marshal(entities)
3✔
52
        if err != nil {
3✔
53
                return err
×
54
        }
×
55
        if err != nil {
3✔
56
                return err
×
57
        }
×
58
        builder.WriteString(fmt.Sprintf("\"World\" : %s", string(jsonData)))
3✔
59
        return nil
3✔
60
}
61

62
func serializeTypes(world *ecs.World, builder *strings.Builder) {
3✔
63
        builder.WriteString("\"Types\" : [\n")
3✔
64

3✔
65
        types := map[ecs.ID]reflect.Type{}
3✔
66
        for i := 0; i < ecs.MaskTotalBits; i++ {
771✔
67
                if info, ok := ecs.ComponentInfo(world, ecs.ID(i)); ok {
773✔
68
                        types[ecs.ID(i)] = info.Type
5✔
69
                }
5✔
70
        }
71
        maxComp := len(types) - 1
3✔
72
        counter := 0
3✔
73
        for _, tp := range types {
8✔
74
                builder.WriteString(fmt.Sprintf("  \"%s\"", tp.String()))
5✔
75
                if counter < maxComp {
8✔
76
                        builder.WriteString(",")
3✔
77
                }
3✔
78
                builder.WriteString("\n")
5✔
79
                counter++
5✔
80
        }
81

82
        builder.WriteString("]")
3✔
83
}
84

85
func serializeComponents(world *ecs.World, builder *strings.Builder) error {
3✔
86

3✔
87
        builder.WriteString("\"Components\" : [\n")
3✔
88

3✔
89
        query := world.Query(ecs.All())
3✔
90
        lastEntity := query.Count() - 1
3✔
91
        counter := 0
3✔
92
        for query.Next() {
8✔
93
                builder.WriteString("  {\n")
5✔
94

5✔
95
                ids := query.Ids()
5✔
96
                last := len(ids) - 1
5✔
97

5✔
98
                for i, id := range ids {
14✔
99
                        info, _ := ecs.ComponentInfo(world, id)
9✔
100

9✔
101
                        if info.IsRelation {
11✔
102
                                target := query.Relation(id)
2✔
103
                                builder.WriteString(fmt.Sprintf("    \"%s\" : [%d,%d],\n", targetTag, target.ID(), target.Gen()))
2✔
104
                        }
2✔
105

106
                        comp := query.Get(id)
9✔
107
                        value := reflect.NewAt(info.Type, comp).Interface()
9✔
108
                        jsonData, err := json.Marshal(value)
9✔
109
                        if err != nil {
9✔
110
                                return err
×
111
                        }
×
112
                        builder.WriteString(fmt.Sprintf("    \"%s\" : ", info.Type.String()))
9✔
113
                        builder.WriteString(string(jsonData))
9✔
114
                        if i < last {
13✔
115
                                builder.WriteString(",")
4✔
116
                        }
4✔
117
                        builder.WriteString("\n")
9✔
118
                }
119

120
                builder.WriteString("  }")
5✔
121
                if counter < lastEntity {
8✔
122
                        builder.WriteString(",")
3✔
123
                }
3✔
124
                builder.WriteString("\n")
5✔
125

5✔
126
                counter++
5✔
127
        }
128
        builder.WriteString("]")
3✔
129

3✔
130
        return nil
3✔
131
}
132

133
func serializeResources(world *ecs.World, builder *strings.Builder) error {
3✔
134
        builder.WriteString("\"Resources\" : {\n")
3✔
135

3✔
136
        resTypes := map[ecs.ResID]reflect.Type{}
3✔
137
        for i := 0; i < ecs.MaskTotalBits; i++ {
771✔
138
                if tp, ok := ecs.ResourceType(world, ecs.ResID(i)); ok {
770✔
139
                        resTypes[ecs.ResID(i)] = tp
2✔
140
                }
2✔
141
        }
142

143
        last := len(resTypes) - 1
3✔
144
        counter := 0
3✔
145
        for id, tp := range resTypes {
5✔
146
                res := world.Resources().Get(id)
2✔
147
                rValue := reflect.ValueOf(res)
2✔
148
                ptr := rValue.UnsafePointer()
2✔
149

2✔
150
                value := reflect.NewAt(tp, ptr).Interface()
2✔
151
                jsonData, err := json.Marshal(value)
2✔
152
                if err != nil {
2✔
153
                        return err
×
154
                }
×
155

156
                builder.WriteString("    ")
2✔
157
                builder.WriteString(fmt.Sprintf("\"%s\" : ", tp.String()))
2✔
158
                builder.WriteString(string(jsonData))
2✔
159

2✔
160
                if counter < last {
3✔
161
                        builder.WriteString(",")
1✔
162
                }
1✔
163
                builder.WriteString("\n")
2✔
164
                counter++
2✔
165
        }
166

167
        builder.WriteString("}")
3✔
168

3✔
169
        return nil
3✔
170
}
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