@shipload/sdk 1.0.0-next.2 → 1.0.0-next.21
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/lib/shipload.d.ts +1731 -1044
- package/lib/shipload.js +6758 -4523
- package/lib/shipload.js.map +1 -1
- package/lib/shipload.m.js +6649 -4479
- package/lib/shipload.m.js.map +1 -1
- package/lib/testing.d.ts +833 -0
- package/lib/testing.js +3647 -0
- package/lib/testing.js.map +1 -0
- package/lib/testing.m.js +3641 -0
- package/lib/testing.m.js.map +1 -0
- package/package.json +15 -2
- package/src/capabilities/gathering.ts +17 -7
- package/src/capabilities/modules.ts +9 -0
- package/src/capabilities/storage.ts +1 -1
- package/src/contracts/platform.ts +211 -3
- package/src/contracts/server.ts +723 -438
- package/src/data/capabilities.ts +9 -329
- package/src/data/capability-formulas.ts +76 -0
- package/src/data/catalog.ts +0 -5
- package/src/data/colors.ts +14 -28
- package/src/data/entities.json +46 -10
- package/src/data/item-ids.ts +17 -13
- package/src/data/items.json +308 -37
- package/src/data/kind-registry.json +85 -0
- package/src/data/kind-registry.ts +150 -0
- package/src/data/metadata.ts +99 -24
- package/src/data/recipes-runtime.ts +3 -23
- package/src/data/recipes.json +265 -96
- package/src/derivation/build-methods.ts +45 -0
- package/src/derivation/capabilities.ts +414 -0
- package/src/derivation/capability-mappings.ts +117 -0
- package/src/derivation/crafting.ts +23 -24
- package/src/derivation/index.ts +8 -2
- package/src/derivation/reserve-regen.ts +34 -0
- package/src/derivation/resources.ts +125 -38
- package/src/derivation/stats.ts +1 -2
- package/src/derivation/stratum.ts +15 -19
- package/src/derivation/tiers.ts +28 -7
- package/src/entities/entity.ts +98 -0
- package/src/entities/gamestate.ts +3 -28
- package/src/entities/makers.ts +75 -129
- package/src/entities/slot-multiplier.ts +37 -0
- package/src/errors.ts +10 -15
- package/src/format.ts +26 -4
- package/src/index-module.ts +151 -40
- package/src/managers/actions.ts +184 -82
- package/src/managers/base.ts +2 -2
- package/src/managers/construction-types.ts +68 -0
- package/src/managers/construction.ts +292 -0
- package/src/managers/context.ts +9 -0
- package/src/managers/entities.ts +18 -66
- package/src/managers/epochs.ts +40 -0
- package/src/managers/index.ts +16 -1
- package/src/managers/locations.ts +2 -20
- package/src/managers/nft.ts +28 -0
- package/src/managers/plot.ts +123 -0
- package/src/nft/atomicassets.ts +231 -0
- package/src/nft/atomicdata.ts +130 -0
- package/src/nft/buildImmutableData.ts +319 -0
- package/src/nft/description.ts +45 -13
- package/src/nft/index.ts +3 -0
- package/src/resolution/describe-module.ts +5 -8
- package/src/resolution/display-name.ts +38 -10
- package/src/resolution/resolve-item.ts +20 -12
- package/src/scheduling/accessor.ts +4 -0
- package/src/scheduling/projection.ts +79 -27
- package/src/scheduling/schedule.ts +15 -1
- package/src/scheduling/task-cargo.ts +46 -0
- package/src/shipload.ts +5 -0
- package/src/subscriptions/manager.ts +40 -6
- package/src/subscriptions/mappers.ts +3 -8
- package/src/subscriptions/types.ts +3 -2
- package/src/testing/catalog-hash.ts +19 -0
- package/src/testing/index.ts +2 -0
- package/src/testing/projection-parity.ts +143 -0
- package/src/travel/travel.ts +61 -2
- package/src/types/index.ts +0 -1
- package/src/types.ts +17 -12
- package/src/utils/cargo.ts +27 -0
- package/src/utils/system.ts +25 -24
- package/src/entities/container.ts +0 -108
- package/src/entities/ship-deploy.ts +0 -258
- package/src/entities/ship.ts +0 -204
- package/src/entities/warehouse.ts +0 -119
- package/src/types/entity-traits.ts +0 -69
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import {Name} from '@wharfkit/antelope'
|
|
2
|
+
import {getItem} from '../data/catalog'
|
|
3
|
+
import {getRecipe} from '../data/recipes-runtime'
|
|
4
|
+
import {computeInputMass} from '../derivation/crafting'
|
|
5
|
+
import {calc_craft_duration} from '../capabilities/crafting'
|
|
6
|
+
import {TaskType} from '../types'
|
|
7
|
+
import {BaseManager} from './base'
|
|
8
|
+
import type {ServerContract} from '../contracts'
|
|
9
|
+
import type {BuildableTarget} from './construction-types'
|
|
10
|
+
|
|
11
|
+
export interface PlotProgressInputRow {
|
|
12
|
+
itemId: number
|
|
13
|
+
required: number
|
|
14
|
+
provided: number
|
|
15
|
+
missing: number
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export interface PlotProgress {
|
|
19
|
+
targetItemId: number
|
|
20
|
+
rows: PlotProgressInputRow[]
|
|
21
|
+
massProvided: number
|
|
22
|
+
massRequired: number
|
|
23
|
+
isComplete: boolean
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export class PlotManager extends BaseManager {
|
|
27
|
+
progress(
|
|
28
|
+
plot: ServerContract.Types.entity_row,
|
|
29
|
+
cargo: ServerContract.Types.cargo_row[]
|
|
30
|
+
): PlotProgress {
|
|
31
|
+
const targetItemId = Number(plot.item_id.toString())
|
|
32
|
+
const recipe = getRecipe(targetItemId)
|
|
33
|
+
if (!recipe) {
|
|
34
|
+
throw new Error(`No recipe found for item ${targetItemId}`)
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const plotId = plot.id.toString()
|
|
38
|
+
const plotCargo = cargo.filter((c) => c.entity_id.toString() === plotId)
|
|
39
|
+
|
|
40
|
+
const quantityByItemId = new Map<number, number>()
|
|
41
|
+
for (const c of plotCargo) {
|
|
42
|
+
const id = c.item_id.toNumber()
|
|
43
|
+
quantityByItemId.set(
|
|
44
|
+
id,
|
|
45
|
+
(quantityByItemId.get(id) ?? 0) + Number(c.quantity.toString())
|
|
46
|
+
)
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const rows: PlotProgressInputRow[] = recipe.inputs.map((input) => {
|
|
50
|
+
const itemId = input.itemId
|
|
51
|
+
const required = input.quantity
|
|
52
|
+
const provided = quantityByItemId.get(itemId) ?? 0
|
|
53
|
+
const missing = Math.max(0, required - provided)
|
|
54
|
+
return {itemId, required, provided, missing}
|
|
55
|
+
})
|
|
56
|
+
|
|
57
|
+
const massRequired = computeInputMass(targetItemId)
|
|
58
|
+
const massProvided = rows.reduce((sum, r) => {
|
|
59
|
+
const item = getItem(r.itemId)
|
|
60
|
+
return sum + item.mass * r.provided
|
|
61
|
+
}, 0)
|
|
62
|
+
const isComplete = rows.every((r) => r.missing === 0)
|
|
63
|
+
|
|
64
|
+
return {targetItemId, rows, massProvided, massRequired, isComplete}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
buildableTarget(
|
|
68
|
+
plot: ServerContract.Types.entity_row,
|
|
69
|
+
cargo: ServerContract.Types.cargo_row[],
|
|
70
|
+
activeTask?: ServerContract.Types.task
|
|
71
|
+
): BuildableTarget {
|
|
72
|
+
const progress = this.progress(plot, cargo)
|
|
73
|
+
const targetItemId = Number(plot.item_id.toString())
|
|
74
|
+
const targetItem = getItem(targetItemId)
|
|
75
|
+
const recipe = getRecipe(targetItemId)
|
|
76
|
+
if (!recipe) {
|
|
77
|
+
throw new Error(`Plot target item ${targetItemId} has no recipe`)
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
let state: BuildableTarget['state']
|
|
81
|
+
const taskType = activeTask?.type.toNumber()
|
|
82
|
+
if (taskType === TaskType.CLAIMPLOT) {
|
|
83
|
+
state = 'initializing'
|
|
84
|
+
} else if (taskType === TaskType.BUILDPLOT) {
|
|
85
|
+
state = 'finalizing'
|
|
86
|
+
} else if (progress.isComplete) {
|
|
87
|
+
state = 'ready'
|
|
88
|
+
} else {
|
|
89
|
+
state = 'accepting'
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
return {
|
|
93
|
+
entityId: plot.id,
|
|
94
|
+
ownerName: plot.owner,
|
|
95
|
+
coordinates: plot.coordinates,
|
|
96
|
+
targetItemId,
|
|
97
|
+
targetItem,
|
|
98
|
+
state,
|
|
99
|
+
recipe,
|
|
100
|
+
progress,
|
|
101
|
+
finalizeAction: Name.from('buildplot'),
|
|
102
|
+
finalizerCapability: 'crafter',
|
|
103
|
+
activeTask,
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
canBuild(
|
|
108
|
+
plot: ServerContract.Types.entity_row,
|
|
109
|
+
cargo: ServerContract.Types.cargo_row[]
|
|
110
|
+
): boolean {
|
|
111
|
+
return this.progress(plot, cargo).isComplete
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
timeToComplete(
|
|
115
|
+
plot: ServerContract.Types.entity_info,
|
|
116
|
+
crafter: ServerContract.Types.crafter_stats
|
|
117
|
+
): number {
|
|
118
|
+
const capacity = Number(plot.capacity?.toString() ?? '0')
|
|
119
|
+
const speed = Number(crafter.speed.toString())
|
|
120
|
+
if (speed === 0) return 0
|
|
121
|
+
return calc_craft_duration(speed, capacity).toNumber()
|
|
122
|
+
}
|
|
123
|
+
}
|
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ABI,
|
|
3
|
+
type ABIDef,
|
|
4
|
+
Action,
|
|
5
|
+
type APIClient,
|
|
6
|
+
type NameType,
|
|
7
|
+
Name,
|
|
8
|
+
PermissionLevel,
|
|
9
|
+
UInt64,
|
|
10
|
+
} from '@wharfkit/antelope'
|
|
11
|
+
import {deserializeAtomicData, type SchemaField} from './atomicdata'
|
|
12
|
+
import {deserializeAsset, type NFTCargoItem, type NFTModuleSlot} from './deserializers'
|
|
13
|
+
import type {ImmutableEntry} from './buildImmutableData'
|
|
14
|
+
|
|
15
|
+
const PLACEHOLDER_AUTH = PermissionLevel.from({
|
|
16
|
+
actor: '............1',
|
|
17
|
+
permission: '............2',
|
|
18
|
+
})
|
|
19
|
+
|
|
20
|
+
export const ATOMICASSETS_ACCOUNT = 'atomicassets'
|
|
21
|
+
export const SHIPLOAD_COLLECTION = 'shipload'
|
|
22
|
+
|
|
23
|
+
const ATOMIC_ATTRIBUTE_VARIANT_NAME =
|
|
24
|
+
'variant_int8_int16_int32_int64_uint8_uint16_uint32_uint64_float32_float64_string_INT8_VEC_INT16_VEC_INT32_VEC_INT64_VEC_UINT8_VEC_UINT16_VEC_UINT32_VEC_UINT64_VEC_FLOAT_VEC_DOUBLE_VEC_STRING_VEC'
|
|
25
|
+
|
|
26
|
+
const MINTASSET_ABI_DEF: ABIDef = {
|
|
27
|
+
version: 'eosio::abi/1.2',
|
|
28
|
+
types: [
|
|
29
|
+
{new_type_name: 'ATOMIC_ATTRIBUTE', type: ATOMIC_ATTRIBUTE_VARIANT_NAME},
|
|
30
|
+
{new_type_name: 'ATTRIBUTE_MAP', type: 'pair_string_ATOMIC_ATTRIBUTE[]'},
|
|
31
|
+
{new_type_name: 'INT8_VEC', type: 'bytes'},
|
|
32
|
+
{new_type_name: 'INT16_VEC', type: 'int16[]'},
|
|
33
|
+
{new_type_name: 'INT32_VEC', type: 'int32[]'},
|
|
34
|
+
{new_type_name: 'INT64_VEC', type: 'int64[]'},
|
|
35
|
+
{new_type_name: 'UINT8_VEC', type: 'bytes'},
|
|
36
|
+
{new_type_name: 'UINT16_VEC', type: 'uint16[]'},
|
|
37
|
+
{new_type_name: 'UINT32_VEC', type: 'uint32[]'},
|
|
38
|
+
{new_type_name: 'UINT64_VEC', type: 'uint64[]'},
|
|
39
|
+
{new_type_name: 'FLOAT_VEC', type: 'float32[]'},
|
|
40
|
+
{new_type_name: 'DOUBLE_VEC', type: 'float64[]'},
|
|
41
|
+
{new_type_name: 'STRING_VEC', type: 'string[]'},
|
|
42
|
+
],
|
|
43
|
+
structs: [
|
|
44
|
+
{
|
|
45
|
+
name: 'pair_string_ATOMIC_ATTRIBUTE',
|
|
46
|
+
base: '',
|
|
47
|
+
fields: [
|
|
48
|
+
{name: 'first', type: 'string'},
|
|
49
|
+
{name: 'second', type: 'ATOMIC_ATTRIBUTE'},
|
|
50
|
+
],
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
name: 'mintasset',
|
|
54
|
+
base: '',
|
|
55
|
+
fields: [
|
|
56
|
+
{name: 'authorized_minter', type: 'name'},
|
|
57
|
+
{name: 'collection_name', type: 'name'},
|
|
58
|
+
{name: 'schema_name', type: 'name'},
|
|
59
|
+
{name: 'template_id', type: 'int32'},
|
|
60
|
+
{name: 'new_asset_owner', type: 'name'},
|
|
61
|
+
{name: 'immutable_data', type: 'ATTRIBUTE_MAP'},
|
|
62
|
+
{name: 'mutable_data', type: 'ATTRIBUTE_MAP'},
|
|
63
|
+
{name: 'tokens_to_back', type: 'asset[]'},
|
|
64
|
+
],
|
|
65
|
+
},
|
|
66
|
+
],
|
|
67
|
+
actions: [{name: 'mintasset', type: 'mintasset', ricardian_contract: ''}],
|
|
68
|
+
variants: [
|
|
69
|
+
{
|
|
70
|
+
name: ATOMIC_ATTRIBUTE_VARIANT_NAME,
|
|
71
|
+
types: [
|
|
72
|
+
'int8',
|
|
73
|
+
'int16',
|
|
74
|
+
'int32',
|
|
75
|
+
'int64',
|
|
76
|
+
'uint8',
|
|
77
|
+
'uint16',
|
|
78
|
+
'uint32',
|
|
79
|
+
'uint64',
|
|
80
|
+
'float32',
|
|
81
|
+
'float64',
|
|
82
|
+
'string',
|
|
83
|
+
'INT8_VEC',
|
|
84
|
+
'INT16_VEC',
|
|
85
|
+
'INT32_VEC',
|
|
86
|
+
'INT64_VEC',
|
|
87
|
+
'UINT8_VEC',
|
|
88
|
+
'UINT16_VEC',
|
|
89
|
+
'UINT32_VEC',
|
|
90
|
+
'UINT64_VEC',
|
|
91
|
+
'FLOAT_VEC',
|
|
92
|
+
'DOUBLE_VEC',
|
|
93
|
+
'STRING_VEC',
|
|
94
|
+
],
|
|
95
|
+
},
|
|
96
|
+
],
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export interface MintAssetParams {
|
|
100
|
+
authorizedMinter: NameType
|
|
101
|
+
collectionName: NameType
|
|
102
|
+
schemaName: NameType
|
|
103
|
+
templateId: number
|
|
104
|
+
newAssetOwner: NameType
|
|
105
|
+
immutableData: ImmutableEntry[]
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const MINTASSET_ABI = ABI.from(MINTASSET_ABI_DEF)
|
|
109
|
+
|
|
110
|
+
export function buildMintAssetAction(params: MintAssetParams): Action {
|
|
111
|
+
return Action.from(
|
|
112
|
+
{
|
|
113
|
+
account: Name.from(ATOMICASSETS_ACCOUNT),
|
|
114
|
+
name: Name.from('mintasset'),
|
|
115
|
+
authorization: [PLACEHOLDER_AUTH],
|
|
116
|
+
data: {
|
|
117
|
+
authorized_minter: Name.from(params.authorizedMinter),
|
|
118
|
+
collection_name: Name.from(params.collectionName),
|
|
119
|
+
schema_name: Name.from(params.schemaName),
|
|
120
|
+
template_id: params.templateId,
|
|
121
|
+
new_asset_owner: Name.from(params.newAssetOwner),
|
|
122
|
+
immutable_data: params.immutableData,
|
|
123
|
+
mutable_data: [],
|
|
124
|
+
tokens_to_back: [],
|
|
125
|
+
},
|
|
126
|
+
},
|
|
127
|
+
MINTASSET_ABI
|
|
128
|
+
)
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
export interface AtomicAssetRow {
|
|
132
|
+
asset_id: string
|
|
133
|
+
collection_name: string
|
|
134
|
+
schema_name: string
|
|
135
|
+
template_id: number
|
|
136
|
+
ram_payer?: string
|
|
137
|
+
backed_tokens?: string[]
|
|
138
|
+
immutable_serialized_data: string | number[]
|
|
139
|
+
mutable_serialized_data?: string | number[]
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
export interface AtomicSchemaRow {
|
|
143
|
+
schema_name: string
|
|
144
|
+
format: SchemaField[]
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
export interface FetchAssetsOptions {
|
|
148
|
+
collection?: NameType
|
|
149
|
+
pageSize?: number
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
export async function fetchAtomicAssetsForOwner(
|
|
153
|
+
client: APIClient,
|
|
154
|
+
owner: NameType,
|
|
155
|
+
opts: FetchAssetsOptions = {}
|
|
156
|
+
): Promise<AtomicAssetRow[]> {
|
|
157
|
+
const collection = opts.collection ? String(Name.from(opts.collection)) : undefined
|
|
158
|
+
const pageSize = opts.pageSize ?? 1000
|
|
159
|
+
const out: AtomicAssetRow[] = []
|
|
160
|
+
let lower: UInt64 | undefined
|
|
161
|
+
while (true) {
|
|
162
|
+
const res = await client.v1.chain.get_table_rows({
|
|
163
|
+
code: Name.from(ATOMICASSETS_ACCOUNT),
|
|
164
|
+
scope: String(Name.from(owner)),
|
|
165
|
+
table: Name.from('assets'),
|
|
166
|
+
limit: pageSize,
|
|
167
|
+
lower_bound: lower,
|
|
168
|
+
json: true,
|
|
169
|
+
})
|
|
170
|
+
for (const row of res.rows as AtomicAssetRow[]) {
|
|
171
|
+
if (!collection || row.collection_name === collection) out.push(row)
|
|
172
|
+
}
|
|
173
|
+
if (!res.more) break
|
|
174
|
+
lower = UInt64.from(String(res.next_key))
|
|
175
|
+
}
|
|
176
|
+
return out
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
export async function fetchAtomicSchemas(
|
|
180
|
+
client: APIClient,
|
|
181
|
+
collection: NameType
|
|
182
|
+
): Promise<AtomicSchemaRow[]> {
|
|
183
|
+
const out: AtomicSchemaRow[] = []
|
|
184
|
+
let lower: Name | undefined
|
|
185
|
+
while (true) {
|
|
186
|
+
const res = await client.v1.chain.get_table_rows({
|
|
187
|
+
code: Name.from(ATOMICASSETS_ACCOUNT),
|
|
188
|
+
scope: String(Name.from(collection)),
|
|
189
|
+
table: Name.from('schemas'),
|
|
190
|
+
limit: 100,
|
|
191
|
+
lower_bound: lower,
|
|
192
|
+
json: true,
|
|
193
|
+
})
|
|
194
|
+
for (const row of res.rows as AtomicSchemaRow[]) out.push(row)
|
|
195
|
+
if (!res.more) break
|
|
196
|
+
lower = Name.from(String(res.next_key))
|
|
197
|
+
}
|
|
198
|
+
return out
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
export interface DecodedAtomicAsset {
|
|
202
|
+
asset_id: bigint
|
|
203
|
+
schema_name: string
|
|
204
|
+
template_id: number
|
|
205
|
+
item_id: number
|
|
206
|
+
quantity: number
|
|
207
|
+
stats: string
|
|
208
|
+
origin_x: bigint
|
|
209
|
+
origin_y: bigint
|
|
210
|
+
modules?: NFTModuleSlot[]
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
export function decodeAtomicAsset(
|
|
214
|
+
asset: AtomicAssetRow,
|
|
215
|
+
schemaFormat: SchemaField[],
|
|
216
|
+
itemId: number
|
|
217
|
+
): DecodedAtomicAsset {
|
|
218
|
+
const data = deserializeAtomicData(asset.immutable_serialized_data, schemaFormat)
|
|
219
|
+
const cargo: NFTCargoItem = deserializeAsset(data, itemId)
|
|
220
|
+
return {
|
|
221
|
+
asset_id: BigInt(String(asset.asset_id)),
|
|
222
|
+
schema_name: String(asset.schema_name),
|
|
223
|
+
template_id: Number(asset.template_id),
|
|
224
|
+
item_id: cargo.item_id,
|
|
225
|
+
quantity: cargo.quantity,
|
|
226
|
+
stats: cargo.stats,
|
|
227
|
+
origin_x: BigInt(String(data.origin_x ?? 0)),
|
|
228
|
+
origin_y: BigInt(String(data.origin_y ?? 0)),
|
|
229
|
+
modules: cargo.modules,
|
|
230
|
+
}
|
|
231
|
+
}
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
export interface SchemaField {
|
|
2
|
+
name: string
|
|
3
|
+
type: string
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
export type RawData =
|
|
7
|
+
| Uint8Array
|
|
8
|
+
| string
|
|
9
|
+
| number[]
|
|
10
|
+
| {immutable_serialized_data: Uint8Array | string | number[]}
|
|
11
|
+
|
|
12
|
+
export function deserializeAtomicData(
|
|
13
|
+
data: RawData,
|
|
14
|
+
schema: SchemaField[]
|
|
15
|
+
): Record<string, unknown> {
|
|
16
|
+
let rawData: Uint8Array | string | number[]
|
|
17
|
+
if (data && typeof data === 'object' && 'immutable_serialized_data' in (data as object)) {
|
|
18
|
+
rawData = (data as {immutable_serialized_data: Uint8Array | string | number[]})
|
|
19
|
+
.immutable_serialized_data
|
|
20
|
+
} else {
|
|
21
|
+
rawData = data as Uint8Array | string | number[]
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
let bytes: Uint8Array
|
|
25
|
+
if (typeof rawData === 'string') {
|
|
26
|
+
const hex = rawData
|
|
27
|
+
bytes = new Uint8Array(hex.length / 2)
|
|
28
|
+
for (let i = 0; i < hex.length; i += 2) {
|
|
29
|
+
bytes[i / 2] = parseInt(hex.substring(i, i + 2), 16)
|
|
30
|
+
}
|
|
31
|
+
} else if (Array.isArray(rawData)) {
|
|
32
|
+
bytes = new Uint8Array(rawData)
|
|
33
|
+
} else {
|
|
34
|
+
bytes = rawData
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
let offset = 0
|
|
38
|
+
|
|
39
|
+
function readVarint(): number {
|
|
40
|
+
let result = 0
|
|
41
|
+
let multiplier = 1
|
|
42
|
+
while (bytes[offset] >= 128) {
|
|
43
|
+
result += (bytes[offset] - 128) * multiplier
|
|
44
|
+
offset++
|
|
45
|
+
multiplier *= 128
|
|
46
|
+
}
|
|
47
|
+
result += bytes[offset] * multiplier
|
|
48
|
+
offset++
|
|
49
|
+
return result
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function readVarint64(): bigint {
|
|
53
|
+
let result = 0n
|
|
54
|
+
let multiplier = 1n
|
|
55
|
+
while (bytes[offset] >= 128) {
|
|
56
|
+
result += BigInt(bytes[offset] - 128) * multiplier
|
|
57
|
+
offset++
|
|
58
|
+
multiplier *= 128n
|
|
59
|
+
}
|
|
60
|
+
result += BigInt(bytes[offset]) * multiplier
|
|
61
|
+
offset++
|
|
62
|
+
return result
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function readZigzagInt64(): bigint {
|
|
66
|
+
const unsigned = readVarint64()
|
|
67
|
+
if (unsigned % 2n === 0n) {
|
|
68
|
+
return unsigned / 2n
|
|
69
|
+
} else {
|
|
70
|
+
return -(unsigned / 2n) - 1n
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function readString(): string {
|
|
75
|
+
const length = readVarint()
|
|
76
|
+
const str = new TextDecoder().decode(bytes.slice(offset, offset + length))
|
|
77
|
+
offset += length
|
|
78
|
+
return str
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const RESERVED = 4
|
|
82
|
+
const result: Record<string, unknown> = {}
|
|
83
|
+
|
|
84
|
+
while (offset < bytes.length) {
|
|
85
|
+
const fieldIndex = readVarint() - RESERVED
|
|
86
|
+
const field = schema[fieldIndex]
|
|
87
|
+
if (!field) break
|
|
88
|
+
|
|
89
|
+
switch (field.type) {
|
|
90
|
+
case 'uint16':
|
|
91
|
+
result[field.name] = readVarint()
|
|
92
|
+
break
|
|
93
|
+
case 'uint32':
|
|
94
|
+
result[field.name] = readVarint()
|
|
95
|
+
break
|
|
96
|
+
case 'uint64':
|
|
97
|
+
result[field.name] = readVarint64()
|
|
98
|
+
break
|
|
99
|
+
case 'int32':
|
|
100
|
+
result[field.name] = readZigzagInt64()
|
|
101
|
+
break
|
|
102
|
+
case 'int64':
|
|
103
|
+
result[field.name] = readZigzagInt64()
|
|
104
|
+
break
|
|
105
|
+
case 'string':
|
|
106
|
+
case 'image':
|
|
107
|
+
case 'ipfs':
|
|
108
|
+
result[field.name] = readString()
|
|
109
|
+
break
|
|
110
|
+
case 'uint16[]': {
|
|
111
|
+
const len = readVarint()
|
|
112
|
+
const arr: number[] = []
|
|
113
|
+
for (let i = 0; i < len; i++) arr.push(readVarint())
|
|
114
|
+
result[field.name] = arr
|
|
115
|
+
break
|
|
116
|
+
}
|
|
117
|
+
case 'uint64[]': {
|
|
118
|
+
const len = readVarint()
|
|
119
|
+
const arr: bigint[] = []
|
|
120
|
+
for (let i = 0; i < len; i++) arr.push(readVarint64())
|
|
121
|
+
result[field.name] = arr
|
|
122
|
+
break
|
|
123
|
+
}
|
|
124
|
+
default:
|
|
125
|
+
throw new Error(`Unknown type: ${field.type}`)
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
return result
|
|
130
|
+
}
|