@loaders.gl/tile-converter 4.1.0-alpha.1 → 4.1.0-alpha.11

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.
Files changed (51) hide show
  1. package/dist/3d-tiles-converter/helpers/b3dm-converter.d.ts.map +1 -1
  2. package/dist/3d-tiles-converter/helpers/b3dm-converter.js +8 -0
  3. package/dist/3d-tiles-converter/helpers/b3dm-converter.js.map +1 -1
  4. package/dist/constants.d.ts +1 -0
  5. package/dist/constants.d.ts.map +1 -1
  6. package/dist/constants.js +1 -0
  7. package/dist/constants.js.map +1 -1
  8. package/dist/converter-cli.js +41 -4
  9. package/dist/converter-cli.js.map +1 -1
  10. package/dist/converter.min.cjs +131 -220
  11. package/dist/deps-installer/deps-installer.d.ts.map +1 -1
  12. package/dist/deps-installer/deps-installer.js +4 -3
  13. package/dist/deps-installer/deps-installer.js.map +1 -1
  14. package/dist/i3s-converter/i3s-converter.d.ts +14 -0
  15. package/dist/i3s-converter/i3s-converter.d.ts.map +1 -1
  16. package/dist/i3s-converter/i3s-converter.js +73 -19
  17. package/dist/i3s-converter/i3s-converter.js.map +1 -1
  18. package/dist/i3s-converter/types.d.ts +7 -0
  19. package/dist/i3s-converter/types.d.ts.map +1 -1
  20. package/dist/i3s-converter/types.js +8 -0
  21. package/dist/i3s-converter/types.js.map +1 -1
  22. package/dist/i3s-server/bin/i3s-server.min.cjs +80 -80
  23. package/dist/index.cjs +365 -93
  24. package/dist/lib/utils/compress-util.d.ts +0 -37
  25. package/dist/lib/utils/compress-util.d.ts.map +1 -1
  26. package/dist/lib/utils/compress-util.js +1 -149
  27. package/dist/lib/utils/compress-util.js.map +1 -1
  28. package/dist/lib/utils/conversion-dump.d.ts +81 -0
  29. package/dist/lib/utils/conversion-dump.d.ts.map +1 -0
  30. package/dist/lib/utils/conversion-dump.js +131 -0
  31. package/dist/lib/utils/conversion-dump.js.map +1 -0
  32. package/dist/lib/utils/statistic-utills.d.ts +23 -6
  33. package/dist/lib/utils/write-queue.d.ts +6 -1
  34. package/dist/lib/utils/write-queue.d.ts.map +1 -1
  35. package/dist/lib/utils/write-queue.js +15 -3
  36. package/dist/lib/utils/write-queue.js.map +1 -1
  37. package/dist/pgm-loader.js +1 -1
  38. package/dist/pgm-loader.js.map +1 -1
  39. package/dist/slpk-extractor.min.cjs +46 -46
  40. package/package.json +16 -16
  41. package/src/3d-tiles-converter/helpers/b3dm-converter.ts +19 -0
  42. package/src/constants.ts +1 -0
  43. package/src/converter-cli.ts +58 -4
  44. package/src/deps-installer/deps-installer.ts +3 -2
  45. package/src/i3s-converter/i3s-converter.ts +191 -51
  46. package/src/i3s-converter/types.ts +8 -0
  47. package/src/lib/utils/compress-util.ts +1 -264
  48. package/src/lib/utils/conversion-dump.ts +203 -0
  49. package/src/lib/utils/write-queue.ts +15 -2
  50. package/dist/lib/utils/statistic-utills.d.js +0 -2
  51. package/dist/lib/utils/statistic-utills.d.js.map +0 -1
@@ -1,4 +1,5 @@
1
- // loaders.gl, MIT license
1
+ // loaders.gl
2
+ // SPDX-License-Identifier: MIT
2
3
  // Copyright (c) vis.gl contributors
3
4
 
4
5
  import {AttributeMetadataInfo} from './helpers/attribute-metadata-info';
