holosphere 1.0.2 → 1.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/hexlib.js +332 -0
- package/index.js +192 -26
- package/package.json +2 -2
package/hexlib.js
ADDED
|
@@ -0,0 +1,332 @@
|
|
|
1
|
+
// Generated code -- CC0 -- No Rights Reserved -- http://www.redblobgames.com/grids/hexagons/
|
|
2
|
+
export class Point {
|
|
3
|
+
constructor(x, y) {
|
|
4
|
+
this.x = x;
|
|
5
|
+
this.y = y;
|
|
6
|
+
}
|
|
7
|
+
}
|
|
8
|
+
export class Hex {
|
|
9
|
+
constructor(q, r, s) {
|
|
10
|
+
this.q = q;
|
|
11
|
+
this.r = r;
|
|
12
|
+
this.s = s;
|
|
13
|
+
if (Math.round(q + r + s) !== 0)
|
|
14
|
+
throw "q + r + s must be 0";
|
|
15
|
+
}
|
|
16
|
+
add(b) {
|
|
17
|
+
return new Hex(this.q + b.q, this.r + b.r, this.s + b.s);
|
|
18
|
+
}
|
|
19
|
+
subtract(b) {
|
|
20
|
+
return new Hex(this.q - b.q, this.r - b.r, this.s - b.s);
|
|
21
|
+
}
|
|
22
|
+
scale(k) {
|
|
23
|
+
return new Hex(this.q * k, this.r * k, this.s * k);
|
|
24
|
+
}
|
|
25
|
+
rotateLeft() {
|
|
26
|
+
return new Hex(-this.s, -this.q, -this.r);
|
|
27
|
+
}
|
|
28
|
+
rotateRight() {
|
|
29
|
+
return new Hex(-this.r, -this.s, -this.q);
|
|
30
|
+
}
|
|
31
|
+
static direction(direction) {
|
|
32
|
+
return Hex.directions[direction];
|
|
33
|
+
}
|
|
34
|
+
neighbor(direction) {
|
|
35
|
+
return this.add(Hex.direction(direction));
|
|
36
|
+
}
|
|
37
|
+
diagonalNeighbor(direction) {
|
|
38
|
+
return this.add(Hex.diagonals[direction]);
|
|
39
|
+
}
|
|
40
|
+
len() {
|
|
41
|
+
return (Math.abs(this.q) + Math.abs(this.r) + Math.abs(this.s)) / 2;
|
|
42
|
+
}
|
|
43
|
+
distance(b) {
|
|
44
|
+
return this.subtract(b).len();
|
|
45
|
+
}
|
|
46
|
+
round() {
|
|
47
|
+
var qi = Math.round(this.q);
|
|
48
|
+
var ri = Math.round(this.r);
|
|
49
|
+
var si = Math.round(this.s);
|
|
50
|
+
var q_diff = Math.abs(qi - this.q);
|
|
51
|
+
var r_diff = Math.abs(ri - this.r);
|
|
52
|
+
var s_diff = Math.abs(si - this.s);
|
|
53
|
+
if (q_diff > r_diff && q_diff > s_diff) {
|
|
54
|
+
qi = -ri - si;
|
|
55
|
+
}
|
|
56
|
+
else if (r_diff > s_diff) {
|
|
57
|
+
ri = -qi - si;
|
|
58
|
+
}
|
|
59
|
+
else {
|
|
60
|
+
si = -qi - ri;
|
|
61
|
+
}
|
|
62
|
+
return new Hex(qi, ri, si);
|
|
63
|
+
}
|
|
64
|
+
lerp(b, t) {
|
|
65
|
+
return new Hex(this.q * (1.0 - t) + b.q * t, this.r * (1.0 - t) + b.r * t, this.s * (1.0 - t) + b.s * t);
|
|
66
|
+
}
|
|
67
|
+
linedraw(b) {
|
|
68
|
+
var N = this.distance(b);
|
|
69
|
+
var a_nudge = new Hex(this.q + 1e-06, this.r + 1e-06, this.s - 2e-06);
|
|
70
|
+
var b_nudge = new Hex(b.q + 1e-06, b.r + 1e-06, b.s - 2e-06);
|
|
71
|
+
var results = [];
|
|
72
|
+
var step = 1.0 / Math.max(N, 1);
|
|
73
|
+
for (var i = 0; i <= N; i++) {
|
|
74
|
+
results.push(a_nudge.lerp(b_nudge, step * i).round());
|
|
75
|
+
}
|
|
76
|
+
return results;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
Hex.directions = [new Hex(1, 0, -1), new Hex(1, -1, 0), new Hex(0, -1, 1), new Hex(-1, 0, 1), new Hex(-1, 1, 0), new Hex(0, 1, -1)];
|
|
80
|
+
Hex.diagonals = [new Hex(2, -1, -1), new Hex(1, -2, 1), new Hex(-1, -1, 2), new Hex(-2, 1, 1), new Hex(-1, 2, -1), new Hex(1, 1, -2)];
|
|
81
|
+
export class OffsetCoord {
|
|
82
|
+
constructor(col, row) {
|
|
83
|
+
this.col = col;
|
|
84
|
+
this.row = row;
|
|
85
|
+
}
|
|
86
|
+
static qoffsetFromCube(offset, h) {
|
|
87
|
+
var col = h.q;
|
|
88
|
+
var row = h.r + (h.q + offset * (h.q & 1)) / 2;
|
|
89
|
+
if (offset !== OffsetCoord.EVEN && offset !== OffsetCoord.ODD) {
|
|
90
|
+
throw "offset must be EVEN (+1) or ODD (-1)";
|
|
91
|
+
}
|
|
92
|
+
return new OffsetCoord(col, row);
|
|
93
|
+
}
|
|
94
|
+
static qoffsetToCube(offset, h) {
|
|
95
|
+
var q = h.col;
|
|
96
|
+
var r = h.row - (h.col + offset * (h.col & 1)) / 2;
|
|
97
|
+
var s = -q - r;
|
|
98
|
+
if (offset !== OffsetCoord.EVEN && offset !== OffsetCoord.ODD) {
|
|
99
|
+
throw "offset must be EVEN (+1) or ODD (-1)";
|
|
100
|
+
}
|
|
101
|
+
return new Hex(q, r, s);
|
|
102
|
+
}
|
|
103
|
+
static roffsetFromCube(offset, h) {
|
|
104
|
+
var col = h.q + (h.r + offset * (h.r & 1)) / 2;
|
|
105
|
+
var row = h.r;
|
|
106
|
+
if (offset !== OffsetCoord.EVEN && offset !== OffsetCoord.ODD) {
|
|
107
|
+
throw "offset must be EVEN (+1) or ODD (-1)";
|
|
108
|
+
}
|
|
109
|
+
return new OffsetCoord(col, row);
|
|
110
|
+
}
|
|
111
|
+
static roffsetToCube(offset, h) {
|
|
112
|
+
var q = h.col - (h.row + offset * (h.row & 1)) / 2;
|
|
113
|
+
var r = h.row;
|
|
114
|
+
var s = -q - r;
|
|
115
|
+
if (offset !== OffsetCoord.EVEN && offset !== OffsetCoord.ODD) {
|
|
116
|
+
throw "offset must be EVEN (+1) or ODD (-1)";
|
|
117
|
+
}
|
|
118
|
+
return new Hex(q, r, s);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
OffsetCoord.EVEN = 1;
|
|
122
|
+
OffsetCoord.ODD = -1;
|
|
123
|
+
export class DoubledCoord {
|
|
124
|
+
constructor(col, row) {
|
|
125
|
+
this.col = col;
|
|
126
|
+
this.row = row;
|
|
127
|
+
}
|
|
128
|
+
static qdoubledFromCube(h) {
|
|
129
|
+
var col = h.q;
|
|
130
|
+
var row = 2 * h.r + h.q;
|
|
131
|
+
return new DoubledCoord(col, row);
|
|
132
|
+
}
|
|
133
|
+
qdoubledToCube() {
|
|
134
|
+
var q = this.col;
|
|
135
|
+
var r = (this.row - this.col) / 2;
|
|
136
|
+
var s = -q - r;
|
|
137
|
+
return new Hex(q, r, s);
|
|
138
|
+
}
|
|
139
|
+
static rdoubledFromCube(h) {
|
|
140
|
+
var col = 2 * h.q + h.r;
|
|
141
|
+
var row = h.r;
|
|
142
|
+
return new DoubledCoord(col, row);
|
|
143
|
+
}
|
|
144
|
+
rdoubledToCube() {
|
|
145
|
+
var q = (this.col - this.row) / 2;
|
|
146
|
+
var r = this.row;
|
|
147
|
+
var s = -q - r;
|
|
148
|
+
return new Hex(q, r, s);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
export class Orientation {
|
|
152
|
+
constructor(f0, f1, f2, f3, b0, b1, b2, b3, start_angle) {
|
|
153
|
+
this.f0 = f0;
|
|
154
|
+
this.f1 = f1;
|
|
155
|
+
this.f2 = f2;
|
|
156
|
+
this.f3 = f3;
|
|
157
|
+
this.b0 = b0;
|
|
158
|
+
this.b1 = b1;
|
|
159
|
+
this.b2 = b2;
|
|
160
|
+
this.b3 = b3;
|
|
161
|
+
this.start_angle = start_angle;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
export class Layout {
|
|
165
|
+
constructor(orientation, size, origin) {
|
|
166
|
+
this.orientation = orientation;
|
|
167
|
+
this.size = size;
|
|
168
|
+
this.origin = origin;
|
|
169
|
+
}
|
|
170
|
+
hexToPixel(h) {
|
|
171
|
+
var M = this.orientation;
|
|
172
|
+
var size = this.size;
|
|
173
|
+
var origin = this.origin;
|
|
174
|
+
var x = (M.f0 * h.q + M.f1 * h.r) * size.x;
|
|
175
|
+
var y = (M.f2 * h.q + M.f3 * h.r) * size.y;
|
|
176
|
+
return new Point(x + origin.x, y + origin.y);
|
|
177
|
+
}
|
|
178
|
+
pixelToHex(p) {
|
|
179
|
+
var M = this.orientation;
|
|
180
|
+
var size = this.size;
|
|
181
|
+
var origin = this.origin;
|
|
182
|
+
var pt = new Point((p.x - origin.x) / size.x, (p.y - origin.y) / size.y);
|
|
183
|
+
var q = M.b0 * pt.x + M.b1 * pt.y;
|
|
184
|
+
var r = M.b2 * pt.x + M.b3 * pt.y;
|
|
185
|
+
return new Hex(q, r, -q - r);
|
|
186
|
+
}
|
|
187
|
+
hexCornerOffset(corner) {
|
|
188
|
+
var M = this.orientation;
|
|
189
|
+
var size = this.size;
|
|
190
|
+
var angle = 2.0 * Math.PI * (M.start_angle - corner) / 6.0;
|
|
191
|
+
return new Point(size.x * Math.cos(angle), size.y * Math.sin(angle));
|
|
192
|
+
}
|
|
193
|
+
polygonCorners(h) {
|
|
194
|
+
var corners = [];
|
|
195
|
+
var center = this.hexToPixel(h);
|
|
196
|
+
for (var i = 0; i < 6; i++) {
|
|
197
|
+
var offset = this.hexCornerOffset(i);
|
|
198
|
+
corners.push(new Point(center.x + offset.x, center.y + offset.y));
|
|
199
|
+
}
|
|
200
|
+
return corners;
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
Layout.pointy = new Orientation(Math.sqrt(3.0), Math.sqrt(3.0) / 2.0, 0.0, 3.0 / 2.0, Math.sqrt(3.0) / 3.0, -1.0 / 3.0, 0.0, 2.0 / 3.0, 0.5);
|
|
204
|
+
Layout.flat = new Orientation(3.0 / 2.0, 0.0, Math.sqrt(3.0) / 2.0, Math.sqrt(3.0), 2.0 / 3.0, 0.0, -1.0 / 3.0, Math.sqrt(3.0) / 3.0, 0.0);
|
|
205
|
+
class Tests {
|
|
206
|
+
constructor() { }
|
|
207
|
+
static equalHex(name, a, b) {
|
|
208
|
+
if (!(a.q === b.q && a.s === b.s && a.r === b.r)) {
|
|
209
|
+
complain(name);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
static equalOffsetcoord(name, a, b) {
|
|
213
|
+
if (!(a.col === b.col && a.row === b.row)) {
|
|
214
|
+
complain(name);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
static equalDoubledcoord(name, a, b) {
|
|
218
|
+
if (!(a.col === b.col && a.row === b.row)) {
|
|
219
|
+
complain(name);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
static equalInt(name, a, b) {
|
|
223
|
+
if (!(a === b)) {
|
|
224
|
+
complain(name);
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
static equalHexArray(name, a, b) {
|
|
228
|
+
Tests.equalInt(name, a.length, b.length);
|
|
229
|
+
for (var i = 0; i < a.length; i++) {
|
|
230
|
+
Tests.equalHex(name, a[i], b[i]);
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
static testHexArithmetic() {
|
|
234
|
+
Tests.equalHex("hex_add", new Hex(4, -10, 6), new Hex(1, -3, 2).add(new Hex(3, -7, 4)));
|
|
235
|
+
Tests.equalHex("hex_subtract", new Hex(-2, 4, -2), new Hex(1, -3, 2).subtract(new Hex(3, -7, 4)));
|
|
236
|
+
}
|
|
237
|
+
static testHexDirection() {
|
|
238
|
+
Tests.equalHex("hex_direction", new Hex(0, -1, 1), Hex.direction(2));
|
|
239
|
+
}
|
|
240
|
+
static testHexNeighbor() {
|
|
241
|
+
Tests.equalHex("hex_neighbor", new Hex(1, -3, 2), new Hex(1, -2, 1).neighbor(2));
|
|
242
|
+
}
|
|
243
|
+
static testHexDiagonal() {
|
|
244
|
+
Tests.equalHex("hex_diagonal", new Hex(-1, -1, 2), new Hex(1, -2, 1).diagonalNeighbor(3));
|
|
245
|
+
}
|
|
246
|
+
static testHexDistance() {
|
|
247
|
+
Tests.equalInt("hex_distance", 7, new Hex(3, -7, 4).distance(new Hex(0, 0, 0)));
|
|
248
|
+
}
|
|
249
|
+
static testHexRotateRight() {
|
|
250
|
+
Tests.equalHex("hex_rotate_right", new Hex(1, -3, 2).rotateRight(), new Hex(3, -2, -1));
|
|
251
|
+
}
|
|
252
|
+
static testHexRotateLeft() {
|
|
253
|
+
Tests.equalHex("hex_rotate_left", new Hex(1, -3, 2).rotateLeft(), new Hex(-2, -1, 3));
|
|
254
|
+
}
|
|
255
|
+
static testHexRound() {
|
|
256
|
+
var a = new Hex(0.0, 0.0, 0.0);
|
|
257
|
+
var b = new Hex(1.0, -1.0, 0.0);
|
|
258
|
+
var c = new Hex(0.0, -1.0, 1.0);
|
|
259
|
+
Tests.equalHex("hex_round 1", new Hex(5, -10, 5), new Hex(0.0, 0.0, 0.0).lerp(new Hex(10.0, -20.0, 10.0), 0.5).round());
|
|
260
|
+
Tests.equalHex("hex_round 2", a.round(), a.lerp(b, 0.499).round());
|
|
261
|
+
Tests.equalHex("hex_round 3", b.round(), a.lerp(b, 0.501).round());
|
|
262
|
+
Tests.equalHex("hex_round 4", a.round(), new Hex(a.q * 0.4 + b.q * 0.3 + c.q * 0.3, a.r * 0.4 + b.r * 0.3 + c.r * 0.3, a.s * 0.4 + b.s * 0.3 + c.s * 0.3).round());
|
|
263
|
+
Tests.equalHex("hex_round 5", c.round(), new Hex(a.q * 0.3 + b.q * 0.3 + c.q * 0.4, a.r * 0.3 + b.r * 0.3 + c.r * 0.4, a.s * 0.3 + b.s * 0.3 + c.s * 0.4).round());
|
|
264
|
+
}
|
|
265
|
+
static testHexLinedraw() {
|
|
266
|
+
Tests.equalHexArray("hex_linedraw", [new Hex(0, 0, 0), new Hex(0, -1, 1), new Hex(0, -2, 2), new Hex(1, -3, 2), new Hex(1, -4, 3), new Hex(1, -5, 4)], new Hex(0, 0, 0).linedraw(new Hex(1, -5, 4)));
|
|
267
|
+
}
|
|
268
|
+
static testLayout() {
|
|
269
|
+
var h = new Hex(3, 4, -7);
|
|
270
|
+
var flat = new Layout(Layout.flat, new Point(10.0, 15.0), new Point(35.0, 71.0));
|
|
271
|
+
Tests.equalHex("layout", h, flat.pixelToHex(flat.hexToPixel(h)).round());
|
|
272
|
+
var pointy = new Layout(Layout.pointy, new Point(10.0, 15.0), new Point(35.0, 71.0));
|
|
273
|
+
Tests.equalHex("layout", h, pointy.pixelToHex(pointy.hexToPixel(h)).round());
|
|
274
|
+
}
|
|
275
|
+
static testOffsetRoundtrip() {
|
|
276
|
+
var a = new Hex(3, 4, -7);
|
|
277
|
+
var b = new OffsetCoord(1, -3);
|
|
278
|
+
Tests.equalHex("conversion_roundtrip even-q", a, OffsetCoord.qoffsetToCube(OffsetCoord.EVEN, OffsetCoord.qoffsetFromCube(OffsetCoord.EVEN, a)));
|
|
279
|
+
Tests.equalOffsetcoord("conversion_roundtrip even-q", b, OffsetCoord.qoffsetFromCube(OffsetCoord.EVEN, OffsetCoord.qoffsetToCube(OffsetCoord.EVEN, b)));
|
|
280
|
+
Tests.equalHex("conversion_roundtrip odd-q", a, OffsetCoord.qoffsetToCube(OffsetCoord.ODD, OffsetCoord.qoffsetFromCube(OffsetCoord.ODD, a)));
|
|
281
|
+
Tests.equalOffsetcoord("conversion_roundtrip odd-q", b, OffsetCoord.qoffsetFromCube(OffsetCoord.ODD, OffsetCoord.qoffsetToCube(OffsetCoord.ODD, b)));
|
|
282
|
+
Tests.equalHex("conversion_roundtrip even-r", a, OffsetCoord.roffsetToCube(OffsetCoord.EVEN, OffsetCoord.roffsetFromCube(OffsetCoord.EVEN, a)));
|
|
283
|
+
Tests.equalOffsetcoord("conversion_roundtrip even-r", b, OffsetCoord.roffsetFromCube(OffsetCoord.EVEN, OffsetCoord.roffsetToCube(OffsetCoord.EVEN, b)));
|
|
284
|
+
Tests.equalHex("conversion_roundtrip odd-r", a, OffsetCoord.roffsetToCube(OffsetCoord.ODD, OffsetCoord.roffsetFromCube(OffsetCoord.ODD, a)));
|
|
285
|
+
Tests.equalOffsetcoord("conversion_roundtrip odd-r", b, OffsetCoord.roffsetFromCube(OffsetCoord.ODD, OffsetCoord.roffsetToCube(OffsetCoord.ODD, b)));
|
|
286
|
+
}
|
|
287
|
+
static testOffsetFromCube() {
|
|
288
|
+
Tests.equalOffsetcoord("offset_from_cube even-q", new OffsetCoord(1, 3), OffsetCoord.qoffsetFromCube(OffsetCoord.EVEN, new Hex(1, 2, -3)));
|
|
289
|
+
Tests.equalOffsetcoord("offset_from_cube odd-q", new OffsetCoord(1, 2), OffsetCoord.qoffsetFromCube(OffsetCoord.ODD, new Hex(1, 2, -3)));
|
|
290
|
+
}
|
|
291
|
+
static testOffsetToCube() {
|
|
292
|
+
Tests.equalHex("offset_to_cube even-", new Hex(1, 2, -3), OffsetCoord.qoffsetToCube(OffsetCoord.EVEN, new OffsetCoord(1, 3)));
|
|
293
|
+
Tests.equalHex("offset_to_cube odd-q", new Hex(1, 2, -3), OffsetCoord.qoffsetToCube(OffsetCoord.ODD, new OffsetCoord(1, 2)));
|
|
294
|
+
}
|
|
295
|
+
static testDoubledRoundtrip() {
|
|
296
|
+
var a = new Hex(3, 4, -7);
|
|
297
|
+
var b = new DoubledCoord(1, -3);
|
|
298
|
+
Tests.equalHex("conversion_roundtrip doubled-q", a, DoubledCoord.qdoubledFromCube(a).qdoubledToCube());
|
|
299
|
+
Tests.equalDoubledcoord("conversion_roundtrip doubled-q", b, DoubledCoord.qdoubledFromCube(b.qdoubledToCube()));
|
|
300
|
+
Tests.equalHex("conversion_roundtrip doubled-r", a, DoubledCoord.rdoubledFromCube(a).rdoubledToCube());
|
|
301
|
+
Tests.equalDoubledcoord("conversion_roundtrip doubled-r", b, DoubledCoord.rdoubledFromCube(b.rdoubledToCube()));
|
|
302
|
+
}
|
|
303
|
+
static testDoubledFromCube() {
|
|
304
|
+
Tests.equalDoubledcoord("doubled_from_cube doubled-q", new DoubledCoord(1, 5), DoubledCoord.qdoubledFromCube(new Hex(1, 2, -3)));
|
|
305
|
+
Tests.equalDoubledcoord("doubled_from_cube doubled-r", new DoubledCoord(4, 2), DoubledCoord.rdoubledFromCube(new Hex(1, 2, -3)));
|
|
306
|
+
}
|
|
307
|
+
static testDoubledToCube() {
|
|
308
|
+
Tests.equalHex("doubled_to_cube doubled-q", new Hex(1, 2, -3), new DoubledCoord(1, 5).qdoubledToCube());
|
|
309
|
+
Tests.equalHex("doubled_to_cube doubled-r", new Hex(1, 2, -3), new DoubledCoord(4, 2).rdoubledToCube());
|
|
310
|
+
}
|
|
311
|
+
static testAll() {
|
|
312
|
+
Tests.testHexArithmetic();
|
|
313
|
+
Tests.testHexDirection();
|
|
314
|
+
Tests.testHexNeighbor();
|
|
315
|
+
Tests.testHexDiagonal();
|
|
316
|
+
Tests.testHexDistance();
|
|
317
|
+
Tests.testHexRotateRight();
|
|
318
|
+
Tests.testHexRotateLeft();
|
|
319
|
+
Tests.testHexRound();
|
|
320
|
+
Tests.testHexLinedraw();
|
|
321
|
+
Tests.testLayout();
|
|
322
|
+
Tests.testOffsetRoundtrip();
|
|
323
|
+
Tests.testOffsetFromCube();
|
|
324
|
+
Tests.testOffsetToCube();
|
|
325
|
+
Tests.testDoubledRoundtrip();
|
|
326
|
+
Tests.testDoubledFromCube();
|
|
327
|
+
Tests.testDoubledToCube();
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
// Tests
|
|
331
|
+
function complain(name) { console.log("FAIL", name); }
|
|
332
|
+
Tests.testAll();
|
package/index.js
CHANGED
|
@@ -2,28 +2,135 @@ import * as h3 from 'h3-js';
|
|
|
2
2
|
import OpenAI from 'openai';
|
|
3
3
|
import Gun from 'gun'
|
|
4
4
|
import Ajv2019 from 'ajv/dist/2019.js'
|
|
5
|
-
import { createHash } from "crypto";
|
|
6
5
|
|
|
7
6
|
class HoloSphere {
|
|
8
7
|
constructor(appname, openaikey = null) {
|
|
9
|
-
this.appname = appname;
|
|
10
8
|
this.validator = new Ajv2019({ allErrors: false, strict: false });
|
|
11
9
|
this.gun = Gun({
|
|
12
|
-
peers: ['https://59.src.eco/gun'],
|
|
13
|
-
axe: false
|
|
10
|
+
peers: ['http://gun.holons.io', 'https://59.src.eco/gun'],
|
|
11
|
+
axe: false,
|
|
12
|
+
// uuid: (content) => { // generate a unique id for each node
|
|
13
|
+
// console.log('uuid', content);
|
|
14
|
+
// return content;}
|
|
14
15
|
});
|
|
15
16
|
|
|
17
|
+
this.gun = this.gun.get(appname)
|
|
18
|
+
|
|
16
19
|
if (openaikey != null) {
|
|
17
20
|
this.openai = new OpenAI({
|
|
18
21
|
apiKey: openaikey,
|
|
19
22
|
});
|
|
20
23
|
}
|
|
21
24
|
|
|
25
|
+
//this.bot.command('sethex', async (ctx) => { this.setHex(ctx) }) TODO: MOVE HERE FROM SETTINGS
|
|
26
|
+
|
|
27
|
+
// this.bot.command('resethex', async (ctx) => {
|
|
28
|
+
// let chatID = ctx.message.chat.id;
|
|
29
|
+
// let hex = (await this.db.get('settings', chatID)).hex
|
|
30
|
+
// this.delete(hex, ctx.message.text.split(' ')[1])
|
|
31
|
+
// })
|
|
32
|
+
|
|
33
|
+
// this.bot.command('get', async (ctx) => {
|
|
34
|
+
// const chatID = ctx.message.chat.id;
|
|
35
|
+
// const lense = ctx.message.text.split(' ')[1];
|
|
36
|
+
// if (!lense) {
|
|
37
|
+
// return ctx.reply('Please specify a tag.');
|
|
38
|
+
// }
|
|
39
|
+
// let hex = (await this.db.get('settings', chatID)).hex
|
|
40
|
+
// //let hex = settings.hex
|
|
41
|
+
// console.log('hex', hex)
|
|
42
|
+
|
|
43
|
+
// let data = await this.get(ctx, hex, lense)
|
|
44
|
+
|
|
45
|
+
// })
|
|
46
|
+
|
|
47
|
+
// this.bot.command('gethex', async (ctx) => {
|
|
48
|
+
// let settings = await this.db.get('settings', chatID)
|
|
49
|
+
// let id = settings.hex ? settings.hex : 'Hex not set, use /sethex'
|
|
50
|
+
// ctx.reply(id)
|
|
51
|
+
// })
|
|
52
|
+
|
|
53
|
+
// this.bot.command('compute', async (ctx) => {
|
|
54
|
+
// const chatID = ctx.message.chat.id;
|
|
55
|
+
// let operation = ctx.message.text.split(' ')[1];
|
|
56
|
+
// if (operation != 'sum') {
|
|
57
|
+
// ctx.reply('Operation not implemented')
|
|
58
|
+
// return
|
|
59
|
+
// }
|
|
60
|
+
// let lense = ctx.message.text.split(' ')[2]
|
|
61
|
+
// if (!lense) {
|
|
62
|
+
// ctx.reply('Please specify a lense where to perform the operation ')
|
|
63
|
+
// return
|
|
64
|
+
// }
|
|
65
|
+
// let hex = (await this.db.get('settings', chatID)).hex
|
|
66
|
+
// await this.compute(hex, lense, operation)
|
|
67
|
+
|
|
68
|
+
// // let parentInfo = await this.getCellInfo(parent)
|
|
69
|
+
// // parentInfo.wisdom[id] = report
|
|
70
|
+
// // //update summary
|
|
71
|
+
// // let summary = await this.summarize(Object.values(parentInfo.wisdom).join('\n'))
|
|
72
|
+
// // parentInfo.summary = summary
|
|
73
|
+
|
|
74
|
+
// // await this.db.put('cell', parentInfo)
|
|
75
|
+
// // return parentInfo
|
|
76
|
+
|
|
77
|
+
// // let content = await this.db.getAll(hex+'/tags')
|
|
78
|
+
// })
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
// this.bot.command('cast', async (ctx) => {
|
|
84
|
+
// if (!ctx.message.reply_to_message) {
|
|
85
|
+
// return ctx.reply('Please reply to a message you want to tag.');
|
|
86
|
+
// }
|
|
87
|
+
// const tags = ctx.message.text.split(' ').slice(1);
|
|
88
|
+
// if (tags.length === 0) {
|
|
89
|
+
// return ctx.reply('Please provide at least one tag.');
|
|
90
|
+
// }
|
|
91
|
+
|
|
92
|
+
// const messageID = ctx.message.reply_to_message.message_id;
|
|
93
|
+
// const chatID = ctx.message.chat.id;
|
|
94
|
+
// const messageContent = ctx.message.reply_to_message.text;
|
|
95
|
+
// let settings = await this.db.get('settings', chatID)
|
|
96
|
+
// let id = settings.hex ? settings.hex : 'Hex not set, use /sethex'
|
|
97
|
+
// //create root node for the item
|
|
98
|
+
// let node = await this.gun.get(chatID + '/' + messageID).put({ id: chatID + '/' + messageID, content: messageContent })
|
|
99
|
+
// for (let tag of tags) {
|
|
100
|
+
// await this.gun.get(id).get(tag).set(node)
|
|
101
|
+
// this.upcast(id, tag, node)
|
|
102
|
+
// }
|
|
103
|
+
// })
|
|
104
|
+
|
|
105
|
+
// this.bot.command('publish', async (ctx) => {
|
|
106
|
+
// console.log(ctx.message)
|
|
107
|
+
// if (!ctx.message.reply_to_message) {
|
|
108
|
+
// return ctx.reply('Please reply to a message you want to tag.');
|
|
109
|
+
// }
|
|
110
|
+
// const tags = ctx.message.text.split(' ').slice(1);
|
|
111
|
+
// if (tags.length === 0) {
|
|
112
|
+
// return ctx.reply('Please provide at least one tag.');
|
|
113
|
+
// }
|
|
114
|
+
|
|
115
|
+
// const messageID = ctx.message.reply_to_message.message_id;
|
|
116
|
+
// const chatID = ctx.message.chat.id;
|
|
117
|
+
// const messageContent = ctx.message.reply_to_message.text;
|
|
118
|
+
// let settings = await this.db.get('settings', chatID)
|
|
119
|
+
// let hex = settings.hex
|
|
120
|
+
|
|
121
|
+
// for (let tag of tags) {
|
|
122
|
+
// let node = await this.gun.get(chatID + '/' + messageID).put({ id: chatID + '/' + messageID, content: messageContent })
|
|
123
|
+
// await this.put(hex, tag, node)
|
|
124
|
+
// }
|
|
125
|
+
|
|
126
|
+
// ctx.reply('Tag published.');
|
|
127
|
+
// });
|
|
128
|
+
|
|
22
129
|
}
|
|
23
130
|
|
|
24
131
|
async setSchema(lense, schema) {
|
|
25
132
|
return new Promise((resolve, reject) => {
|
|
26
|
-
this.gun.get(
|
|
133
|
+
this.gun.get(lense).get('schema').put(JSON.stringify(schema), ack => {
|
|
27
134
|
if (ack.err) {
|
|
28
135
|
resolve(new Error('Failed to add schema: ' + ack.err));
|
|
29
136
|
} else {
|
|
@@ -36,7 +143,7 @@ class HoloSphere {
|
|
|
36
143
|
|
|
37
144
|
async getSchema(lense) {
|
|
38
145
|
return new Promise((resolve) => {
|
|
39
|
-
this.gun.get(
|
|
146
|
+
this.gun.get(lense).get('schema').once(data => {
|
|
40
147
|
if (data) {
|
|
41
148
|
let parsed;
|
|
42
149
|
try {
|
|
@@ -71,12 +178,11 @@ class HoloSphere {
|
|
|
71
178
|
}
|
|
72
179
|
|
|
73
180
|
async delete(id, tag) {
|
|
74
|
-
await this.gun.get(
|
|
181
|
+
await this.gun.get(id).get(tag).put(null)
|
|
75
182
|
}
|
|
76
183
|
|
|
77
184
|
async put(hex, lense, content) {
|
|
78
185
|
// Retrieve the schema for the lense
|
|
79
|
-
console.log('HoloSphere: Putting content in lense:', lense, 'at hex:', hex, 'content:', content)
|
|
80
186
|
let schema = await this.getSchema(lense)
|
|
81
187
|
if (schema) {
|
|
82
188
|
// Validate the content against the schema
|
|
@@ -93,16 +199,20 @@ class HoloSphere {
|
|
|
93
199
|
let noderef;
|
|
94
200
|
|
|
95
201
|
if (content.id) { //use the user-defined id. Important to be able to send updates using put
|
|
96
|
-
noderef = this.gun.get(
|
|
97
|
-
this.gun.get(
|
|
202
|
+
noderef = this.gun.get(lense).get(content.id).put(payload)
|
|
203
|
+
this.gun.get(hex.toString()).get(lense).get(content.id).put(payload)
|
|
98
204
|
} else { // create a content-addressable reference like IPFS. Note: no updates possible using put
|
|
99
|
-
const hash = createHash("sha256").update(payload).digest("hex");
|
|
100
|
-
|
|
101
|
-
|
|
205
|
+
//const hash = createHash("sha256").update(payload).digest("hex");
|
|
206
|
+
const hash = await crypto.subtle.digest("SHA-256", new TextEncoder().encode(payload));
|
|
207
|
+
// const hashHex = Array.from(new Uint8Array(hash))
|
|
208
|
+
// .map(byte => byte.toString(16).padStart(2, "0"))
|
|
209
|
+
// .join("");
|
|
210
|
+
noderef = this.gun.get(lense).get(hash).put(payload)
|
|
211
|
+
this.gun.get(hex.toString()).get(lense).get(hash).put(payload)
|
|
102
212
|
}
|
|
103
213
|
|
|
104
214
|
// return new Promise((resolve, reject) => {
|
|
105
|
-
// this.gun.get(
|
|
215
|
+
// this.gun.get(hex.toString()).get(lense).set(noderef, ack => {
|
|
106
216
|
// if (ack.err) {
|
|
107
217
|
// reject(new Error('Failed to add content: ' + ack.err));
|
|
108
218
|
// } else {
|
|
@@ -127,16 +237,16 @@ class HoloSphere {
|
|
|
127
237
|
return new Promise(async (resolve, reject) => {
|
|
128
238
|
let output = []
|
|
129
239
|
let counter = 0
|
|
130
|
-
this.gun.get(
|
|
240
|
+
this.gun.get(hex.toString()).get(lense).once((data, key) => {
|
|
131
241
|
if (data) {
|
|
132
242
|
const maplenght = Object.keys(data).length - 1
|
|
133
243
|
console.log('Map length:', maplenght)
|
|
134
|
-
this.gun.get(
|
|
244
|
+
this.gun.get(hex.toString()).get(lense).map().once(async (itemdata, key) => {
|
|
135
245
|
counter += 1
|
|
136
246
|
if (itemdata) {
|
|
137
247
|
// if (itemdata._["#"]) {
|
|
138
248
|
// // If the data is a reference, fetch the actual content
|
|
139
|
-
// itemdata = await this.gun.get(
|
|
249
|
+
// itemdata = await this.gun.get(itemdata._['#']).then();
|
|
140
250
|
// console.log("Data :",itemdata)
|
|
141
251
|
// }
|
|
142
252
|
var parsed = {}
|
|
@@ -151,7 +261,7 @@ class HoloSphere {
|
|
|
151
261
|
let valid = this.validator.validate(schema, parsed);
|
|
152
262
|
if (!valid || parsed == null || parsed == undefined) {
|
|
153
263
|
console.log('Removing Invalid content:', this.validator.errors);
|
|
154
|
-
this.gun.get(
|
|
264
|
+
this.gun.get(hex).get(lense).get(key).put(null);
|
|
155
265
|
|
|
156
266
|
} else {
|
|
157
267
|
output.push(parsed);
|
|
@@ -208,7 +318,7 @@ class HoloSphere {
|
|
|
208
318
|
console.log('Content:', content);
|
|
209
319
|
let computed = await this.summarize(content.join('\n'))
|
|
210
320
|
console.log('Computed:', computed)
|
|
211
|
-
let node = await this.gun.get(
|
|
321
|
+
let node = await this.gun.get(parent + '_summary').put({ id: parent + '_summary', content: computed })
|
|
212
322
|
|
|
213
323
|
this.put(parent, lense, node);
|
|
214
324
|
this.compute(parent, lense, operation)
|
|
@@ -218,10 +328,10 @@ class HoloSphere {
|
|
|
218
328
|
let entities = {};
|
|
219
329
|
|
|
220
330
|
// Get list out of Gun
|
|
221
|
-
this.gun.get(
|
|
331
|
+
this.gun.get(hex).get(lense).map().once((data, key) => {
|
|
222
332
|
//entities = data;
|
|
223
333
|
//const id = Object.keys(entities)[0] // since this would be in object form, you can manipulate it as you would like.
|
|
224
|
-
this.gun.get(
|
|
334
|
+
this.gun.get(hex).get(lense).put({ [key]: null })
|
|
225
335
|
})
|
|
226
336
|
}
|
|
227
337
|
|
|
@@ -260,15 +370,15 @@ class HoloSphere {
|
|
|
260
370
|
|
|
261
371
|
async upcast(hex, lense, content) {
|
|
262
372
|
let res = h3.getResolution(hex)
|
|
263
|
-
|
|
264
|
-
if (res == 0)
|
|
265
|
-
return content
|
|
373
|
+
|
|
266
374
|
|
|
267
375
|
console.log('Upcasting ', hex, lense, content)
|
|
268
376
|
let parent = h3.cellToParent(hex, res - 1)
|
|
269
377
|
await this.put(parent, lense, content)
|
|
270
|
-
|
|
271
|
-
|
|
378
|
+
if (res == 0)
|
|
379
|
+
return content
|
|
380
|
+
else
|
|
381
|
+
return this.upcast(parent, lense, content)
|
|
272
382
|
}
|
|
273
383
|
|
|
274
384
|
|
|
@@ -312,6 +422,62 @@ class HoloSphere {
|
|
|
312
422
|
}
|
|
313
423
|
return list
|
|
314
424
|
}
|
|
425
|
+
|
|
426
|
+
subscribe(hex, lense, callback) {
|
|
427
|
+
this.gun.get(hex).get(lense).map().on((data, key) => {
|
|
428
|
+
callback(data, key)
|
|
429
|
+
})
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
// VOTING SYSTEM
|
|
433
|
+
|
|
434
|
+
getFinalVote(userId, topic, votes, visited = new Set()) {
|
|
435
|
+
if (visited.has(userId)) {
|
|
436
|
+
return null; // Avoid circular delegations
|
|
437
|
+
}
|
|
438
|
+
visited.add(userId);
|
|
439
|
+
|
|
440
|
+
const delegation = users[userId].delegations[topic];
|
|
441
|
+
if (delegation && votes[delegation] === undefined) {
|
|
442
|
+
return getFinalVote(delegation, topic, votes, visited); // Follow delegation
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
return votes[userId] !== undefined ? votes[userId] : null; // Return direct vote or null
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
aggregateVotes(hexId, topic) {
|
|
449
|
+
const votes = hexagonVotes[hexId][topic];
|
|
450
|
+
const aggregatedVotes = {};
|
|
451
|
+
|
|
452
|
+
Object.keys(votes).forEach(userId => {
|
|
453
|
+
const finalVote = getFinalVote(userId, topic, votes);
|
|
454
|
+
if (finalVote !== null) {
|
|
455
|
+
aggregatedVotes[finalVote] = (aggregatedVotes[finalVote] || 0) + 1;
|
|
456
|
+
}
|
|
457
|
+
});
|
|
458
|
+
|
|
459
|
+
return aggregatedVotes;
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
async delegateVote(userId, topic, delegateTo) {
|
|
463
|
+
const response = await fetch('/delegate', {
|
|
464
|
+
method: 'POST',
|
|
465
|
+
headers: { 'Content-Type': 'application/json' },
|
|
466
|
+
body: JSON.stringify({ userId, topic, delegateTo })
|
|
467
|
+
});
|
|
468
|
+
alert(await response.text());
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
async vote(userId, hexId, topic, vote) {
|
|
472
|
+
const response = await fetch('/vote', {
|
|
473
|
+
method: 'POST',
|
|
474
|
+
headers: { 'Content-Type': 'application/json' },
|
|
475
|
+
body: JSON.stringify({ userId, hexId, topic, vote })
|
|
476
|
+
});
|
|
477
|
+
alert(await response.text());
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
|
|
315
481
|
}
|
|
316
482
|
|
|
317
483
|
export default HoloSphere;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "holosphere",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.4",
|
|
4
4
|
"description": "Holonic Geospatial Communication Infrastructure based on h3.js and gun.js",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
"license": "GPL-3.0-or-later",
|
|
12
12
|
"dependencies": {
|
|
13
13
|
"ajv": "^8.12.0",
|
|
14
|
-
"gun": "^0.2020.
|
|
14
|
+
"gun": "^0.2020.1240",
|
|
15
15
|
"h3-js": "^4.1.0",
|
|
16
16
|
"openai": "^4.29.2"
|
|
17
17
|
}
|