@@ -29,12 +30,7 @@ import md5 from 'md5';
29
30
 
30
31
  import NodePages from './helpers/node-pages';
31
32
  import {writeFile, removeDir, writeFileForSlpk, removeFile} from '../lib/utils/file-utils';
32
- import {
33
- compressFileWithGzip,
34
- compressWithChildProcess
35
- // generateHash128FromZip,
36
- // addFileToZip
37
- } from '../lib/utils/compress-util';
33
+ import {compressFileWithGzip} from '../lib/utils/compress-util';
38
34
  import {calculateFilesSize, timeConverter} from '../lib/utils/statistic-utills';
39
35
  import convertB3dmToI3sGeometry, {getPropertyTable} from './helpers/geometry-converter';
40
36
  import {
@@ -58,6 +54,7 @@ import {
58
54
  GLTFPrimitiveModeString,
59
55
  I3SConvertedResources,
60
56
  PreprocessData,
57
+ ResourceType,
61
58
  SharedResourcesArrays
62
59
  } from './types';
63
60
  import {WorkerFarm} from '@loaders.gl/worker-utils';
@@ -80,6 +77,8 @@ import {createBoundingVolume} from '@loaders.gl/tiles';
80
77
  import {TraversalConversionProps, traverseDatasetWith} from './helpers/tileset-traversal';
81
78
  import {analyzeTileContent, mergePreprocessData} from './helpers/preprocess-3d-tiles';
82
79
  import {Progress} from './helpers/progress';
80
+ import {composeHashFile, createZip} from '@loaders.gl/zip';
81
+ import {ConversionDump, ConversionDumpOptions} from '../lib/utils/conversion-dump';
83
82
 
84
83
  const ION_DEFAULT_TOKEN = process.env?.IonToken;
85
84
  const HARDCODED_NODES_PER_PAGE = 64;
@@ -134,13 +133,14 @@ export default class I3SConverter {
134
133
  generateBoundingVolumes: boolean;
135
134
  layersHasTexture: boolean;
136
135
  workerSource: {[key: string]: string} = {};
137
- writeQueue: WriteQueue<WriteQueueItem> = new WriteQueue();
136
+ writeQueue: WriteQueue<WriteQueueItem> = new WriteQueue(new ConversionDump());
138
137
  compressList: string[] | null = null;
139
138
  preprocessData: PreprocessData = {
140
139
  meshTopologyTypes: new Set(),
141
140
  metadataClasses: new Set()
142
141
  };
143
142
  progresses: Record<string, Progress> = {};
143
+ conversionDump: ConversionDump;
144
144
 
145
145
  constructor() {
146
146
  this.attributeMetadataInfo = new AttributeMetadataInfo();
@@ -163,6 +163,7 @@ export default class I3SConverter {
163
163
  this.generateBoundingVolumes = false;
164
164
  this.layersHasTexture = false;
165
165
  this.compressList = null;
166
+ this.conversionDump = new ConversionDump();
166
167
  }
167
168
 
168
169
  /**
@@ -226,6 +227,8 @@ export default class I3SConverter {
226
227
  analyze = false
227
228
  } = options;
228
229
  this.options = {
230
+ outputPath,
231
+ tilesetName,
229
232
  maxDepth,
230
233
  slpk,
231
234
  sevenZipExe,
@@ -245,7 +248,7 @@ export default class I3SConverter {
245
248
  this.generateTextures = Boolean(generateTextures);
246
249
  this.generateBoundingVolumes = Boolean(generateBoundingVolumes);
247
250
 
248
- this.writeQueue = new WriteQueue();
251
+ this.writeQueue = new WriteQueue(this.conversionDump);
249
252
  this.writeQueue.startListening();
250
253
 
251
254
  console.log('Loading egm file...'); // eslint-disable-line
@@ -256,6 +259,9 @@ export default class I3SConverter {
256
259
  this.nodePages.useWriteFunction(writeFileForSlpk);
257
260
  }
258
261
 
262
+ //create a dump file with convertion options
263
+ await this.conversionDump.createDumpFile(options as ConversionDumpOptions);
264
+
259
265
  try {
260
266
  const preloadOptions = await this._fetchPreloadOptions();
261
267
  let tilesetUrl = inputUrl;
@@ -552,35 +558,16 @@ export default class I3SConverter {
552
558
  * @param tilesetPath - Path to save file
553
559
  */
554
560
  private async _createSlpk(tilesetPath: string): Promise<void> {
561
+ await this.conversionDump.deleteDumpFile();
555
562
  if (this.options.slpk) {
556
563
  const slpkTilesetPath = join(tilesetPath, 'SceneServer', 'layers', '0');
557
564
  const slpkFileName = `${tilesetPath}.slpk`;
558
- await compressWithChildProcess(
559
- slpkTilesetPath,
560
- slpkFileName,
561
- 0,
562
- '.',
563
- this.options.sevenZipExe
564
- );
565
565
 
566
- // TODO: `addFileToZip` corrupts archive so it can't be validated with windows i3s_converter.exe
567
- // const fileHash128Path = `${tilesetPath}/@specialIndexFileHASH128@`;
568
- // try {
569
- // await generateHash128FromZip(slpkFileName, fileHash128Path);
570
- // await addFileToZip(
571
- // tilesetPath,
572
- // '@specialIndexFileHASH128@',
573
- // slpkFileName,
574
- // this.options.sevenZipExe
575
- // );
576
- // } catch (error) {
577
- // if (error.code === FS_FILE_TOO_LARGE) {
578
- // console.warn(`${slpkFileName} file is too big to generate a hash`); // eslint-disable-line
579
- // } else {
580
- // console.error(error); // eslint-disable-line
581
- // }
582
- // }
583
- // All converted files are contained in slpk now they can be deleted
566
+ await createZip(slpkTilesetPath, slpkFileName, async (fileList) => ({
567
+ path: '@specialIndexFileHASH128@',
568
+ file: await composeHashFile(fileList)
569
+ }));
570
+
584
571
  try {
585
572
  await removeDir(tilesetPath);
586
573
  } catch (e) {
@@ -613,6 +600,7 @@ export default class I3SConverter {
613
600
  if (sourceTile.id) {
614
601
  console.log(`[convert]: ${sourceTile.id}`); // eslint-disable-line
615
602
  }
603
+
616
604
  const {parentNodes, transform} = traversalProps;
617
605
  let transformationMatrix: Matrix4 = transform.clone();
618
606
  if (sourceTile.transform) {
@@ -751,7 +739,13 @@ export default class I3SConverter {
751
739
  nodes.push(node);
752
740
 
753
741
  if (nodeInPage.mesh) {
754
- await this._writeResources(resources, node.id);
742
+ //update a record in a dump file
743
+ if (sourceTile.id) {
744
+ await this.conversionDump.addNode(sourceTile.id, nodeInPage.index);
745
+ }
746
+
747
+ //write resources
748
+ await this._writeResources(resources, node.id, sourceTile);
755
749
  }
756
750
 
757
751
  if (this.validate) {
@@ -900,9 +894,15 @@ export default class I3SConverter {
900
894
  * @param resources.texture - texture image
901
895
  * @param resources.sharedResources - shared resource data object
902
896
  * @param resources.attributes - feature attributes
897
+ * @param nodePath - node path
898
+ * @param sourceTile - source tile (3DTile)
903
899
  * @return {Promise<void>}
904
900
  */
905
- private async _writeResources(resources: I3SConvertedResources, nodePath: string): Promise<void> {
901
+ private async _writeResources(
902
+ resources: I3SConvertedResources,
903
+ nodePath: string,
904
+ sourceTile: Tiles3DTileJSONPostprocessed
905
+ ): Promise<void> {
906
906
  const {
907
907
  geometry: geometryBuffer,
908
908
  compressedGeometry,
@@ -913,10 +913,36 @@ export default class I3SConverter {
913
913
  const childPath = join(this.layers0Path, 'nodes', nodePath);
914
914
  const slpkChildPath = join('nodes', nodePath);
915
915
 
916
- await this._writeGeometries(geometryBuffer!, compressedGeometry!, childPath, slpkChildPath);
917
- await this._writeShared(sharedResources, childPath, slpkChildPath, nodePath);
918
- await this._writeTexture(texture, childPath, slpkChildPath);
919
- await this._writeAttributes(attributes, childPath, slpkChildPath);
916
+ await this._writeGeometries(
917
+ geometryBuffer!,
918
+ compressedGeometry!,
919
+ childPath,
920
+ slpkChildPath,
921
+ sourceTile.id || '',
922
+ parseInt(nodePath)
923
+ );
924
+ await this._writeShared(
925
+ sharedResources,
926
+ childPath,
927
+ slpkChildPath,
928
+ nodePath,
929
+ sourceTile.id || '',
930
+ parseInt(nodePath)
931
+ );
932
+ await this._writeTexture(
933
+ texture,
934
+ childPath,
935
+ slpkChildPath,
936
+ sourceTile.id || '',
937
+ parseInt(nodePath)
938
+ );
939
+ await this._writeAttributes(
940
+ attributes,
941
+ childPath,
942
+ slpkChildPath,
943
+ sourceTile.id || '',
944
+ parseInt(nodePath)
945
+ );
920
946
  }
921
947
 
922
948
  /**
@@ -925,37 +951,57 @@ export default class I3SConverter {
925
951
  * @param compressedGeometry - Uint8Array with compressed (draco) geometry
926
952
  * @param childPath - a child path to write resources
927
953
  * @param slpkChildPath - resource path inside *slpk file
954
+ * @param sourceId - source filename
955
+ * @param nodeId - nodeId of a converted node for the writing
928
956
  */
929
957
  private async _writeGeometries(
930
958
  geometryBuffer: ArrayBuffer,
931
959
  compressedGeometry: Promise<ArrayBuffer>,
932
960
  childPath: string,
933
- slpkChildPath: string
961
+ slpkChildPath: string,
962
+ sourceId: string,
963
+ nodeId: number
934
964
  ): Promise<void> {
965
+ this.conversionDump.updateDoneStatus(sourceId, nodeId, ResourceType.GEOMETRY, false);
966
+
935
967
  if (this.options.slpk) {
936
968
  const slpkGeometryPath = join(childPath, 'geometries');
937
969
  await this.writeQueue.enqueue({
938
970
  archiveKey: `${slpkChildPath}/geometries/0.bin.gz`,
971
+ sourceId,
972
+ outputId: nodeId,
973
+ resourceType: ResourceType.GEOMETRY,
939
974
  writePromise: () => writeFileForSlpk(slpkGeometryPath, geometryBuffer, '0.bin')
940
975
  });
941
976
  } else {
942
977
  const geometryPath = join(childPath, 'geometries/0/');
943
978
  await this.writeQueue.enqueue({
979
+ sourceId,
980
+ outputId: nodeId,
981
+ resourceType: ResourceType.GEOMETRY,
944
982
  writePromise: () => writeFile(geometryPath, geometryBuffer, 'index.bin')
945
983
  });
946
984
  }
947
985
 
948
986
  if (this.options.draco) {
987
+ this.conversionDump.updateDoneStatus(sourceId, nodeId, ResourceType.DRACO_GEOMETRY, false);
988
+
949
989
  if (this.options.slpk) {
950
990
  const slpkCompressedGeometryPath = join(childPath, 'geometries');
951
991
  await this.writeQueue.enqueue({
952
992
  archiveKey: `${slpkChildPath}/geometries/1.bin.gz`,
993
+ sourceId,
994
+ outputId: nodeId,
995
+ resourceType: ResourceType.DRACO_GEOMETRY,
953
996
  writePromise: () =>
954
997
  writeFileForSlpk(slpkCompressedGeometryPath, compressedGeometry, '1.bin')
955
998
  });
956
999
  } else {
957
1000
  const compressedGeometryPath = join(childPath, 'geometries/1/');
958
1001
  await this.writeQueue.enqueue({
1002
+ sourceId,
1003
+ outputId: nodeId,
1004
+ resourceType: ResourceType.DRACO_GEOMETRY,
959
1005
  writePromise: () => writeFile(compressedGeometryPath, compressedGeometry, 'index.bin')
960
1006
  });
961
1007
  }
@@ -968,12 +1014,16 @@ export default class I3SConverter {
968
1014
  * @param childPath - a child path to write resources
969
1015
  * @param slpkChildPath - resource path inside *slpk file
970
1016
  * @param nodePath - a node path
1017
+ * @param sourceId - source filename
1018
+ * @param nodeId - nodeId of a converted node for the writing
971
1019
  */
972
1020
  private async _writeShared(
973
1021
  sharedResources: SharedResourcesArrays | null,
974
1022
  childPath: string,
975
1023
  slpkChildPath: string,
976
- nodePath: string
1024
+ nodePath: string,
1025
+ sourceId: string,
1026
+ nodeId: number
977
1027
  ): Promise<void> {
978
1028
  if (!sharedResources) {
979
1029
  return;
@@ -981,15 +1031,24 @@ export default class I3SConverter {
981
1031
  sharedResources.nodePath = nodePath;
982
1032
  const sharedData = transform(sharedResources, sharedResourcesTemplate());
983
1033
  const sharedDataStr = JSON.stringify(sharedData);
1034
+ this.conversionDump.updateDoneStatus(sourceId, nodeId, ResourceType.SHARED, false);
984
1035
  if (this.options.slpk) {
985
1036
  const slpkSharedPath = join(childPath, 'shared');
986
1037
  await this.writeQueue.enqueue({
987
1038
  archiveKey: `${slpkChildPath}/shared/sharedResource.json.gz`,
1039
+ sourceId,
1040
+ outputId: nodeId,
1041
+ resourceType: ResourceType.SHARED,
988
1042
  writePromise: () => writeFileForSlpk(slpkSharedPath, sharedDataStr, 'sharedResource.json')
989
1043
  });
990
1044
  } else {
991
1045
  const sharedPath = join(childPath, 'shared/');
992
- await this.writeQueue.enqueue({writePromise: () => writeFile(sharedPath, sharedDataStr)});
1046
+ await this.writeQueue.enqueue({
1047
+ sourceId,
1048
+ outputId: nodeId,
1049
+ resourceType: ResourceType.SHARED,
1050
+ writePromise: () => writeFile(sharedPath, sharedDataStr)
1051
+ });
993
1052
  }
994
1053
  }
995
1054
 
@@ -998,11 +1057,15 @@ export default class I3SConverter {
998
1057
  * @param texture - the texture image
999
1058
  * @param childPath - a child path to write resources
1000
1059
  * @param slpkChildPath - the resource path inside *slpk file
1060
+ * @param sourceId - source filename
1061
+ * @param nodeId - nodeId of a converted node for the writing
1001
1062
  */
1002
1063
  private async _writeTexture(
1003
1064
  texture: GLTFImagePostprocessed,
1004
1065
  childPath: string,
1005
- slpkChildPath: string
1066
+ slpkChildPath: string,
1067
+ sourceId: string,
1068
+ nodeId: number
1006
1069
  ): Promise<void> {
1007
1070
  if (texture) {
1008
1071
  const format = this._getFormatByMimeType(texture?.mimeType);
@@ -1013,7 +1076,21 @@ export default class I3SConverter {
1013
1076
  case 'jpg':
1014
1077
  case 'png': {
1015
1078
  formats.push({name: '0', format});
1016
- await this.writeTextureFile(textureData, '0', format, childPath, slpkChildPath);
1079
+ this.conversionDump.updateDoneStatus(
1080
+ sourceId,
1081
+ nodeId,
1082
+ `${ResourceType.TEXTURE}/${format}`,
1083
+ false
1084
+ );
1085
+ await this.writeTextureFile(
1086
+ textureData,
1087
+ '0',
1088
+ format,
1089
+ childPath,
1090
+ slpkChildPath,
1091
+ sourceId,
1092
+ nodeId
1093
+ );
1017
1094
 
1018
1095
  if (this.generateTextures) {
1019
1096
  formats.push({name: '1', format: 'ktx2'});
@@ -1022,6 +1099,7 @@ export default class I3SConverter {
1022
1099
  const arrayToEncode = new Uint8Array(copyArrayBuffer);
1023
1100
  const ktx2TextureData = encode(
1024
1101
  {...texture.image, data: arrayToEncode},
1102
+ // @ts-expect-error - Worker encoder typing is still WIP
1025
1103
  KTX2BasisWriterWorker,
1026
1104
  {
1027
1105
  ...KTX2BasisWriterWorker.options,
@@ -1035,7 +1113,22 @@ export default class I3SConverter {
1035
1113
  }
1036
1114
  );
1037
1115
 
1038
- await this.writeTextureFile(ktx2TextureData, '1', 'ktx2', childPath, slpkChildPath);
1116
+ this.conversionDump.updateDoneStatus(
1117
+ sourceId,
1118
+ nodeId,
1119
+ `${ResourceType.TEXTURE}/ktx2`,
1120
+ false
1121
+ );
1122
+
1123
+ await this.writeTextureFile(
1124
+ ktx2TextureData,
1125
+ '1',
1126
+ 'ktx2',
1127
+ childPath,
1128
+ slpkChildPath,
1129
+ sourceId,
1130
+ nodeId
1131
+ );
1039
1132
  }
1040
1133
 
1041
1134
  break;
@@ -1043,17 +1136,39 @@ export default class I3SConverter {
1043
1136
 
1044
1137
  case 'ktx2': {
1045
1138
  formats.push({name: '1', format});
1046
- await this.writeTextureFile(textureData, '1', format, childPath, slpkChildPath);
1139
+ this.conversionDump.updateDoneStatus(
1140
+ sourceId,
1141
+ nodeId,
1142
+ `${ResourceType.TEXTURE}/${format}`,
1143
+ false
1144
+ );
1145
+ await this.writeTextureFile(
1146
+ textureData,
1147
+ '1',
1148
+ format,
1149
+ childPath,
1150
+ slpkChildPath,
1151
+ sourceId,
1152
+ nodeId
1153
+ );
1047
1154
 
1048
1155
  if (this.generateTextures) {
1049
1156
  formats.push({name: '0', format: 'jpg'});
1050
1157
  const decodedFromKTX2TextureData = encode(texture.image!.data[0], ImageWriter);
1158
+ this.conversionDump.updateDoneStatus(
1159
+ sourceId,
1160
+ nodeId,
1161
+ `${ResourceType.TEXTURE}/jpg`,
1162
+ false
1163
+ );
1051
1164
  await this.writeTextureFile(
1052
1165
  decodedFromKTX2TextureData,
1053
1166
  '0',
1054
1167
  'jpg',
1055
1168
  childPath,
1056
- slpkChildPath
1169
+ slpkChildPath,
1170
+ sourceId,
1171
+ nodeId
1057
1172
  );
1058
1173
  }
1059
1174
  }
@@ -1073,13 +1188,17 @@ export default class I3SConverter {
1073
1188
  * @param format
1074
1189
  * @param childPath
1075
1190
  * @param slpkChildPath
1191
+ * @param sourceId
1192
+ * @param nodeId
1076
1193
  */
1077
1194
  private async writeTextureFile(
1078
1195
  textureData: Uint8Array | Promise<ArrayBuffer>,
1079
1196
  name: string,
1080
1197
  format: 'jpg' | 'png' | 'ktx2',
1081
1198
  childPath: string,
1082
- slpkChildPath: string
1199
+ slpkChildPath: string,
1200
+ sourceId: string,
1201
+ nodeId: number
1083
1202
  ): Promise<void> {
1084
1203
  if (this.options.slpk) {
1085
1204
  const slpkTexturePath = join(childPath, 'textures');
@@ -1087,12 +1206,18 @@ export default class I3SConverter {
1087
1206
 
1088
1207
  await this.writeQueue.enqueue({
1089
1208
  archiveKey: `${slpkChildPath}/textures/${name}.${format}`,
1209
+ sourceId,
1210
+ outputId: nodeId,
1211
+ resourceType: `${ResourceType.TEXTURE}/${format}`,
1090
1212
  writePromise: () =>
1091
1213
  writeFileForSlpk(slpkTexturePath, textureData, `${name}.${format}`, compress)
1092
1214
  });
1093
1215
  } else {
1094
1216
  const texturePath = join(childPath, `textures/${name}/`);
1095
1217
  await this.writeQueue.enqueue({
1218
+ sourceId,
1219
+ outputId: nodeId,
1220
+ resourceType: `${ResourceType.TEXTURE}/${format}`,
1096
1221
  writePromise: () => writeFile(texturePath, textureData, `index.${format}`)
1097
1222
  });
1098
1223
  }
@@ -1103,11 +1228,15 @@ export default class I3SConverter {
1103
1228
  * @param attributes - feature attributes
1104
1229
  * @param childPath - a child path to write resources
1105
1230
  * @param slpkChildPath - the resource path inside *slpk file
1231
+ * @param sourceId - source filename
1232
+ * @param nodeId - nodeId of a converted node for the writing
1106
1233
  */
1107
1234
  private async _writeAttributes(
1108
1235
  attributes: ArrayBuffer[] | null = [],
1109
1236
  childPath: string,
1110
- slpkChildPath: string
1237
+ slpkChildPath: string,
1238
+ sourceId: string,
1239
+ nodeId: number
1111
1240
  ): Promise<void> {
1112
1241
  if (attributes?.length && this.attributeMetadataInfo.attributeStorageInfo.length) {
1113
1242
  const minimumLength =
@@ -1118,16 +1247,27 @@ export default class I3SConverter {
1118
1247
  for (let index = 0; index < minimumLength; index++) {
1119
1248
  const folderName = this.attributeMetadataInfo.attributeStorageInfo[index].key;
1120
1249
  const fileBuffer = new Uint8Array(attributes[index]);
1121
-
1250
+ this.conversionDump.updateDoneStatus(
1251
+ sourceId,
1252
+ nodeId,
1253
+ `${ResourceType.ATTRIBUTES}/${folderName}`,
1254
+ false
1255
+ );
1122
1256
  if (this.options.slpk) {
1123
1257
  const slpkAttributesPath = join(childPath, 'attributes', folderName);
1124
1258
  await this.writeQueue.enqueue({
1125
1259
  archiveKey: `${slpkChildPath}/attributes/${folderName}.bin.gz`,
1260
+ sourceId,
1261
+ outputId: nodeId,
1262
+ resourceType: `${ResourceType.ATTRIBUTES}/${folderName}`,
1126
1263
  writePromise: () => writeFileForSlpk(slpkAttributesPath, fileBuffer, '0.bin')
1127
1264
  });
1128
1265
  } else {
1129
1266
  const attributesPath = join(childPath, `attributes/${folderName}/0`);
1130
1267
  await this.writeQueue.enqueue({
1268
+ sourceId,
1269
+ outputId: nodeId,
1270
+ resourceType: `${ResourceType.ATTRIBUTES}/${folderName}`,
1131
1271
  writePromise: () => writeFile(attributesPath, fileBuffer, 'index.bin')
1132
1272
  });
1133
1273
  }
@@ -241,3 +241,11 @@ export const AttributeType = {
241
241
  /** Integer data type name for feature attributes */
242
242
  SHORT_INT_TYPE: 'Int32'
243
243
  } as const;
244
+
245
+ export enum ResourceType {
246
+ ATTRIBUTES = 'ATTRIBUTES',
247
+ DRACO_GEOMETRY = 'DRACO_GEOMETRY',
248
+ GEOMETRY = 'GEOMETRY',
249
+ SHARED = 'SHARED',
250
+ TEXTURE = 'TEXTURE'
251
+ }