@wildshard/shard-format 0.0.1 → 0.4.6
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/corpus/brasscap-mesa/blobs/bin/02da0052111419cdff3a29f1c6d0ff0d223e0b53a956c16c65ed63d87928b3b9.bin +0 -0
- package/corpus/brasscap-mesa/blobs/bin/068a121cd780a2a9164416f6e4fde44834f2d2f3a5ed65c174e480b7a2d3f627.bin +0 -0
- package/corpus/brasscap-mesa/blobs/bin/07d5a061cd338618e528747d61eb2b17709510550ef0ba40a58b67761b200f3f.bin +0 -0
- package/corpus/brasscap-mesa/blobs/bin/086e3706070555baca863f6ecf9dbca09c084afa501d92d4246d896b09546f36.bin +0 -0
- package/corpus/brasscap-mesa/blobs/bin/08b1b9ab7c732d7dbe8f961f1fc40e84042d1fe42544f55c9ee89f04dffe3d5e.bin +0 -0
- package/corpus/brasscap-mesa/blobs/bin/18bdbdc704cb8aac93435d208dfe0e9a44374efb73afa3bc58c631650e0a2995.bin +0 -0
- package/corpus/brasscap-mesa/blobs/bin/1a210fcddcb9749ecb1c244837e8e37ea69b038faae191dee6bbbde228d31a18.bin +0 -0
- package/corpus/brasscap-mesa/blobs/bin/264ab9ede386504a5ff9814b0a620b879cb29f3f45a80bcfc0c80b8ee236e364.bin +0 -0
- package/corpus/brasscap-mesa/blobs/bin/2b6fbea4c846a23cf4802ebdb1804e128896c8dd87e5d23509db6729e5b1be4e.bin +0 -0
- package/corpus/brasscap-mesa/blobs/bin/2d755cc635dee90b0f3958272855a821e2dd605a189a5ffcd480a325155fe84f.bin +0 -0
- package/corpus/brasscap-mesa/blobs/bin/2d76c6829fe77fb55cc2541e4aca5ce5d18b68508dcdf3fa957fe4a83b9c887a.bin +0 -0
- package/corpus/brasscap-mesa/blobs/bin/32c15d55a4548501740593807c5007217c72dbc10a21f4613ef5e0cee0b90d1d.bin +0 -0
- package/corpus/brasscap-mesa/blobs/bin/3539b362cf3a61a79e92e113ebf8f255d0b25ec2d2edd816498879de831fa912.bin +0 -0
- package/corpus/brasscap-mesa/blobs/bin/3af38a2377bc89f6c6c82ee1e83df674efa2793db932b50a23bbce7ec9cd7941.bin +0 -0
- package/corpus/brasscap-mesa/blobs/bin/3c176a7a0d0850fdcee790ed2641216fc3d1cba025928de3d7784262bb9b6f4a.bin +0 -0
- package/corpus/brasscap-mesa/blobs/bin/3fb37e488aa81a64c997b3dd09794e988994c6ee3476c6d653ced1670888dd8e.bin +0 -0
- package/corpus/brasscap-mesa/blobs/bin/424dcc7b320317bf3f2c62c8f19bc80564035127eb38ab811e460934d57ea38c.bin +0 -0
- package/corpus/brasscap-mesa/blobs/bin/45cea35fab6bb06051a3286fca2307944850c7f9ed7aa89b7c24fafef28efda6.bin +0 -0
- package/corpus/brasscap-mesa/blobs/bin/499cc7863851f97d79dbfc64e76f9e6978894199184a0d80ebdca13066a8fa78.bin +0 -0
- package/corpus/brasscap-mesa/blobs/bin/4b7217644763b00c6ee6ae3f176c726914966fb791654a385c0638bb998b6dd2.bin +0 -0
- package/corpus/brasscap-mesa/blobs/bin/4cf11c7177bb082f335e5bc7a037ef00d09355c5ad8263e284a96a92630ff9ae.bin +0 -0
- package/corpus/brasscap-mesa/blobs/bin/536b37cab5a1edd6a68a71d122aab6898e44c68a5470a4ca8a9a72c57c02e034.bin +0 -0
- package/corpus/brasscap-mesa/blobs/bin/55d3628b27e0fcea383df86c434a69761439f51a013359f0829675b07ee2b616.bin +0 -0
- package/corpus/brasscap-mesa/blobs/bin/5652ba90fbd8146edaf42660329cc81798752f2f60b8d03956714460d5ba75ef.bin +0 -0
- package/corpus/brasscap-mesa/blobs/bin/57459ab5e2ac6cec65ef5e59789dd82b9666d8573df41c4a398df603f1fa456f.bin +0 -0
- package/corpus/brasscap-mesa/blobs/bin/5915b6aed21bba49b841b45574f44f60d26b44810bd68ac70b22f3f3b0dab072.bin +0 -0
- package/corpus/brasscap-mesa/blobs/bin/5c4a5c7a8e99253561105c5fa3faf14326cf0c23adc32bfe7f8aea4dbf4b05f9.bin +0 -0
- package/corpus/brasscap-mesa/blobs/bin/61822a412cfd461f4f7ae50bc13f242a0fca6c5c58fca72247b596ab037a1c85.bin +0 -0
- package/corpus/brasscap-mesa/blobs/bin/673b7712908966718341508469b39cd49e6461f690ca3c23d4621ea7eba0cc30.bin +0 -0
- package/corpus/brasscap-mesa/blobs/bin/69394a49520f84f6dccc1655f1c89eedc913ac53a7e48ac5dc1bff4141639bb4.bin +0 -0
- package/corpus/brasscap-mesa/blobs/bin/6e58a53a6c2acd50f9f80fd270ca034c54421df8a587e181101b4b75b952ac5d.bin +0 -0
- package/corpus/brasscap-mesa/blobs/bin/75dc9f23ee71e11a3a0c67eb77275d741a281c3398808fb42efd52b9973d5d04.bin +0 -0
- package/corpus/brasscap-mesa/blobs/bin/76c6a403293a68ed3d6ad14e9dd27b555c3a1ef4a3cae12a2bd2ab3e67c5ad02.bin +0 -0
- package/corpus/brasscap-mesa/blobs/bin/82b73ce3a18e47092840fc029177861887aa2867b007248ac79ffa20895a4491.bin +0 -0
- package/corpus/brasscap-mesa/blobs/bin/8430d9bbfb4e2b678c54595ad95555c3c73d0e1b144a4d6e29664ccb4371baf0.bin +0 -0
- package/corpus/brasscap-mesa/blobs/bin/848d4492508689f5c4a224079dca8809e872e33b8f2635c9f16da5dc21beed16.bin +0 -0
- package/corpus/brasscap-mesa/blobs/bin/84941ac387a0d245ea20bd663ff4ee78c5315bedfa058ada0961765aff61acaf.bin +0 -0
- package/corpus/brasscap-mesa/blobs/bin/859b7bbcf048a4525db0548b8f5afef83bfc4870914767153f44c05e83436ec5.bin +0 -0
- package/corpus/brasscap-mesa/blobs/bin/87b68b45680a57c796eed9183211b03335a6ad6737372b3ef476c2cf42efa631.bin +0 -0
- package/corpus/brasscap-mesa/blobs/bin/8cef94308af8d09670e4c99a3b6c3d9280b7a27d386653a3bd7d482b2cdf2b65.bin +0 -0
- package/corpus/brasscap-mesa/blobs/bin/8e564bce3f352c2186ae09ed7fbca9739c10abc46fd5f6893c68cb47178bd2b4.bin +0 -0
- package/corpus/brasscap-mesa/blobs/bin/8f89e79d0fb9b04d48c7b5719e1d024161c6a2119835b18dcb193ff51123a9be.bin +0 -0
- package/corpus/brasscap-mesa/blobs/bin/8fe511ad48656a0b10801100b9100edab1be605a8a182dc5c834d298bf0d9166.bin +0 -0
- package/corpus/brasscap-mesa/blobs/bin/900bda6562d06fafda54c495e325d57dbb7931813178ee207449c5519d89d537.bin +0 -0
- package/corpus/brasscap-mesa/blobs/bin/997b1b7d9210bfa77dc71f16a57c6bd66bc7c648686dc2a2666044c95042978a.bin +0 -0
- package/corpus/brasscap-mesa/blobs/bin/a111bb4c6cec536bcf57dddc744b871ac9f3d094ce459c16243adca19020db77.bin +0 -0
- package/corpus/brasscap-mesa/blobs/bin/a2208bf899e6c84942eef9fbab569d597f574551afae5864f1953c6a517af068.bin +0 -0
- package/corpus/brasscap-mesa/blobs/bin/a302ddb2598a72ece53780094b64ad861dc68e6913d8a1ea08f5d141736e2986.bin +0 -0
- package/corpus/brasscap-mesa/blobs/bin/afcbc671326d0dac14e460662c1f793335877ba53cc965f67c0306833b087e7c.bin +0 -0
- package/corpus/brasscap-mesa/blobs/bin/b657159e6a28c801a211024f96a7ef60e388ce928a7b41ae3d7555a6f8fd2e3e.bin +0 -0
- package/corpus/brasscap-mesa/blobs/bin/be6bbc6cd15ba525790075252ba0ed0b28dae5cfbfa118c00dfb9ea1ab95e668.bin +0 -0
- package/corpus/brasscap-mesa/blobs/bin/c1360e3cbe6b3dc8894bc66c359853854c2e5adeac9c7cd5ba63f5db448be601.bin +0 -0
- package/corpus/brasscap-mesa/blobs/bin/c7983018dbf8e384ddf73191f526075bd0b29907061ab17642ecdc18ea7b9897.bin +0 -0
- package/corpus/brasscap-mesa/blobs/bin/cea66f27ca60ea173ee0a2bcd91964dc2638eb5657250fe3aa5bd3e41faf8730.bin +0 -0
- package/corpus/brasscap-mesa/blobs/bin/d052be571a0f3ab69926951f3a4c9d63f05da2ca6d91e5963dd63e04ecb515de.bin +0 -0
- package/corpus/brasscap-mesa/blobs/bin/d162a993a60dd682c8c21dd111429d84d8d30413a000cf481cf98d06ca83e706.bin +0 -0
- package/corpus/brasscap-mesa/blobs/bin/d238c3d3d054911714ebe30dafc99e6ad13925b7a600ba9f8d532d0f515f3f5a.bin +0 -0
- package/corpus/brasscap-mesa/blobs/bin/d9a98cfe2865a9bb0e94f35c735a570b0625b58f890a6b1f6e14fab2401f0af2.bin +0 -0
- package/corpus/brasscap-mesa/blobs/bin/dc27ae954b7b8a13a9459d6ca6ef2997f662715ff5f5453ea0da169f141748b8.bin +0 -0
- package/corpus/brasscap-mesa/blobs/bin/e3ff1fd41cf76668b8e1927c0c2e4056b63a293ebbd300a8f1b1d27d87786271.bin +0 -0
- package/corpus/brasscap-mesa/blobs/bin/e45b7344d373b3ef4a94f560cf4e17b1eb3b8cd89d1e552fc9be11d6b7b546f0.bin +0 -0
- package/corpus/brasscap-mesa/blobs/bin/eb14eb898224d5d81d1012bec54f2b79f9377dc60fa1d01e49b4c3e148292d77.bin +0 -0
- package/corpus/brasscap-mesa/blobs/bin/ed0e0101a3d91a3a615f9e78ef36f7deb8bb0eab0f133241d621925d0b596599.bin +0 -0
- package/corpus/brasscap-mesa/blobs/bin/f722e3a3b1f0a3d7b9f7d7c66c46d8c87245de5f8eece055daf95c7086f8c267.bin +0 -0
- package/corpus/brasscap-mesa/blobs/bin/f76013aedfd810f136fa689a151024bcb942687ef42ae7edf1fd3513ac4e22c7.bin +0 -0
- package/corpus/brasscap-mesa/blobs/glb/0547e63693282614673b13bade4c08eb772020757b131b7c80f2077873aab70e.glb +0 -0
- package/corpus/brasscap-mesa/blobs/glb/0cf89e9b1824440d213c8e9e33fb357734b7241b4c7eedaba3df7f8306e05425.glb +0 -0
- package/corpus/brasscap-mesa/blobs/glb/0e01060e3a507ffff6461c50b5c565c71380a6a67d9760cdd7a09afd3e30b584.glb +0 -0
- package/corpus/brasscap-mesa/blobs/glb/0ef326c5cf5292cd15b48b851460ee8156f51e0a5b62457c8f1f3c53c41665a3.glb +0 -0
- package/corpus/brasscap-mesa/blobs/glb/1112ff4a3f69db3b62c6d2d6ae021e7c43ce0ca1feb1d3130376881decb3c6b0.glb +0 -0
- package/corpus/brasscap-mesa/blobs/glb/11357cb8a0670fdc9a03780dd79a31e0aa7a0537786cbf66491bae1722d6feb3.glb +0 -0
- package/corpus/brasscap-mesa/blobs/glb/11dbecc73bd343c375bd4b79db8dbda2272e76a6b8426ac29e90f2b1272ccfc2.glb +0 -0
- package/corpus/brasscap-mesa/blobs/glb/133f639cfa837bc5da7915121c71fd32281660c2aaa0248bd59bde47e7faf8bc.glb +0 -0
- package/corpus/brasscap-mesa/blobs/glb/16812a090136b6678633aa4db03e4187920ae0aca776ad6da373c600cd341972.glb +0 -0
- package/corpus/brasscap-mesa/blobs/glb/17e63980d7934cfe1d2823d78652af338fe9f0c2170106cd4506a2c4e7f4716f.glb +0 -0
- package/corpus/brasscap-mesa/blobs/glb/199224cafc86904bdefec8f01d131d7ca3e076a22b689bfc6a26dd20373cf286.glb +0 -0
- package/corpus/brasscap-mesa/blobs/glb/1a5c8cf223a2f64715ea5eaf14d97a0131f9ebdef4388dc4823dcfa57817724c.glb +0 -0
- package/corpus/brasscap-mesa/blobs/glb/1b0ec09ad6718149d7ca514136cee09b04c96425f03af0559fd097112aa0daa5.glb +0 -0
- package/corpus/brasscap-mesa/blobs/glb/1e5024bbb1284b2ed39bbca2d0ade3acb5be2a2c6ba643291f269b76098c7f79.glb +0 -0
- package/corpus/brasscap-mesa/blobs/glb/1e7635972e13468ffcbb1608f1d12559b066b4533912be2c35e3db07fd4a679d.glb +0 -0
- package/corpus/brasscap-mesa/blobs/glb/1f03db3a38a21b8d4d02f8ede30e1303cd8d4c426815326a88f45a268b17a492.glb +0 -0
- package/corpus/brasscap-mesa/blobs/glb/2624abb7bf45618be40f8c3221445179fca44f7321baff415fdf7ddd5e0afc6f.glb +0 -0
- package/corpus/brasscap-mesa/blobs/glb/27fc3bad6db6e2b5ade5d242867d882362482ddf19c647edef821afc27d52dc2.glb +0 -0
- package/corpus/brasscap-mesa/blobs/glb/29959bdb5b04a9180e88ec1ed976bae55424d3dc50985f13c0f85bae11ae79ee.glb +0 -0
- package/corpus/brasscap-mesa/blobs/glb/308cbce2b1b6360f9a2dc275d0bc28be1966fc3ff5e0a58844405ba867f3f668.glb +0 -0
- package/corpus/brasscap-mesa/blobs/glb/3674d7be969755aaffa368e57b8d1bb743bc98e766a57948859d54fdc7d2c066.glb +0 -0
- package/corpus/brasscap-mesa/blobs/glb/3736ca95c9c40b30e21302ae6c89148d8ac09264dfbb7e5764b08c265a73ba3c.glb +0 -0
- package/corpus/brasscap-mesa/blobs/glb/3bc90e1dc9411d249697e4ec352baa4886f91cacfe4940ac43aed879f60966c9.glb +0 -0
- package/corpus/brasscap-mesa/blobs/glb/3f519c7c7482307cae908b27602dcb7716e2da4b651eff39c4c37103998d18fa.glb +0 -0
- package/corpus/brasscap-mesa/blobs/glb/4767636d5554b60c94b447b87b77fc1456a2b9af42bfe08585389d27f306dd5e.glb +0 -0
- package/corpus/brasscap-mesa/blobs/glb/4a3242773b3a73a73ee746a0cdf30c8d6d904bb4406dfdf9822dcd535d6ae308.glb +0 -0
- package/corpus/brasscap-mesa/blobs/glb/4c7bf3788cba151442d85c3f76553c2e356edf8566ae8243d0a535c9bcde51d0.glb +0 -0
- package/corpus/brasscap-mesa/blobs/glb/4f3b9f4c818ed6d375947e9603dd058c539e14ff05aa193fb5054d899dbb82a2.glb +0 -0
- package/corpus/brasscap-mesa/blobs/glb/4fdf7ee67d12de1cd30c3c2bbd9409032dcab5feb3a7d3977b92c50b1d161afe.glb +0 -0
- package/corpus/brasscap-mesa/blobs/glb/5821f33aa00e9acd2f4c0a29129978ee7006a879d163ce1463ae476031bfabcf.glb +0 -0
- package/corpus/brasscap-mesa/blobs/glb/5a986c3e44fc686a2efe7648c3945bb7b51cf303918381383f21f898dd312cad.glb +0 -0
- package/corpus/brasscap-mesa/blobs/glb/5c32fc1de6d198ed606d3e8c3264319acdd950dab18e8b723fc6332bf2f56aea.glb +0 -0
- package/corpus/brasscap-mesa/blobs/glb/602ce4e8b00a0afbc1a894b65641e48d362ec834a559b9d97a4801473bb01da7.glb +0 -0
- package/corpus/brasscap-mesa/blobs/glb/6180f9f96167522d8cab4de1d52598cecee8d7ee042f48e41669c98cf61c19c3.glb +0 -0
- package/corpus/brasscap-mesa/blobs/glb/6205973ba63f7a554662ba05010d25131bed2d9656de422e2067ca54709d5b3c.glb +0 -0
- package/corpus/brasscap-mesa/blobs/glb/693e556f2165232e8a38b1b2d68676f235ece5705c564992cfa7731426f4d376.glb +0 -0
- package/corpus/brasscap-mesa/blobs/glb/6a46175438bec5527c281b577bd220b6badedf3c74266b997d39e596f83b8853.glb +0 -0
- package/corpus/brasscap-mesa/blobs/glb/6ca1bcad7ea053a259b7f9fc5a7ec388a4cd29d44391d93386ea8b1143d94c21.glb +0 -0
- package/corpus/brasscap-mesa/blobs/glb/6f9bc99656b611890d6acc76ee416f6222ca2d5f62167840b4216a21e020a4c8.glb +0 -0
- package/corpus/brasscap-mesa/blobs/glb/6fb1e7857996662233ab5314fc13f8aa30703f91c04542e352ec17f9dc4fc054.glb +0 -0
- package/corpus/brasscap-mesa/blobs/glb/7028ec39712143a7e9d09d2e1477282b654d0470102ca9d272ac82b23604cb21.glb +0 -0
- package/corpus/brasscap-mesa/blobs/glb/73af65ac86efa61099178f3e7075dcd26d389ee9b9aa3546c18dede10c3dfda1.glb +0 -0
- package/corpus/brasscap-mesa/blobs/glb/73b992b71bd3165ff7701ab1430c075cb5ba9b74e6363d24640377b1011ddc93.glb +0 -0
- package/corpus/brasscap-mesa/blobs/glb/7471261d4df59979ba41a622d93779b66ebecd50353ad433862e603ee65f8748.glb +0 -0
- package/corpus/brasscap-mesa/blobs/glb/76e9a3fcca962c2f900cf79dc1a0851840bd405dc11231f629f784adbcb69d23.glb +0 -0
- package/corpus/brasscap-mesa/blobs/glb/79d2d29e8cd8b642386b5f31429b39bc4d6f13e53107dda00ebc463abf80c79d.glb +0 -0
- package/corpus/brasscap-mesa/blobs/glb/7de66fcfffe4ff108510cbe6bebec44e28ab4b78e98e9c1a38466db5b81881f7.glb +0 -0
- package/corpus/brasscap-mesa/blobs/glb/811fa798cb81ea99488db98e3d3ddea815aac8f6e7493ad04d0176f603978678.glb +0 -0
- package/corpus/brasscap-mesa/blobs/glb/89b277f1636be220ff5658ff1f1c62efe14079d6e1f42efb373fbf0246801533.glb +0 -0
- package/corpus/brasscap-mesa/blobs/glb/905c5fe666d9f6174e987382e47d3f325c5696cf8792d7a4a1dd120a438b8270.glb +0 -0
- package/corpus/brasscap-mesa/blobs/glb/90efe3e05370ee853c0130b98ee82f00b86f7c7104e96b094715187fa49ac16f.glb +0 -0
- package/corpus/brasscap-mesa/blobs/glb/968a7c5cb13014bce00a29d43b344bd6943ff00ae2908abbc6b40a994f1172a1.glb +0 -0
- package/corpus/brasscap-mesa/blobs/glb/9a955b4e69dfa5b38f071099053c1a3684cf85ec2d346420de2853c61768f8cc.glb +0 -0
- package/corpus/brasscap-mesa/blobs/glb/9da2781216a2e482dd8a6ada5ebb43bcf48e0169430e787ac277559cb2ade19a.glb +0 -0
- package/corpus/brasscap-mesa/blobs/glb/9db02aab14a3b52463deadefbf4ba771809941e7fcb137c905955bdc80ec23bd.glb +0 -0
- package/corpus/brasscap-mesa/blobs/glb/a3fe1788cf5d7f260249c722f0e0695a4d55744d1b14be44122377147a296256.glb +0 -0
- package/corpus/brasscap-mesa/blobs/glb/a5c75af8f090d3c95fa46d2be49be5031138d7cd1bae234ae028edf717bf299e.glb +0 -0
- package/corpus/brasscap-mesa/blobs/glb/a771abd40bd337a464c1bd19f841b62e290124faa89b19ec50e85ab36bc740a5.glb +0 -0
- package/corpus/brasscap-mesa/blobs/glb/a94a2ad2ed463a47cdda117df25b06b3cf6be37ddac08594bc5f5d76c7237730.glb +0 -0
- package/corpus/brasscap-mesa/blobs/glb/ad434e4a6490e495994b25f7574a5847a9f7d9c2ca5a2b229a9dfdd2e5e2bb72.glb +0 -0
- package/corpus/brasscap-mesa/blobs/glb/aeae7b05404b852008a7897689e58aacef44a2c3bc0e87d2519ecdb4cb1e3ff5.glb +0 -0
- package/corpus/brasscap-mesa/blobs/glb/b0c0c8a4985f92be3b358a8e703c67957427501882aeee05b4ccd3c7880930d4.glb +0 -0
- package/corpus/brasscap-mesa/blobs/glb/b25174c3cd13eea6e1d9c3104ee5197dc6330129b2f0f7676e8a429900999d9b.glb +0 -0
- package/corpus/brasscap-mesa/blobs/glb/b3eecdec571df96338edf690443394ff859383b4c94f4cf33d42c240006f8543.glb +0 -0
- package/corpus/brasscap-mesa/blobs/glb/b7aa0c61ff9e7411535c7b7b8e587849a92bad00d431171ab16ad47d55db0a53.glb +0 -0
- package/corpus/brasscap-mesa/blobs/glb/b9deef944c22331bc05220d1d6e46412e3cb1246ef041a4405d0cbbd90c2d624.glb +0 -0
- package/corpus/brasscap-mesa/blobs/glb/ba9376e4ac39b809133ab717edb4c88b5219118766db492d7c97534ce119c2ec.glb +0 -0
- package/corpus/brasscap-mesa/blobs/glb/baf338e9c272158b905fb58a712e29410c657a45be2764f1c6c43ca87fd1db48.glb +0 -0
- package/corpus/brasscap-mesa/blobs/glb/bd442ac9fbe52b9f2e4ba586670017c3f2d9fedf1cbdec77ef24e9f8b3a183c8.glb +0 -0
- package/corpus/brasscap-mesa/blobs/glb/c142adcf253be43b66f23ede8cea1e8fcfa256ebf53054a1068ace04745718a6.glb +0 -0
- package/corpus/brasscap-mesa/blobs/glb/c6d7cbdc4b2ee9d416edf4d736a4f374f08aea98ca395ad371a50a1853744cfc.glb +0 -0
- package/corpus/brasscap-mesa/blobs/glb/cfb165a7675d15cee2c490b31095a58f73bace50ccc1e0fdf2c8dc4400f1df27.glb +0 -0
- package/corpus/brasscap-mesa/blobs/glb/d40f2ee59612473e9f687f17a0e203fdb4ba54c7185b05a8d81a433b04f24134.glb +0 -0
- package/corpus/brasscap-mesa/blobs/glb/d50ce95411156a6b6cf386aefa5ee58db659811813f74be74f323e7c5795056f.glb +0 -0
- package/corpus/brasscap-mesa/blobs/glb/d6af418bbde39b4fc7d22a61401d416be7a3fc1214ea2d3f42b4549c392d22ca.glb +0 -0
- package/corpus/brasscap-mesa/blobs/glb/de7222ceeb1f72693dfb7fd1f343798659e03772d77f2b498fd8ebece2d5550a.glb +0 -0
- package/corpus/brasscap-mesa/blobs/glb/e26975b198127ac3b6b4f5c4bc08ad47d6691398feee777743285391cd36d502.glb +0 -0
- package/corpus/brasscap-mesa/blobs/glb/ea428490cd5f2672676a2776a598b819b08246871e76de94b7196f9643144986.glb +0 -0
- package/corpus/brasscap-mesa/blobs/glb/eb96567a266d24be188cb5b08021112f2fad311cbead939d53c5565da11f6265.glb +0 -0
- package/corpus/brasscap-mesa/blobs/glb/ecf66230bf7b68050c0827c2e4caf3de90e46859d291b794faa0dd3816d9dac6.glb +0 -0
- package/corpus/brasscap-mesa/blobs/glb/ed8f067763a4a8adb83d80c8324b2a9668f1061f5f5352f21295e6cc5132386f.glb +0 -0
- package/corpus/brasscap-mesa/blobs/glb/ee507a38772865467736d370791fe73c6aa4d83fe3e7ff4baa156b9cb2894c1c.glb +0 -0
- package/corpus/brasscap-mesa/blobs/glb/eedc5b62dc6f27d4a089e9f5b282f626129236d3f1689b001e04f8748bf8859c.glb +0 -0
- package/corpus/brasscap-mesa/blobs/glb/f4119b9c6c23435619682b5d247743459e76584b9b0d6c5cb689d8e156906695.glb +0 -0
- package/corpus/brasscap-mesa/blobs/glb/f576047267a0bf9bd4bfc47072ea3d11066345b839953546292da678d1cb4722.glb +0 -0
- package/corpus/brasscap-mesa/blobs/glb/f8cdfb11997d4ccabea88bcdd3924cc8b621b33618b18fe5fbfd286edfc1d87e.glb +0 -0
- package/corpus/brasscap-mesa/blobs/glb/fce95ecc5db24c903bd46f338e366e2715411465a5efac180e2f0f46397e59de.glb +0 -0
- package/corpus/brasscap-mesa/blobs/image/0579557f9344df6f2c4b1225e6252e53ab86d417a4c9b504b5c714a08a388e47.jpg +0 -0
- package/corpus/brasscap-mesa/blobs/image/9e18816a2ec16fbbb1f00f4a39c73ac2cbf6a8cdc17b4c96b1eba4cc9a754dc7.jpg +0 -0
- package/corpus/brasscap-mesa/blobs/image/eb453c71cfb1f9441eb00b32281f98e226e49d9dcf75c231455575fcdc652222.jpg +0 -0
- package/corpus/brasscap-mesa/blobs/json/e0072ed82115c519b891f53a194ea3b28fff7d3826d8ddf23460d6f21b7728d9.json +1 -0
- package/corpus/brasscap-mesa/blobs/json/ffb0e08eaaa7188db1f55931c9b6330937316091cc7463ed2eff6767bbfa33de.json +1 -0
- package/corpus/brasscap-mesa/blobs/wasm/1d6ace79610c4d510b60ad0c52915e42b57797d91f1ef292f60d8a3daec03dd6.wasm +0 -0
- package/corpus/brasscap-mesa/blobs/wasm/24a4d4c1292677b1c984b5c0d3497ae2929528bf511df475f80cc20945bb08ec.wasm +0 -0
- package/corpus/brasscap-mesa/blobs/wasm/b86d8afcc269fb063ebf64768fc3787635b65a7409a571115b07be2e4da39733.wasm +0 -0
- package/corpus/brasscap-mesa/cook.json +1 -0
- package/corpus/brasscap-mesa/mounts/shardfiles/brasscap-mesa/discovery.json +1 -0
- package/corpus/brasscap-mesa/sections/actors/creatures.json +1 -0
- package/corpus/brasscap-mesa/sections/actors/crowds.json +1 -0
- package/corpus/brasscap-mesa/sections/actors/species.json +1 -0
- package/corpus/brasscap-mesa/sections/audio/audio.json +1 -0
- package/corpus/brasscap-mesa/sections/combat/encounters.json +1 -0
- package/corpus/brasscap-mesa/sections/combat/items.json +1 -0
- package/corpus/brasscap-mesa/sections/combat/strikes.json +1 -0
- package/corpus/brasscap-mesa/sections/economy/ledger.json +1 -0
- package/corpus/brasscap-mesa/sections/economy/loot.json +1 -0
- package/corpus/brasscap-mesa/sections/look/look.json +1 -0
- package/corpus/brasscap-mesa/sections/look/materials.json +1 -0
- package/corpus/brasscap-mesa/sections/quests/quests.json +1 -0
- package/corpus/brasscap-mesa/sections/sim/client-scripts.json +1 -0
- package/corpus/brasscap-mesa/sections/sim/hooks.json +1 -0
- package/corpus/brasscap-mesa/sections/sim/plumbing.json +1 -0
- package/corpus/brasscap-mesa/sections/sim/scripts.json +1 -0
- package/corpus/brasscap-mesa/sections/sim/sim.json +1 -0
- package/corpus/brasscap-mesa/sections/state/migrations.json +1 -0
- package/corpus/brasscap-mesa/sections/state/state.json +1 -0
- package/corpus/brasscap-mesa/sections/ui/card.json +1 -0
- package/corpus/brasscap-mesa/sections/ui/compendium.json +1 -0
- package/corpus/brasscap-mesa/sections/ui/level.json +1 -0
- package/corpus/brasscap-mesa/sections/ui/ui.json +1 -0
- package/corpus/brasscap-mesa/sections/world/collision.json +1 -0
- package/corpus/brasscap-mesa/sections/world/days.json +1 -0
- package/corpus/brasscap-mesa/sections/world/edge.json +1 -0
- package/corpus/brasscap-mesa/sections/world/movers.json +1 -0
- package/corpus/brasscap-mesa/sections/world/navigation.json +1 -0
- package/corpus/brasscap-mesa/sections/world/props.json +1 -0
- package/corpus/brasscap-mesa/sections/world/spawn.json +1 -0
- package/corpus/brasscap-mesa/sections/world/terrain.json +1 -0
- package/corpus/brasscap-mesa/sections/world/tiles.json +1 -0
- package/corpus/brasscap-mesa/sections/world/traversal.json +1 -0
- package/corpus/brasscap-mesa/sections/world/water.json +1 -0
- package/corpus/brasscap-mesa/sections/world/weather.json +1 -0
- package/corpus/brasscap-mesa/shard.json +1 -0
- package/corpus/brasscap-mesa/validation.json +1 -0
- package/corpus/handwritten/blobs/bin/027822f6ae9c374ce1ced851f2227cb9acb03077e5cc6b7fecb245c31f021abd.bin +0 -0
- package/corpus/handwritten/blobs/bin/0377ce182bd604bcf4d501f14bf954c434ea64ad856ad9d71c502d1045612703.bin +0 -0
- package/corpus/handwritten/blobs/bin/05ad93d239eeeb5d9afa09b00d90c56098d88e8850e5b5e691fcaa7520dec3cd.bin +0 -0
- package/corpus/handwritten/blobs/bin/0c8980141e6e394ea473df1eb11c347ba617a1a9a4b39b3fa1871b5d15b97d87.bin +0 -0
- package/corpus/handwritten/blobs/bin/14eb11f8d809320e0a68b1edea7837d7a5b4a3da71f1ce4f54068e0afe0b039b.bin +0 -0
- package/corpus/handwritten/blobs/bin/16590066c039ac71e5038a9866a53ccb95e21af13db29cb655b379c4fcfef7bb.bin +0 -0
- package/corpus/handwritten/blobs/bin/1795b5147ad52482445d2414ee22823b947c43a917b6e96fd9ec017f17000912.bin +0 -0
- package/corpus/handwritten/blobs/bin/18f2e24ecc1ed1b1d12ae1c89732a5a1a618ab6e973d4ff0332cf9ecc4e4f4a6.bin +0 -0
- package/corpus/handwritten/blobs/bin/1a18ade01095f1a9ebe75650127861ef27dda0bb17c2b91bde057ec88ef2e98a.bin +0 -0
- package/corpus/handwritten/blobs/bin/1dba017cddb874bc147efb00c55418846ffa344a696f4df702bbabeea55034d0.bin +0 -0
- package/corpus/handwritten/blobs/bin/248c703537e4687ddd2b69a40d1ef3936da718626289d6867ce0a6866f562ba4.bin +0 -0
- package/corpus/handwritten/blobs/bin/2612d9fd4727f8c349f2dbfb7b1650bb7a752d0798a4966ac22cf2b6cdd9fcef.bin +0 -0
- package/corpus/handwritten/blobs/bin/28c54c766e90e3b046a2377b9fa015b0ce45cf3da4420f2b10553251f86c06aa.bin +0 -0
- package/corpus/handwritten/blobs/bin/30866b4807b12579f50218f6525c3db00919fbd43c97921daf47b3244b25dca6.bin +0 -0
- package/corpus/handwritten/blobs/bin/3d14fae85d77406a9b8c59f2e973cdae9587d49108ea92fb460679ca860196b8.bin +0 -0
- package/corpus/handwritten/blobs/bin/3f2201a53c441abcfb52089fe9bbb01f26fac8744099d3fb6668452885c2fa11.bin +0 -0
- package/corpus/handwritten/blobs/bin/42f270a99367fc4cc901518ccaa344ab595e265f113be944510da745c11f69d1.bin +0 -0
- package/corpus/handwritten/blobs/bin/43fd4327fedd51a586684ac611bcad4a8b9d62e51e03967de71fb42c9bf0f6e1.bin +0 -0
- package/corpus/handwritten/blobs/bin/484adda0898a881b6f095dad447f6a619bf0933f65efe940b72f1ab7f3630c22.bin +0 -0
- package/corpus/handwritten/blobs/bin/4a38cd49e8797429ce76265c3d8972195d5b0a02a35fc05fc513eab11240f415.bin +0 -0
- package/corpus/handwritten/blobs/bin/4fe636237bbbd4f836b0816bc61702f4c224d4cb91fbd94f244c731e24a1b945.bin +0 -0
- package/corpus/handwritten/blobs/bin/51b1cff782dc7ebb382bc429ee965023d4cdb52c7b3e37d6ffff5ef55c1c2813.bin +0 -0
- package/corpus/handwritten/blobs/bin/52561f02071ecaa98432fab5e8ece407a8e8f733a01f8eb7c543d1efe02614da.bin +0 -0
- package/corpus/handwritten/blobs/bin/556d6333923afea9641c4738741a41d6a46ae28a508288b9a49a749a344c1398.bin +0 -0
- package/corpus/handwritten/blobs/bin/5caeb97f32c7f31e1029eebdf31131f879f781bb5e3a225206a646710d83fd75.bin +0 -0
- package/corpus/handwritten/blobs/bin/5d1131e42a045083225105b640ff72e02c7f353ee6285545ac264d01bea26b1b.bin +0 -0
- package/corpus/handwritten/blobs/bin/5d80b30eee9f8342a92f6756fd0d84fb9d2d2ce994d222627641e584ad45d2a8.bin +0 -0
- package/corpus/handwritten/blobs/bin/5e0f9f7f2a85abe11a0a61ede853c9b9942b4494c3eb9943785cf6ae221e40e3.bin +0 -0
- package/corpus/handwritten/blobs/bin/5fdc5485343bba8201185c9bae862ad8618498ab5ce63b53514e4e0226fa7bdb.bin +0 -0
- package/corpus/handwritten/blobs/bin/6623dcb0b31c9ca0be342f6dca6b9e607ec3c12ff82068fa6030c142c2df77f7.bin +0 -0
- package/corpus/handwritten/blobs/bin/6887131a04175edbd1989aa95e8749d1703e7f2d0b8464e85f6bad28d6964125.bin +0 -0
- package/corpus/handwritten/blobs/bin/6cf89771d998486cad9049e6f4fc177d742a18ad79fafa4596814ff9d3cf1952.bin +0 -0
- package/corpus/handwritten/blobs/bin/74bbb0fc219e8476cd5550014a357ee18abc981ff3fe787ae3e60d4593705ec5.bin +0 -0
- package/corpus/handwritten/blobs/bin/76784a7f519ac43ce113a0c9365881839b75f66f96aa009fe8d3c8ab539ef283.bin +0 -0
- package/corpus/handwritten/blobs/bin/79a2f693ee2da546bb551f8b641b9c3affd2b8bfb5632ed7f417daba9d900af9.bin +0 -0
- package/corpus/handwritten/blobs/bin/7b593b0f9eefb957fb9d58b316d9836971203038d7c8127284bba44ccb3090bb.bin +0 -0
- package/corpus/handwritten/blobs/bin/7bb8e518ca5606de78972a6c648b57623f8bc12d7e06b4bbf43c60ac419a9bbd.bin +0 -0
- package/corpus/handwritten/blobs/bin/7c6133f3350147257fa501f41269cb77cb11d8ed96d351e873333b079cee524a.bin +0 -0
- package/corpus/handwritten/blobs/bin/7f5acf1893828995256f5b2c54948f80ba21e53de72db26ea72ce2479f5b0682.bin +0 -0
- package/corpus/handwritten/blobs/bin/836516253cf0f3e6e79537609fdbe6331c8c5c974f9ec4d3fbe4a7db48cf123d.bin +0 -0
- package/corpus/handwritten/blobs/bin/89900344f82d5c1474d2a163f8d29903447bac64e9c9775123ef499be70c2380.bin +0 -0
- package/corpus/handwritten/blobs/bin/95d76a9273c3edd98b3643c54e2e7989800bdcaf6f815230ef09f601e760330f.bin +0 -0
- package/corpus/handwritten/blobs/bin/a7b5a5fe053a38c93eed899bde5051cddd80e0a3f3c82b6fd814869097f0944b.bin +0 -0
- package/corpus/handwritten/blobs/bin/b29be84df0bfd1bc97a1464fd5ea068130947bfed3328e167640c81326eb45d7.bin +0 -0
- package/corpus/handwritten/blobs/bin/b6518dc352be03332a256f1cd9d1149da262fe6829e87ba43364f19c687ca7c9.bin +0 -0
- package/corpus/handwritten/blobs/bin/b7edb8095beeb158adb61ae3caa1653773757afbcd8fb2764c94b975a43fe9e2.bin +0 -0
- package/corpus/handwritten/blobs/bin/b86d617ae7fa397df51ff7af87cd89fa113ac19abd3840ea8f3a086d6c82905c.bin +0 -0
- package/corpus/handwritten/blobs/bin/bb860b5c67ee7f2fafd67588822152228d6f6c9de1231123eeafa4844732b18b.bin +0 -0
- package/corpus/handwritten/blobs/bin/bf8c3971bbb224075d488ffa9cfc20e322c61f9ca0c59c356838415f6778014b.bin +0 -0
- package/corpus/handwritten/blobs/bin/c2edd52ee14ebdc9fcc01d38c15d6ab3379df7a20098c260c546551898959cd1.bin +0 -0
- package/corpus/handwritten/blobs/bin/c3de13c551c5b45270143dcbb9fc9a31651f6012355823c0709c2fe6cafda940.bin +0 -0
- package/corpus/handwritten/blobs/bin/c57a8d9da18b1289afd16de00dd1ec75027048b8dcf7dd218da36bc3276ff035.bin +0 -0
- package/corpus/handwritten/blobs/bin/cc2975c9dea4c31b1bf380623a8f44059423004653f9cae4f603d374174323b7.bin +0 -0
- package/corpus/handwritten/blobs/bin/d476abba2e1c63ad3c7527617559173484ee837a5be2744d968466d5527c286b.bin +0 -0
- package/corpus/handwritten/blobs/bin/db242f89115c878cf0c3b976a1647e9cdeb6a1a51813b1dacaf1188715603294.bin +0 -0
- package/corpus/handwritten/blobs/bin/dcc4b9b3bc4ca777d11c494ae5478f17ad7cf2efa18dcba30def872d55355bc3.bin +0 -0
- package/corpus/handwritten/blobs/bin/dd99da483f385327d6b8319d6e2e9000b580280069353718aa0fda2230707e8b.bin +0 -0
- package/corpus/handwritten/blobs/bin/dfc139dba26f1789e16f72602e654636f2d99bcd41e3f10454da74b3a6a64dda.bin +0 -0
- package/corpus/handwritten/blobs/bin/e15ab3cc9f60657321cfe8d9751e086f025734f4e7068271e0baf6066a686f18.bin +0 -0
- package/corpus/handwritten/blobs/bin/e16a83a71213db6f804ce1d53981a2308062752c85c440022d9eeb7605fd37c8.bin +0 -0
- package/corpus/handwritten/blobs/bin/e7355876487f660ac9f25c9d9dfcd66eaf432e1e1669eb89d12ce8267a8d3e86.bin +0 -0
- package/corpus/handwritten/blobs/bin/e81a632e2da0f6a4d801f18aadfe2c6e640401cc1178935a9099ebb8e3af6cc1.bin +0 -0
- package/corpus/handwritten/blobs/bin/f0721c60d0b1046579d8c587fac8482a70822f0b39a85f9acc0cfc31f82b7dd2.bin +0 -0
- package/corpus/handwritten/blobs/bin/f301cf574de6d84030f839098ca44705dca115f9d3e4ee848e0b35fff3deaf77.bin +0 -0
- package/corpus/handwritten/blobs/bin/f7797f295a7570c437bf7020a1ddf208fea2a7aab595333320a6396c1608d360.bin +0 -0
- package/corpus/handwritten/blobs/glb/08de0bb2439ac812adef528b4b073bdb954bbeada972a2f3afb1757bd0540396.glb +0 -0
- package/corpus/handwritten/blobs/glb/153681171c35d2898569324e21ebe734b8418d4122833618a1e64ea326be1e5e.glb +0 -0
- package/corpus/handwritten/blobs/glb/1df5ce0b6cae72ec4cf3c41510681ba70ebb474f9745d536ebd4f03e8fc82de9.glb +0 -0
- package/corpus/handwritten/blobs/glb/262031e2fa710bd8d586eafce1019ca1434a2170e407567741aac1d99fc9c5ab.glb +0 -0
- package/corpus/handwritten/blobs/glb/27466efb180fb5b5074b40e424bd0b8d78f7ff0f5f3663748e014daeeeb5bedd.glb +0 -0
- package/corpus/handwritten/blobs/glb/2d2f6d00a14c89a4efb7f679b371118f564f258797ed8b8b42baf4ae60902ea6.glb +0 -0
- package/corpus/handwritten/blobs/glb/31f327d215ed7ef422e2169172f3869769e9816c9da979616844081e74f2eb09.glb +0 -0
- package/corpus/handwritten/blobs/glb/3bfe0e9ca18077ffee9c284ef40fed9f2fc354f7495612c785a6f980b5966559.glb +0 -0
- package/corpus/handwritten/blobs/glb/3db43042b3eeb1dee7ce9de1cc00322cefc348aa18c37d168b0858e6af6ca7a4.glb +0 -0
- package/corpus/handwritten/blobs/glb/46460a50da44fb8e792b48a646ec9ce025bb309d315dbcf67d2e9598591750de.glb +0 -0
- package/corpus/handwritten/blobs/glb/4902213556fedaf269fba6f0f195e424b2e49973ab45dcb8b69e34d253d9d8ff.glb +0 -0
- package/corpus/handwritten/blobs/glb/4dda463c9cd4bf339e5611871d4ba2fe16fe1487389a88b2888e96bc55e45d93.glb +0 -0
- package/corpus/handwritten/blobs/glb/4ed23469bd2b6b73183564cfc80a1ebcd0ffe2666a90a556752af0ca147fd2f7.glb +0 -0
- package/corpus/handwritten/blobs/glb/4fe74a1bed6b67129885b90cfcae01b5ca82e23e6d40507e280f02fca7fda54f.glb +0 -0
- package/corpus/handwritten/blobs/glb/50521bb3a50cc7199d324a0b25bc167c2e9d69770cb500490428efefc81ce3ea.glb +0 -0
- package/corpus/handwritten/blobs/glb/5ecca36d1e503edc092af0ef42f139cdcad99b8c2008318eb6ad337023d57296.glb +0 -0
- package/corpus/handwritten/blobs/glb/60fc036925852568cdb1b9fb85218dc43a8bf2ed86d3971a221ad942ece203a7.glb +0 -0
- package/corpus/handwritten/blobs/glb/611633cee0e5822b744486e6dff5414ad5b159eaabffe1c0ba0bb68be794bfa1.glb +0 -0
- package/corpus/handwritten/blobs/glb/67c7f983a0bcb9f84425378acac121a53f30795dce3181643bc1b763d0ae80b5.glb +0 -0
- package/corpus/handwritten/blobs/glb/6ecc0d307030943727484b49b1872643479c55ccc92252fca06e9e3cbe98fa90.glb +0 -0
- package/corpus/handwritten/blobs/glb/774b366df4de56cb6f9e3c904f02ec98016ac2ec489dc9e214b09220fca2f8e5.glb +0 -0
- package/corpus/handwritten/blobs/glb/785bae514ffc029e611d602259db7d37cbef589409a0814b9d37175d8b6c0a45.glb +0 -0
- package/corpus/handwritten/blobs/glb/79e79524efb2830e90af3c945c5b36ef07c1a38f2da2958112203a99eac52a16.glb +0 -0
- package/corpus/handwritten/blobs/glb/7bebdcdaf0be30d9f8d21bde72af68c32d825d12dc668f48109223ed7ff71c9f.glb +0 -0
- package/corpus/handwritten/blobs/glb/7d8b5ec9326a11362b3f9fa3409cb59d11b99f549cc304319c63c1ec55cbf5ab.glb +0 -0
- package/corpus/handwritten/blobs/glb/82e886f826315e4bf962363165fadadd3d93f85132c1909095045e0a7ccc0b34.glb +0 -0
- package/corpus/handwritten/blobs/glb/84b4ef190c3994ae7ca1b1f7a936526d1d20ad7deac13f949e3fe6bb7ba139ed.glb +0 -0
- package/corpus/handwritten/blobs/glb/85b7153e943fbe8c659bd6e4b323511dc6f6e2c7a3a1185e7a9a29ea6ddfdfa6.glb +0 -0
- package/corpus/handwritten/blobs/glb/85cf2d2be91cedbaf454ca42ad53c0c17b311088528d274695dbcea490d6c684.glb +0 -0
- package/corpus/handwritten/blobs/glb/8662b4cdc626c61a45e63f71dc866746c083cd0d4644b817a373105f936a7047.glb +0 -0
- package/corpus/handwritten/blobs/glb/8a4d33bfbb17d865e5deb0a0bdf3de67fc2312950a7568ed2635c22fbe4b1ecf.glb +0 -0
- package/corpus/handwritten/blobs/glb/8b11171d41c9027411ca8b87797d9ec70355471bdd3a247c114c49b8b781bbd9.glb +0 -0
- package/corpus/handwritten/blobs/glb/9026e1c4f0250832b69a989e69fe3071e5cad72adfe9c22ce11c409b18bb3357.glb +0 -0
- package/corpus/handwritten/blobs/glb/945b946f17b6393ea040230641c3083678bb6ab42e1d7239aeb9c950d0e7d5bb.glb +0 -0
- package/corpus/handwritten/blobs/glb/9afab455d603f1f8a38074c5a6cbed26d7d7f2cfd8a531820bd165d4b37399ee.glb +0 -0
- package/corpus/handwritten/blobs/glb/a6d702fb1be1095517625bfb2a2383f5f9638775059fd7e0d093d2044651b848.glb +0 -0
- package/corpus/handwritten/blobs/glb/aae479c2f99848998a1b499bbcad815d971349c2442bc363786aef63baad4337.glb +0 -0
- package/corpus/handwritten/blobs/glb/b155bd41f260d5303e293d691b657e0fb9b9c8b2f8aa589a0187061baa033eb7.glb +0 -0
- package/corpus/handwritten/blobs/glb/b1e8b770d99e8ca4396f21fd512f632c587149fc13db69deba388f702a46982f.glb +0 -0
- package/corpus/handwritten/blobs/glb/b382c318a5baac35da59a7b99ebaad6992e30c4bac327e85851ce0b2f89aa58b.glb +0 -0
- package/corpus/handwritten/blobs/glb/ba4478198696802808262af9bbfc224fe37e24e3f8c13de91debc87d3e1a9d41.glb +0 -0
- package/corpus/handwritten/blobs/glb/baf02cd967d1bf3c6a2ae878f4ca4ed34d0c39302ca2b8b6e3560a4e87b5c16f.glb +0 -0
- package/corpus/handwritten/blobs/glb/bc14dd152815ea6ed39458dcf89f2d69173d61d6e2b57be99d31ce2da64ccf67.glb +0 -0
- package/corpus/handwritten/blobs/glb/bc4e4d3bcf7ace855183efec0fbf242d444a32714d8b2fd8a45fa7b539ef2c73.glb +0 -0
- package/corpus/handwritten/blobs/glb/bc53475e2aa2fc9c2c0574b36a449fd57259c462d771e2b360def5c338d37c26.glb +0 -0
- package/corpus/handwritten/blobs/glb/c35d9e50f392c29f2587e3a6eb4f21143ba08e48d76a53b9de62d3b5be46c1a5.glb +0 -0
- package/corpus/handwritten/blobs/glb/c6911e059d3ac6aea75bc0ad3dd8b220704bfbba8ba98b57705e7aa3ecbe0050.glb +0 -0
- package/corpus/handwritten/blobs/glb/c84d88b6ed878490bcf9fa985b5e6a7a683de8ee7808ee4151a3b6a898fbe4f2.glb +0 -0
- package/corpus/handwritten/blobs/glb/c9d5d02ef0e38ac2898d3e6ecbc2ea0a6d2bd04531118550ab54b5e83293d7ec.glb +0 -0
- package/corpus/handwritten/blobs/glb/cd9d04e361e4c3d0aeb82f8682d71114ff8318b8fc4980bccee3c5e5c16afc27.glb +0 -0
- package/corpus/handwritten/blobs/glb/d32499928422a0cd1a32b1afaeacc31d2d84d74876f6805b36218dc04402a921.glb +0 -0
- package/corpus/handwritten/blobs/glb/dc7ea629fcddeba445599d73a5d721f4d5004e056c3c140baa3e6817393c6462.glb +0 -0
- package/corpus/handwritten/blobs/glb/dce79b59c85ca5a7f9fc25e585d253b15558f8f5d8497a76923c9071601de8b1.glb +0 -0
- package/corpus/handwritten/blobs/glb/e7fa1b02bae6c8d19ace0e8db44810beab9a1be9f8172d5816324760267d6d11.glb +0 -0
- package/corpus/handwritten/blobs/glb/eb664feed0fdcc3ac73cecbe737109994fe5dfad8a33997de88598965fa936ba.glb +0 -0
- package/corpus/handwritten/blobs/glb/ec6a771ca852b0b69e55a12df9d347384d01e611c8c6151ea771910f1601605d.glb +0 -0
- package/corpus/handwritten/blobs/glb/ede05013f575b4216d2b4b3f8a14d611ef28756f952f702bb169529c8ab02eff.glb +0 -0
- package/corpus/handwritten/blobs/glb/fec21fa96950340a1a031b31b37407468361ab0a7645c683e0d7773c18591a26.glb +0 -0
- package/corpus/handwritten/blobs/glb/ff21ea082bb00b01006900e7dbbb85220f31f45c144405c840a70872f9e09cb9.glb +0 -0
- package/corpus/handwritten/blobs/image/248fe9601e921305ffb35421414bc5f03e9f1b3dba15bf9b5c3387d8f255da17.png +0 -0
- package/corpus/handwritten/blobs/image/4b47420aff1ded28c9c6cf1eb92d6e2d7b01d057f2654654405445ff8d562e55.webp +0 -0
- package/corpus/handwritten/blobs/image/5dbc818ed0be692e6ba3df87898fd623280a2686eed5a538333e1325764b238d.png +0 -0
- package/corpus/handwritten/blobs/image/d5ae692911bbc2b60b5fdde239b70aad4ce9be0d7665c4a91b438de6077e21e3.jpg +0 -0
- package/corpus/handwritten/blobs/ktx2/df0dd2e8adc1d9479148bb198cb750471df454680cf0c9ffd6dc85d6262ed676.ktx2 +0 -0
- package/corpus/handwritten/blobs/wasm/ecc886d8bbebcf190298ff9162b6bb364f2125606f5bdc8cc220ea28044f96ea.wasm +0 -0
- package/corpus/handwritten/cook.json +1 -0
- package/corpus/handwritten/mounts/shardfiles/blender-template/discovery.json +1 -0
- package/corpus/handwritten/sections/actors/creatures.json +1 -0
- package/corpus/handwritten/sections/actors/crowds.json +1 -0
- package/corpus/handwritten/sections/actors/species.json +1 -0
- package/corpus/handwritten/sections/audio/audio.json +1 -0
- package/corpus/handwritten/sections/client/plan.json +1 -0
- package/corpus/handwritten/sections/combat/encounters.json +1 -0
- package/corpus/handwritten/sections/combat/items.json +1 -0
- package/corpus/handwritten/sections/combat/strikes.json +1 -0
- package/corpus/handwritten/sections/economy/ledger.json +1 -0
- package/corpus/handwritten/sections/economy/loot.json +1 -0
- package/corpus/handwritten/sections/look/look.json +1 -0
- package/corpus/handwritten/sections/look/map.json +1 -0
- package/corpus/handwritten/sections/look/materials.json +1 -0
- package/corpus/handwritten/sections/quests/quests.json +1 -0
- package/corpus/handwritten/sections/sim/client-scripts.json +1 -0
- package/corpus/handwritten/sections/sim/hooks.json +1 -0
- package/corpus/handwritten/sections/sim/plumbing.json +1 -0
- package/corpus/handwritten/sections/sim/sim.json +1 -0
- package/corpus/handwritten/sections/state/migrations.json +1 -0
- package/corpus/handwritten/sections/state/state.json +1 -0
- package/corpus/handwritten/sections/ui/card.json +1 -0
- package/corpus/handwritten/sections/ui/compendium.json +1 -0
- package/corpus/handwritten/sections/ui/level.json +1 -0
- package/corpus/handwritten/sections/ui/ui.json +1 -0
- package/corpus/handwritten/sections/world/collision.json +1 -0
- package/corpus/handwritten/sections/world/days.json +1 -0
- package/corpus/handwritten/sections/world/edge.json +1 -0
- package/corpus/handwritten/sections/world/movers.json +1 -0
- package/corpus/handwritten/sections/world/navigation.json +1 -0
- package/corpus/handwritten/sections/world/props.json +1 -0
- package/corpus/handwritten/sections/world/spawn.json +1 -0
- package/corpus/handwritten/sections/world/terrain.json +1 -0
- package/corpus/handwritten/sections/world/tiles.json +1 -0
- package/corpus/handwritten/sections/world/traversal.json +1 -0
- package/corpus/handwritten/sections/world/water.json +1 -0
- package/corpus/handwritten/sections/world/weather.json +1 -0
- package/corpus/handwritten/shard.json +1 -0
- package/corpus/handwritten/validation.json +1 -0
- package/package.json +508 -2
- package/packages/wire/src/net-command.ts +150 -0
- package/src/cli/bin.mjs +9 -0
- package/src/cli/main.ts +148 -0
- package/src/cli/pack.ts +262 -0
- package/src/cli/validate.ts +210 -0
- package/src/cli/version.ts +13 -0
- package/src/format/aacIndex.ts +160 -0
- package/src/format/accent.ts +35 -0
- package/src/format/achievementCounters.ts +22 -0
- package/src/format/actorMoves.ts +615 -0
- package/src/format/actorProjectionV2.ts +93 -0
- package/src/format/admissionControl.ts +66 -0
- package/src/format/admissionLate.ts +22 -0
- package/src/format/admissionLimits.ts +11 -0
- package/src/format/admissionServer.ts +30 -0
- package/src/format/ambientLife.ts +123 -0
- package/src/format/arenaRoomDocument.ts +114 -0
- package/src/format/arenaScriptRows.ts +107 -0
- package/src/format/arenaView.ts +30 -0
- package/src/format/assetAdmission.ts +279 -0
- package/src/format/audio-measure.ts +184 -0
- package/src/format/audio-mp4.ts +234 -0
- package/src/format/audio-rules.ts +295 -0
- package/src/format/audio-waiver.ts +55 -0
- package/src/format/audio.ts +463 -0
- package/src/format/audioBank.ts +37 -0
- package/src/format/audioProfiles.ts +501 -0
- package/src/format/audioRouting.ts +67 -0
- package/src/format/audioScene.ts +342 -0
- package/src/format/bakedTerrainBytes.ts +35 -0
- package/src/format/bakedTerrainSampling.ts +66 -0
- package/src/format/bakedTiles.ts +407 -0
- package/src/format/binarySource.ts +32 -0
- package/src/format/bodySlots.ts +90 -0
- package/src/format/bossEncounter.ts +354 -0
- package/src/format/bossProfiles.ts +709 -0
- package/src/format/bossSocketRig.ts +92 -0
- package/src/format/bowVariantRows.ts +68 -0
- package/src/format/brains.ts +252 -0
- package/src/format/budget.ts +214 -0
- package/src/format/buildings.ts +496 -0
- package/src/format/builtIndexes.ts +26 -0
- package/src/format/catalogueEconomy.ts +65 -0
- package/src/format/caveInterior.ts +225 -0
- package/src/format/cellBounds.ts +47 -0
- package/src/format/cellField.ts +98 -0
- package/src/format/chapterDirector.ts +193 -0
- package/src/format/clientChannels.ts +450 -0
- package/src/format/clientCues.ts +34 -0
- package/src/format/clientNative.ts +358 -0
- package/src/format/clientOwnership.ts +43 -0
- package/src/format/clientPlan.ts +306 -0
- package/src/format/clientScripts.ts +116 -0
- package/src/format/clientState.ts +273 -0
- package/src/format/clientTrails.ts +56 -0
- package/src/format/collectionDisplay.ts +232 -0
- package/src/format/colourFunction.ts +44 -0
- package/src/format/colourLut.ts +4 -0
- package/src/format/commonsCosts.ts +28 -0
- package/src/format/compendiumRows.ts +151 -0
- package/src/format/compendiumSketches.ts +23 -0
- package/src/format/completion.ts +83 -0
- package/src/format/contentBounds.ts +76 -0
- package/src/format/contentCost.ts +50 -0
- package/src/format/contracts.ts +305 -0
- package/src/format/cook-data.ts +148 -0
- package/src/format/cook-preparation.ts +241 -0
- package/src/format/coverAppearance.ts +53 -0
- package/src/format/creatures.ts +175 -0
- package/src/format/crowdPresentation.ts +87 -0
- package/src/format/crowds.ts +46 -0
- package/src/format/cueDirector.ts +134 -0
- package/src/format/dayCycle.ts +28 -0
- package/src/format/dayLook.ts +44 -0
- package/src/format/decisionBindings.ts +80 -0
- package/src/format/decisionPublication.ts +35 -0
- package/src/format/decisionScripts.ts +327 -0
- package/src/format/declaredQuestPage.ts +101 -0
- package/src/format/deviceMemoryCost.ts +50 -0
- package/src/format/director.ts +52 -0
- package/src/format/directorProduct.ts +27 -0
- package/src/format/directorStages.ts +165 -0
- package/src/format/directorWhen.ts +78 -0
- package/src/format/discoveryValues.ts +416 -0
- package/src/format/easedFields.ts +48 -0
- package/src/format/edgeProfiles.ts +40 -0
- package/src/format/eliteContinuation.ts +110 -0
- package/src/format/eliteEntryRows.ts +351 -0
- package/src/format/eliteFeature.ts +605 -0
- package/src/format/eliteScripts.ts +60 -0
- package/src/format/encounterRows.ts +1030 -0
- package/src/format/encounters.ts +65 -0
- package/src/format/engine-music.ts +42 -0
- package/src/format/entryClearance.ts +86 -0
- package/src/format/entryCoverage.ts +61 -0
- package/src/format/entryGeometry.ts +56 -0
- package/src/format/entryLanding.ts +83 -0
- package/src/format/entryReads.ts +45 -0
- package/src/format/entrywayAssets.ts +33 -0
- package/src/format/entryways.ts +58 -0
- package/src/format/exchange.ts +25 -0
- package/src/format/explorerCatalogue.ts +312 -0
- package/src/format/feature-sides.ts +233 -0
- package/src/format/fieldPresentation.ts +62 -0
- package/src/format/figures.ts +437 -0
- package/src/format/findsCatalogue.ts +67 -0
- package/src/format/fixedDraws.ts +24 -0
- package/src/format/flyers.ts +226 -0
- package/src/format/forestNativeInputs.ts +37 -0
- package/src/format/forestPage.ts +285 -0
- package/src/format/forestWeather.ts +333 -0
- package/src/format/geometryPack.ts +136 -0
- package/src/format/glbBuffers.ts +77 -0
- package/src/format/glbCost.ts +212 -0
- package/src/format/glbImages.ts +95 -0
- package/src/format/glbTriangles.ts +95 -0
- package/src/format/graphArmsRows.ts +200 -0
- package/src/format/grapple.ts +123 -0
- package/src/format/grazers.ts +164 -0
- package/src/format/grid-catalogue.ts +247 -0
- package/src/format/gridReadiness.ts +49 -0
- package/src/format/groupBrains.ts +249 -0
- package/src/format/heldArms.ts +576 -0
- package/src/format/heldEquipment.ts +78 -0
- package/src/format/heldFinishes.ts +415 -0
- package/src/format/heldGear.ts +68 -0
- package/src/format/heldJianDocument.ts +75 -0
- package/src/format/heldMelee.ts +866 -0
- package/src/format/heldView.ts +26 -0
- package/src/format/heldWeaponDocuments.ts +36 -0
- package/src/format/herdShelter.ts +58 -0
- package/src/format/hooks.ts +45 -0
- package/src/format/immutable.ts +59 -0
- package/src/format/inputDeclarations.ts +157 -0
- package/src/format/islandLibrary.ts +51 -0
- package/src/format/issue-codes.ts +262 -0
- package/src/format/items.ts +229 -0
- package/src/format/json.ts +143 -0
- package/src/format/keyedSky.ts +314 -0
- package/src/format/kitFigure.ts +68 -0
- package/src/format/ktx2Cost.ts +47 -0
- package/src/format/ledger.ts +56 -0
- package/src/format/liftApproach.ts +75 -0
- package/src/format/liftRider.ts +10 -0
- package/src/format/lightEmitters.ts +105 -0
- package/src/format/lights.ts +135 -0
- package/src/format/limbCollision.ts +136 -0
- package/src/format/limbPopulation.ts +33 -0
- package/src/format/limbRig.ts +202 -0
- package/src/format/loadout.ts +156 -0
- package/src/format/look-light.ts +153 -0
- package/src/format/lootBag.ts +145 -0
- package/src/format/lootEconomy.ts +235 -0
- package/src/format/materialFamilies.ts +565 -0
- package/src/format/materialGraph.ts +1220 -0
- package/src/format/materials.ts +449 -0
- package/src/format/memoryAdmission.ts +84 -0
- package/src/format/memoryGates.json +7 -0
- package/src/format/meshCollision.ts +56 -0
- package/src/format/meshCollisionAssets.ts +19 -0
- package/src/format/meshCollisionBytes.ts +102 -0
- package/src/format/meshEntryways.ts +54 -0
- package/src/format/meshopt-decoder.wasm +0 -0
- package/src/format/meshopt-module.ts +177 -0
- package/src/format/meshopt-static.mjs +11 -0
- package/src/format/meshopt-wasm.ts +61 -0
- package/src/format/migrations.ts +209 -0
- package/src/format/minimap.ts +1052 -0
- package/src/format/mixedPopulation.ts +222 -0
- package/src/format/modes.ts +304 -0
- package/src/format/mountedSpecimenRows.ts +64 -0
- package/src/format/moverLifecycle.ts +34 -0
- package/src/format/moverMotion.ts +271 -0
- package/src/format/movers.ts +224 -0
- package/src/format/namedJsonContracts.ts +423 -0
- package/src/format/nativeActors.ts +45 -0
- package/src/format/nativeAssembly.ts +141 -0
- package/src/format/nativeGround.ts +37 -0
- package/src/format/nativeGroundAssets.ts +35 -0
- package/src/format/nativeItems.ts +184 -0
- package/src/format/nativePhysics.ts +140 -0
- package/src/format/nativeQuestComposition.ts +398 -0
- package/src/format/nativeRiding.ts +103 -0
- package/src/format/nativeRuntimePlan.ts +89 -0
- package/src/format/navigation.ts +99 -0
- package/src/format/navigationBytes.ts +111 -0
- package/src/format/nearPlaceholder.ts +111 -0
- package/src/format/nearPlaceholderAssets.ts +23 -0
- package/src/format/netCommand.ts +11 -0
- package/src/format/npcs.ts +546 -0
- package/src/format/outputAddress.ts +11 -0
- package/src/format/outputDownload.ts +34 -0
- package/src/format/outputFields.ts +123 -0
- package/src/format/outputIndex.ts +352 -0
- package/src/format/overdraw.ts +41 -0
- package/src/format/pageLife.ts +303 -0
- package/src/format/pagePreparation.ts +60 -0
- package/src/format/paintedLook.ts +55 -0
- package/src/format/paintedResources.ts +158 -0
- package/src/format/panelTemplate.ts +139 -0
- package/src/format/placeholderSource.ts +209 -0
- package/src/format/platformDataSections.ts +146 -0
- package/src/format/platformFileFamilies.ts +299 -0
- package/src/format/plumbing.ts +165 -0
- package/src/format/populationEnvironment.ts +210 -0
- package/src/format/populationKeeper.ts +163 -0
- package/src/format/populationProjection.ts +496 -0
- package/src/format/populationRespawn.ts +48 -0
- package/src/format/populationRoster.ts +158 -0
- package/src/format/portalFloor.ts +56 -0
- package/src/format/portalLink.ts +112 -0
- package/src/format/portalLinkAssets.ts +42 -0
- package/src/format/portalRide.ts +22 -0
- package/src/format/postGraphDocument.ts +36 -0
- package/src/format/postGraphLook.ts +477 -0
- package/src/format/postStack.ts +114 -0
- package/src/format/practiceCourseRows.ts +466 -0
- package/src/format/preflight.ts +155 -0
- package/src/format/presentation.ts +33 -0
- package/src/format/product-audio.ts +76 -0
- package/src/format/product-reads.ts +178 -0
- package/src/format/product-stream-admit.ts +114 -0
- package/src/format/product-stream-assets.ts +511 -0
- package/src/format/product-stream-facts.ts +208 -0
- package/src/format/product-stream-miss.ts +15 -0
- package/src/format/product-stream-node.ts +47 -0
- package/src/format/product-stream-packs.ts +247 -0
- package/src/format/product-stream-rows.ts +234 -0
- package/src/format/product-stream-tar.ts +204 -0
- package/src/format/product-stream.ts +297 -0
- package/src/format/product.ts +366 -0
- package/src/format/productValidation.ts +236 -0
- package/src/format/propMaterials.ts +254 -0
- package/src/format/props.ts +137 -0
- package/src/format/questContinuation.ts +42 -0
- package/src/format/questFigures.ts +227 -0
- package/src/format/questGraph.ts +30 -0
- package/src/format/questHost.ts +314 -0
- package/src/format/questInteractionSource.ts +57 -0
- package/src/format/questInteractions.ts +642 -0
- package/src/format/questPageComposition.ts +92 -0
- package/src/format/questPageFacets.ts +121 -0
- package/src/format/questRuntime.ts +118 -0
- package/src/format/questSteps.ts +182 -0
- package/src/format/questStory.ts +512 -0
- package/src/format/questStoryBindings.ts +43 -0
- package/src/format/questWorld.ts +36 -0
- package/src/format/quests.ts +333 -0
- package/src/format/rainPresentation.ts +131 -0
- package/src/format/rangedPage.ts +117 -0
- package/src/format/receipt-cost.ts +71 -0
- package/src/format/registeredJson.ts +530 -0
- package/src/format/returnProgramDocument.ts +40 -0
- package/src/format/returnProjectionV2.ts +84 -0
- package/src/format/riding.ts +377 -0
- package/src/format/riggedHulls.ts +160 -0
- package/src/format/roamingBossProjection.ts +178 -0
- package/src/format/roamingCombat.ts +22 -0
- package/src/format/ropeDeckSite.ts +148 -0
- package/src/format/rows.ts +86 -0
- package/src/format/runtime.ts +38 -0
- package/src/format/runtimeBinds.ts +49 -0
- package/src/format/runtimeCost.ts +80 -0
- package/src/format/runtimeSpawns.ts +73 -0
- package/src/format/scalarChannel.ts +38 -0
- package/src/format/scaledPost.ts +27 -0
- package/src/format/scaledPostContract.ts +51 -0
- package/src/format/sceneBuffers.ts +122 -0
- package/src/format/sceneDraws.ts +89 -0
- package/src/format/sceneDressing.ts +247 -0
- package/src/format/sceneInstances.ts +192 -0
- package/src/format/sceneMotion.ts +122 -0
- package/src/format/sceneRefs.ts +71 -0
- package/src/format/sceneSources.ts +730 -0
- package/src/format/script-side-grandfather.ts +62 -0
- package/src/format/script-sides.ts +289 -0
- package/src/format/scriptAbi.ts +14 -0
- package/src/format/scriptAbiV1.ts +56 -0
- package/src/format/scriptActionsV2.ts +101 -0
- package/src/format/scriptAdmission.ts +165 -0
- package/src/format/scriptAdmissionV2.ts +126 -0
- package/src/format/scriptContract.ts +170 -0
- package/src/format/scriptFuelV2.ts +124 -0
- package/src/format/scriptGroupBankV2.ts +54 -0
- package/src/format/scriptGroupStepV2.ts +165 -0
- package/src/format/scriptInputStateV2.ts +52 -0
- package/src/format/scriptLimits.ts +5 -0
- package/src/format/scriptMemoryV2.ts +17 -0
- package/src/format/scriptModuleV2.ts +116 -0
- package/src/format/scriptObservationColumnsV2.ts +226 -0
- package/src/format/scriptQueriesV2.ts +164 -0
- package/src/format/scriptQueryStateV2.ts +40 -0
- package/src/format/scriptRngV2.ts +52 -0
- package/src/format/scriptWireV2.ts +106 -0
- package/src/format/scripts.ts +31 -0
- package/src/format/sections.ts +140 -0
- package/src/format/shardSchema.ts +632 -0
- package/src/format/shardSections.ts +383 -0
- package/src/format/sketch.ts +79 -0
- package/src/format/skin-materials.ts +172 -0
- package/src/format/skinAssets.ts +107 -0
- package/src/format/skinData.ts +110 -0
- package/src/format/skinLayers.ts +90 -0
- package/src/format/skins.ts +37 -0
- package/src/format/socketLift.ts +58 -0
- package/src/format/socketLiftAssets.ts +81 -0
- package/src/format/socketRigCreature.ts +66 -0
- package/src/format/sourceResidency.ts +16 -0
- package/src/format/spawnCombat.ts +26 -0
- package/src/format/spawnScriptV2.ts +145 -0
- package/src/format/spawnScripts.ts +229 -0
- package/src/format/spawnTables.ts +46 -0
- package/src/format/spawnView.ts +26 -0
- package/src/format/speciesActorsFile.ts +86 -0
- package/src/format/speciesBookRows.ts +84 -0
- package/src/format/speciesBrain.ts +96 -0
- package/src/format/speciesLooks.ts +1021 -0
- package/src/format/speciesPrograms.ts +97 -0
- package/src/format/speciesScripts.ts +45 -0
- package/src/format/specimenCatalogue.ts +94 -0
- package/src/format/splatTerrain.ts +192 -0
- package/src/format/standalone-catalogue.ts +144 -0
- package/src/format/standaloneControl.ts +44 -0
- package/src/format/state.ts +61 -0
- package/src/format/stateLineage.ts +71 -0
- package/src/format/stealth.ts +106 -0
- package/src/format/stillImage.ts +135 -0
- package/src/format/streamedCover.ts +105 -0
- package/src/format/surfaceLooks.ts +50 -0
- package/src/format/tar-fields.ts +54 -0
- package/src/format/tar-paths.ts +104 -0
- package/src/format/tar-source.ts +13 -0
- package/src/format/tar-write.ts +152 -0
- package/src/format/tar.ts +204 -0
- package/src/format/targets.ts +217 -0
- package/src/format/terrain.ts +241 -0
- package/src/format/terrainTileBytes.ts +104 -0
- package/src/format/tierSelection.ts +195 -0
- package/src/format/toonLighting.ts +32 -0
- package/src/format/toonLook.ts +332 -0
- package/src/format/trail.ts +17 -0
- package/src/format/traversal.ts +13 -0
- package/src/format/treeSetRows.ts +93 -0
- package/src/format/ui.ts +90 -0
- package/src/format/uiStrings.ts +17 -0
- package/src/format/uniformRows.ts +31 -0
- package/src/format/upload-wire.ts +184 -0
- package/src/format/validationReceipt.ts +142 -0
- package/src/format/version.ts +9 -0
- package/src/format/vertexWear.ts +45 -0
- package/src/format/viewProgram.ts +329 -0
- package/src/format/voicePatches.ts +47 -0
- package/src/format/water.ts +247 -0
- package/src/format/waterWaves.ts +7 -0
- package/src/format/waterWorld.ts +34 -0
- package/src/format/weaponProfiles.ts +1315 -0
- package/src/format/weatherBundle.ts +36 -0
- package/src/format/weatherEffects.ts +78 -0
- package/src/format/weatherProgram.ts +422 -0
- package/src/format/wildlifePopulation.ts +210 -0
- package/src/format/wireLimits.ts +9 -0
- package/src/format/worldAssembly.ts +104 -0
- package/src/format/worldEntry.ts +151 -0
- package/src/format/worldPhysics.ts +292 -0
- package/src/format/worldSceneBatch.ts +106 -0
- package/src/format/worldSceneModels.ts +79 -0
- package/src/format/worldScenePages.ts +89 -0
- package/src/format/worldScenePlacement.ts +191 -0
- package/src/format/worldSceneSlabs.ts +43 -0
- package/src/format/worldSceneSurface.ts +113 -0
- package/src/format/worldSceneWeld.ts +702 -0
- package/src/format/worldScenes.ts +184 -0
- package/src/format/worldTargets.ts +111 -0
- package/src/format/worldUpdates.ts +229 -0
- package/src/hook/format-hook.d.mts +2 -0
- package/src/hook/format-hook.mjs +47 -0
- package/src/tools/runtime-hosts.json +497 -0
- package/README.md +0 -8
|
@@ -0,0 +1,366 @@
|
|
|
1
|
+
import { admitScriptContract, type ScriptContract } from './scriptContract.ts';
|
|
2
|
+
import { prepareGlbBuffers } from './glbBuffers.ts';
|
|
3
|
+
import { parseGlbData } from './glbCost.ts';
|
|
4
|
+
import { parseKtx2 } from './ktx2Cost.ts';
|
|
5
|
+
import { indexRecordingAac } from './aacIndex.ts';
|
|
6
|
+
import { bilinearTerrainSamplers, decodeTerrainTile, isTerrainTileData, terrainTileCost, terrainTileHeight } from "./terrainTileBytes.ts";
|
|
7
|
+
import { decodeMeshCollision, isMeshCollisionData, meshCollisionCost } from "./meshCollisionBytes.ts";
|
|
8
|
+
import type { GlbVertex } from "./glbTriangles.ts";
|
|
9
|
+
import type { OverdrawEstimate } from "./overdraw.ts";
|
|
10
|
+
import { parseImageAsset } from "./stillImage.ts";
|
|
11
|
+
import { journalImageRefs } from './compendiumRows.ts';
|
|
12
|
+
import type { Shardfile } from "./shardSchema.ts";
|
|
13
|
+
import type { ShardTerrain } from "./terrain.ts";
|
|
14
|
+
import { worstContentCost, memoryTargetWarnings, nearbyContentCost } from "./budget.ts";
|
|
15
|
+
import { CONTENT_CAPS as C, MEMORY_GATES } from './contentBounds.ts';
|
|
16
|
+
import { DEFAULT_GRAPH_BUDGET } from "./materialGraph.ts";
|
|
17
|
+
import { SCRIPT_LIMITS } from './scriptLimits.ts';
|
|
18
|
+
import { runtimeAccountedBytes } from "./runtimeCost.ts";
|
|
19
|
+
import { MemoryAdmission } from './memoryAdmission.ts';
|
|
20
|
+
import { nearPlaceholderRoots } from './nearPlaceholder.ts';
|
|
21
|
+
import type { IssueCodeOf } from './issue-codes.ts';
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
/** Actual costs derived from a bounded parser, never trusted from the author declaration. */
|
|
25
|
+
import { isNavigationData, navigationCost } from './navigationBytes.ts';
|
|
26
|
+
|
|
27
|
+
/** A performance issue's code and its metric words. */
|
|
28
|
+
type Named = readonly [code: IssueCodeOf<'performance'>, metric: string];
|
|
29
|
+
|
|
30
|
+
/** Admitted decoded CPU bytes, GPU bytes, triangle count and draw count charged to the asset budget. */
|
|
31
|
+
export interface AssetCost { decoded: number; gpu: number; triangles: number; draws: number }
|
|
32
|
+
const MAX_BYTES = 25_000_000;
|
|
33
|
+
function requireRange(bytes: Uint8Array, offset: number, size: number): void {
|
|
34
|
+
if (!Number.isSafeInteger(offset) || !Number.isSafeInteger(size) || offset < 0 || size < 0 || offset + size > bytes.length) throw new Error('asset truncated or oversized');
|
|
35
|
+
}
|
|
36
|
+
function json(bytes: Uint8Array): unknown { return JSON.parse(new TextDecoder('utf-8', { fatal: true }).decode(bytes)); }
|
|
37
|
+
|
|
38
|
+
/** Parse self-contained GLB 2 without following URLs or allocating accessor-sized arrays. */
|
|
39
|
+
export function parseGlb(bytes: Uint8Array): AssetCost { return parseGlbData(bytes); }
|
|
40
|
+
/** Prepare compressed-asset decoding before synchronous byte admission; importing schemas never waits for Wasm. */
|
|
41
|
+
export function prepareAssetDecoders(): Promise<void> { return prepareGlbBuffers(); }
|
|
42
|
+
/** Inspect exact static triangles only after the bounded GLB parser admits the complete payload. */
|
|
43
|
+
export function visitGlbTriangles(bytes: Uint8Array, visit: (triangle: readonly GlbVertex[]) => void): void { parseGlbData(bytes, visit); }
|
|
44
|
+
/** Shared byte-derived raster estimate; no author-supplied overdraw number is accepted. */
|
|
45
|
+
export function assetOverdraw(requestedKind: string, bytes: Uint8Array, script?: ScriptContract): OverdrawEstimate {
|
|
46
|
+
const kind = requestedKind === 'commons' ? commonsKind(bytes) : requestedKind;
|
|
47
|
+
const estimate: OverdrawEstimate = { layers: 0, blendedLayers: 0, maskedLayers: 0, basis: 'primitive-bounds' };
|
|
48
|
+
if (kind === 'glb') parseGlbData(bytes, undefined, estimate);
|
|
49
|
+
else { assetCost(kind, bytes, script); if (isTerrainTileData(bytes)) estimate.layers = 1; }
|
|
50
|
+
return estimate;
|
|
51
|
+
}
|
|
52
|
+
/** Admit bounded PCM WAV or indexed AAC-LC without decoding; charge full float32 sample residency. */
|
|
53
|
+
export function parseAudio(bytes: Uint8Array): AssetCost {
|
|
54
|
+
requireRange(bytes, 0, 12);
|
|
55
|
+
if (new TextDecoder().decode(bytes.subarray(4, 8)) === 'ftyp') {
|
|
56
|
+
if (bytes.length > MAX_BYTES) throw new Error('audio byte cap');
|
|
57
|
+
const indexed = indexRecordingAac(bytes);
|
|
58
|
+
if (indexed.mediaFrames / indexed.sampleRate > 180) throw new Error('AAC duration cap');
|
|
59
|
+
// Include priming and the entire final packet: never undercharge packet padding or encoder delay.
|
|
60
|
+
return { decoded: indexed.sizes.length * 1024 * indexed.channels * 4, gpu: 0, triangles: 0, draws: 0 };
|
|
61
|
+
}
|
|
62
|
+
requireRange(bytes, 0, 12); const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength), tag = (at: number): string => new TextDecoder().decode(bytes.subarray(at, at + 4));
|
|
63
|
+
if (bytes.length > MAX_BYTES || tag(0) !== 'RIFF' || tag(8) !== 'WAVE' || view.getUint32(4, true) + 8 !== bytes.length) throw new Error('invalid WAV header');
|
|
64
|
+
let at = 12, channels = 0, rate = 0, alignment = 0, data = 0;
|
|
65
|
+
while (at < bytes.length) {
|
|
66
|
+
requireRange(bytes, at, 8); const n = view.getUint32(at + 4, true); requireRange(bytes, at + 8, n);
|
|
67
|
+
if (tag(at) === 'fmt ') {
|
|
68
|
+
if (channels !== 0 || n < 16 || view.getUint16(at + 8, true) !== 1) throw new Error('unsupported WAV format');
|
|
69
|
+
channels = view.getUint16(at + 10, true); rate = view.getUint32(at + 12, true); alignment = view.getUint16(at + 20, true); const bits = view.getUint16(at + 22, true);
|
|
70
|
+
if (channels < 1 || channels > 2 || rate < 8000 || rate > 96000 || ![8, 16, 24, 32].includes(bits) || alignment !== channels * bits / 8 || view.getUint32(at + 16, true) !== rate * alignment) throw new Error('WAV channel/rate cap');
|
|
71
|
+
} else if (tag(at) === 'data') { if (data !== 0) throw new Error('duplicate WAV data'); data = n; }
|
|
72
|
+
at += 8 + n + (n % 2);
|
|
73
|
+
}
|
|
74
|
+
if (channels === 0 || data === 0 || data % alignment !== 0 || data / alignment / rate > 180 || at !== bytes.length) throw new Error('WAV duration or data cap');
|
|
75
|
+
return { decoded: data / alignment * channels * 4, gpu: 0, triangles: 0, draws: 0 };
|
|
76
|
+
}
|
|
77
|
+
function commonsKind(bytes: Uint8Array): 'ktx2' | 'glb' | 'audio' | 'binary' {
|
|
78
|
+
return bytes[0] === 171 ? 'ktx2' : bytes[0] === 103 ? 'glb'
|
|
79
|
+
: bytes[0] === 82 || new TextDecoder().decode(bytes.subarray(4, 8)) === 'ftyp' ? 'audio' : 'binary';
|
|
80
|
+
}
|
|
81
|
+
/** Select the format parser; binary/JSON/Wasm are bounded before higher-level content validators run. */
|
|
82
|
+
export function assetCost(requestedKind: string, bytes: Uint8Array, script?: ScriptContract): AssetCost {
|
|
83
|
+
const kind = requestedKind === 'commons' ? commonsKind(bytes) : requestedKind;
|
|
84
|
+
if (kind === 'image') { const image = parseImageAsset(bytes); return { decoded: image.decoded, gpu: image.gpu, triangles: 0, draws: 0 }; }
|
|
85
|
+
if (kind === 'glb') return parseGlb(bytes);
|
|
86
|
+
if (kind === 'ktx2') return parseKtx2(bytes);
|
|
87
|
+
if (kind === 'audio') return parseAudio(bytes);
|
|
88
|
+
if (bytes.length > MAX_BYTES) throw new Error('asset byte cap');
|
|
89
|
+
if (kind === 'binary' && isNavigationData(bytes)) return navigationCost(bytes);
|
|
90
|
+
if (kind === 'binary' && isTerrainTileData(bytes)) return terrainTileCost(decodeTerrainTile(bytes));
|
|
91
|
+
if (kind === 'binary' && isMeshCollisionData(bytes)) return meshCollisionCost(decodeMeshCollision(bytes));
|
|
92
|
+
if (kind === 'json') { json(bytes); return { decoded: bytes.length, gpu: 0, triangles: 0, draws: 0 }; }
|
|
93
|
+
if (kind === 'wasm') {
|
|
94
|
+
if (script === undefined) throw new Error('Wasm needs an explicit script contract');
|
|
95
|
+
admitScriptContract(bytes, script);
|
|
96
|
+
}
|
|
97
|
+
return { decoded: bytes.length, gpu: 0, triangles: 0, draws: 0 };
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/** Refuse orphan wire assets and require look LUTs in the charged library closure before any asset read. */
|
|
101
|
+
export function preflightAssetGraph(source: Pick<Shardfile, 'files' | 'library' | 'critical' | 'tiles' | 'far' | 'look' | 'requires'> & Partial<Pick<Shardfile, 'rows' | 'presentation' | 'map' | 'audio' | 'near'>>): void {
|
|
102
|
+
const files = new Map(source.files.map((file) => [file.hash, file]));
|
|
103
|
+
const closure = (roots: readonly string[]): Set<string> => {
|
|
104
|
+
const found = new Set<string>(), pending = [...roots];
|
|
105
|
+
while (pending.length > 0) {
|
|
106
|
+
const ref = pending.pop(); if (ref === undefined || found.has(ref)) continue;
|
|
107
|
+
found.add(ref); for (const dependency of files.get(ref)?.dependencies ?? []) pending.push(dependency);
|
|
108
|
+
}
|
|
109
|
+
return found;
|
|
110
|
+
};
|
|
111
|
+
const library = closure(source.library), lut = source.look.grade.lut;
|
|
112
|
+
if (lut !== null && !library.has(lut)) throw new Error('Look LUT must be in the charged library closure');
|
|
113
|
+
if (source.map !== undefined && (!library.has(source.map.image) || files.get(source.map.image)?.kind !== 'image')) throw new Error('Map image must be a declared image file in the charged library closure');
|
|
114
|
+
for (const ref of Object.values(source.presentation?.card ?? {})) {
|
|
115
|
+
if (!library.has(ref) || files.get(ref)?.kind !== 'image') throw new Error('Presentation images must be declared image files in the charged library closure');
|
|
116
|
+
}
|
|
117
|
+
for (const ref of Object.values(source.audio?.recordings ?? {})) {
|
|
118
|
+
const shared = ref.startsWith('commons:') && source.requires.commons.includes(ref.slice(8));
|
|
119
|
+
if (!library.has(ref) || (!shared && files.get(ref)?.kind !== 'audio')) throw new Error('Audio recordings must be declared audio in the charged library closure');
|
|
120
|
+
}
|
|
121
|
+
for (const row of source.rows?.compendiums ?? []) {
|
|
122
|
+
if ('kind' in row) {
|
|
123
|
+
for (const ref of journalImageRefs(row)) if (!library.has(ref) || files.get(ref)?.kind !== 'image') throw new Error('Journal image must be a declared image in the charged library closure');
|
|
124
|
+
} else for (const entry of row.entries) {
|
|
125
|
+
if (!entry.sketch.startsWith('data:') && !library.has(entry.sketch)) throw new Error('Compendium sketch hash must be in the charged library closure');
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
const reachable = closure([...source.library, ...source.critical, ...source.tiles.flatMap((tile) => tile.files), ...source.far?.files ?? [], ...nearPlaceholderRoots(source.near)]);
|
|
129
|
+
if (source.files.some((file) => !reachable.has(file.hash)) || source.requires.commons.some((hash) => !reachable.has(`commons:${hash}`))) throw new Error('Orphan shardfile asset is not reachable from a bundle root');
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/** Check baked payloads against the public tile rows and edge profiles, including exact render/collider L0 seams. */
|
|
133
|
+
export function validateTerrainAssets(terrain: ShardTerrain, assets: ReadonlyMap<string, Uint8Array>, content: {
|
|
134
|
+
tiles: readonly { lod: number; x: number; z: number; files: readonly string[]; geometricError: number }[];
|
|
135
|
+
critical: readonly string[]; edge: Record<'north' | 'east' | 'south' | 'west', { heights: readonly number[]; colours: readonly (readonly number[])[] }>;
|
|
136
|
+
}): void {
|
|
137
|
+
const read = (fileRef: string) => { const bytes = assets.get(fileRef); if (bytes === undefined) throw new Error('Missing terrain file'); return decodeTerrainTile(bytes); };
|
|
138
|
+
const collider = read(terrain.collider);
|
|
139
|
+
const derivedQuery = terrain.form === 'query' && terrain.collider === terrain.sampling.file;
|
|
140
|
+
if (!derivedQuery && (!content.critical.includes(terrain.collider) || collider.colours !== undefined || collider.splat !== undefined || collider.x !== -250 || collider.z !== -250 || collider.size !== 500 || collider.resolution !== 257)) throw new Error('Terrain collider must be a complete critical heightfield');
|
|
141
|
+
if (terrain.sampling !== undefined) {
|
|
142
|
+
if (!content.critical.includes(terrain.sampling.file)) throw new Error('Terrain sampling must be a critical query root');
|
|
143
|
+
bilinearTerrainSamplers(read(terrain.sampling.file), terrain.sampling.normalEpsilon, terrain.sampling.datum);
|
|
144
|
+
}
|
|
145
|
+
if (terrain.form === 'query') return; // Queries install no render seams, road colours or collision.
|
|
146
|
+
const colours = new Map<string, readonly number[]>();
|
|
147
|
+
for (const tile of terrain.tiles) {
|
|
148
|
+
const data = read(tile.file), size = tile.lod === 0 ? 62.5 : 125, row = content.tiles.find((t) => t.lod === tile.lod && t.x === tile.x && t.z === tile.z);
|
|
149
|
+
if (data.colours === undefined || data.size !== size || data.x !== -250 + tile.x * size || data.z !== -250 + tile.z * size || data.resolution !== (tile.lod === 0 ? 33 : 17) || row === undefined || !row.files.includes(tile.file)) throw new Error('Terrain tile payload disagrees with its address');
|
|
150
|
+
for (let z = 0; z < data.resolution; z++) for (let x = 0; x < data.resolution; x++) {
|
|
151
|
+
const height = terrainTileHeight(collider, data.x + x * size / (data.resolution - 1), data.z + z * size / (data.resolution - 1));
|
|
152
|
+
if (Math.abs((data.heights[z * data.resolution + x] ?? Infinity) - height) > 1e-5) throw new Error('Terrain render/collider seam mismatch');
|
|
153
|
+
if (tile.lod === 0) {
|
|
154
|
+
const key = `${tile.x * 32 + x}/${tile.z * 32 + z}`, rgb = [...data.colours.subarray((z * data.resolution + x) * 3, (z * data.resolution + x) * 3 + 3)], prior = colours.get(key);
|
|
155
|
+
if (prior !== undefined && rgb.some((c, i) => c !== prior[i])) throw new Error('Terrain colour seam mismatch');
|
|
156
|
+
colours.set(key, rgb);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
let error = 0;
|
|
160
|
+
for (let z = 0; z <= size / (500 / 256); z++) for (let x = 0; x <= size / (500 / 256); x++) {
|
|
161
|
+
const px = data.x + x * 500 / 256, pz = data.z + z * 500 / 256;
|
|
162
|
+
error = Math.max(error, Math.abs(terrainTileHeight(data, px, pz) - terrainTileHeight(collider, px, pz)));
|
|
163
|
+
}
|
|
164
|
+
if (row.geometricError + 1e-5 < error) throw new Error('Terrain geometric error understated');
|
|
165
|
+
}
|
|
166
|
+
for (const [side, edge] of Object.entries(content.edge)) {
|
|
167
|
+
if (edge.heights.length !== 257 || edge.colours.length !== 257) throw new Error('Terrain edge profile sample count');
|
|
168
|
+
edge.heights.forEach((height, i) => {
|
|
169
|
+
const p = -250 + i * 500 / 256, x = side === 'east' ? 250 : side === 'west' ? -250 : p, z = side === 'north' ? 250 : side === 'south' ? -250 : p;
|
|
170
|
+
if (Math.abs(height - terrainTileHeight(collider, x, z)) > 1e-5) throw new Error('Terrain edge profile mismatch');
|
|
171
|
+
const key = `${Math.round((x + 250) / 500 * 256)}/${Math.round((z + 250) / 500 * 256)}`, rgb = colours.get(key), declared = edge.colours[i];
|
|
172
|
+
if (rgb === undefined || declared?.length !== 3 || rgb.some((c, channel) => c !== declared[channel])) throw new Error('Terrain edge colour mismatch');
|
|
173
|
+
});
|
|
174
|
+
if (edge.heights[128] !== 0) throw new Error('Terrain entry road must meet road height zero');
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/** Native offline observations; script execution is timed separately from physics and checkpoint/IPC work. */
|
|
179
|
+
export interface PerformanceObservations {
|
|
180
|
+
scripts: { p95Micros: number; maxMicros: number; samples: number };
|
|
181
|
+
fuel: { p95: number; max: number; samples: number };
|
|
182
|
+
}
|
|
183
|
+
/** A report issue distinguishes tradeable memory targets from enforceable complete totals and execution budgets. */
|
|
184
|
+
export interface PerformanceIssue {
|
|
185
|
+
/** SHARD-AUTHORING SA41: the stable code (issue-codes.ts, docs/VALIDATION-CODES.md); `metric` keeps its words. */
|
|
186
|
+
code: IssueCodeOf<'performance'>; metric: string; actual: number; limit: number; severity: 'warning' | 'refusal';
|
|
187
|
+
}
|
|
188
|
+
/** Build-time estimates retain units, their scope, and the measured execution samples they use. */
|
|
189
|
+
export interface PerformanceReport {
|
|
190
|
+
slug: string; policy: 'refuse' | 'warn'; pass: boolean;
|
|
191
|
+
native: { resident: number; evidence: string | null; unmeasuredViewAndDownload: boolean };
|
|
192
|
+
memory: { near: ReturnType<typeof nearbyContentCost>; worst: ReturnType<typeof worstContentCost>; playingLimit: number; loadingLimit: number };
|
|
193
|
+
views: { name: string; x: number; z: number; draws: number; triangles: number }[];
|
|
194
|
+
graphs: { id: string; nodes: number; samplers: number; instructions: number }[];
|
|
195
|
+
scripts: PerformanceObservations;
|
|
196
|
+
download: { critical: number; tiles: number; library: number; far: number; near?: number; total: number; playable: number };
|
|
197
|
+
estimatedPlayable: { seconds: number; bytesPerSecond: number; setupSeconds: number };
|
|
198
|
+
issues: PerformanceIssue[];
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
function reportCardClosure(source: Shardfile, roots: readonly string[]): Set<string> {
|
|
202
|
+
const files = new Map(source.files.map(file => [file.hash, file])), found = new Set<string>(), pending = [...roots];
|
|
203
|
+
while (pending.length > 0) {
|
|
204
|
+
const ref = pending.pop(); if (ref === undefined || found.has(ref)) continue;
|
|
205
|
+
found.add(ref); pending.push(...files.get(ref)?.dependencies ?? []);
|
|
206
|
+
}
|
|
207
|
+
return found;
|
|
208
|
+
}
|
|
209
|
+
function totals(source: Shardfile, refs: Iterable<string>): { bytes: number; draws: number; triangles: number } {
|
|
210
|
+
const files = new Map(source.files.map(file => [file.hash, file]));
|
|
211
|
+
let bytes = 0, draws = 0, triangles = 0;
|
|
212
|
+
for (const ref of refs) {
|
|
213
|
+
const shared = ref.startsWith('commons:') ? ref.slice(8) : null;
|
|
214
|
+
const file = files.get(ref), row = shared === null ? file : source.requires.commonsCosts[shared];
|
|
215
|
+
if (row === undefined) throw new Error(`Report requires admitted cost for ${ref}`);
|
|
216
|
+
const wire = shared === null ? file?.compressed : source.requires.commonsWire[shared];
|
|
217
|
+
if (wire === undefined) throw new Error(`Report requires admitted wire size for ${ref}`);
|
|
218
|
+
bytes += wire; draws += row.draws; triangles += row.triangles;
|
|
219
|
+
}
|
|
220
|
+
return { bytes, draws, triangles };
|
|
221
|
+
}
|
|
222
|
+
const near = (tile: Shardfile['tiles'][number], x: number, z: number): boolean => {
|
|
223
|
+
const dx = Math.max((tile.drawBounds ?? tile.bounds).min[0] - x, x - (tile.drawBounds ?? tile.bounds).max[0], 0), dz = Math.max((tile.drawBounds ?? tile.bounds).min[2] - z, z - (tile.drawBounds ?? tile.bounds).max[2], 0);
|
|
224
|
+
return dx * dx + dz * dz <= C.nearRadius ** 2;
|
|
225
|
+
};
|
|
226
|
+
|
|
227
|
+
/** Cheap target grading before asset reads; format integrity and total-memory admission remain separate. */
|
|
228
|
+
export function performanceTargetIssues(source: Shardfile, policy: 'refuse' | 'warn' = 'refuse'): PerformanceIssue[] {
|
|
229
|
+
const issues: PerformanceIssue[] = [];
|
|
230
|
+
const check = ([code, metric]: Named, actual: number, limit: number, provisional = false): void => {
|
|
231
|
+
if (actual > limit) issues.push({ code, metric, actual, limit, severity: provisional || policy === 'warn' ? 'warning' : 'refusal' });
|
|
232
|
+
};
|
|
233
|
+
const libraryAllowance = source.budgets.library.downloadAllowance ?? C.library.compressed;
|
|
234
|
+
check(['perf-library-download-budget', 'library download budget bytes'], source.budgets.library.compressed, libraryAllowance);
|
|
235
|
+
check(['perf-critical-download-budget', 'critical download budget bytes'], source.budgets.sim.compressed, C.sim.compressed);
|
|
236
|
+
check(['perf-library-download', 'library download bytes'], totals(source, reportCardClosure(source, source.library)).bytes, libraryAllowance);
|
|
237
|
+
check(['perf-critical-download', 'critical download bytes'], totals(source, reportCardClosure(source, source.critical)).bytes, C.sim.compressed);
|
|
238
|
+
for (const tile of source.tiles) {
|
|
239
|
+
const cap = tile.lod === 0 ? C.l0 : C.l1, id = `tile ${tile.lod}/${tile.x}/${tile.z}`;
|
|
240
|
+
check(['perf-tile-download', `${id} download bytes`], tile.compressed, cap.compressed, true); check(['perf-tile-draws', `${id} draws`], tile.draws, cap.draws, true); check(['perf-tile-triangles', `${id} triangles`], tile.triangles, cap.triangles, true);
|
|
241
|
+
}
|
|
242
|
+
if (source.far !== null) {
|
|
243
|
+
check(['perf-far-download', 'far download bytes'], source.far.compressed, C.far.compressed); check(['perf-far-draws', 'far draws'], source.far.draws, C.far.draws); check(['perf-far-triangles', 'far triangles'], source.far.triangles, C.far.triangles);
|
|
244
|
+
}
|
|
245
|
+
return issues;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
type DrawBounds = Shardfile['tiles'][number]['bounds'];
|
|
249
|
+
/** CI6: the extents of one visit's points. Comparisons only, so a NaN coordinate never counts, exactly as it never fails
|
|
250
|
+
* the per-point checks; an admission records them while one validator visits a prop GLB, so the draw-bounds check needs
|
|
251
|
+
* one visit per GLB instead of one per validator and placement. */
|
|
252
|
+
export class PropExtent {
|
|
253
|
+
minX: number; minY: number; minZ: number; maxX: number; maxY: number; maxZ: number; reachX = 0; reachZ = 0;
|
|
254
|
+
constructor() { this.minX = this.minY = this.minZ = Infinity; this.maxX = this.maxY = this.maxZ = -Infinity; }
|
|
255
|
+
add(triangle: readonly { readonly x: number; readonly y: number; readonly z: number }[]): void {
|
|
256
|
+
for (const { x, y, z } of triangle) {
|
|
257
|
+
if (x < this.minX) this.minX = x; if (x > this.maxX) this.maxX = x; if (y < this.minY) this.minY = y; if (y > this.maxY) this.maxY = y;
|
|
258
|
+
if (z < this.minZ) this.minZ = z; if (z > this.maxZ) this.maxZ = z;
|
|
259
|
+
const reachX = Math.abs(x), reachZ = Math.abs(z); if (reachX > this.reachX) this.reachX = reachX; if (reachZ > this.reachZ) this.reachZ = reachZ;
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
/** True exactly when no visited point fails validatePropDrawBounds' per-point test. */
|
|
263
|
+
within(bounds?: DrawBounds): boolean {
|
|
264
|
+
if (this.reachX > 250 || this.reachZ > 250) return false;
|
|
265
|
+
return bounds === undefined || !(this.minX < bounds.min[0] || this.maxX > bounds.max[0] || this.minY < bounds.min[1] || this.maxY > bounds.max[1] || this.minZ < bounds.min[2] || this.maxZ > bounds.max[2]);
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
/** Check the exact placed prop XZ footprint, even without drawBounds or overhang. Height keeps its own contract. `recorded`
|
|
270
|
+
* holds extents another validator recorded from these same assets; any check they would fail visits again, so a refusal
|
|
271
|
+
* is the per-point one. */
|
|
272
|
+
export function validatePropDrawBounds(source: Shardfile, assets: ReadonlyMap<string, Uint8Array>, recorded?: Map<string, PropExtent>): void {
|
|
273
|
+
const props = source.props; if (props === null) return;
|
|
274
|
+
const known = recorded ?? new Map<string, PropExtent>();
|
|
275
|
+
const validate = (ref: string, bounds?: DrawBounds): void => {
|
|
276
|
+
const bytes = assets.get(ref); if (bytes === undefined) throw new Error('Missing prop draw bytes');
|
|
277
|
+
let extent = known.get(ref);
|
|
278
|
+
if (extent === undefined) {
|
|
279
|
+
const visited = new PropExtent();
|
|
280
|
+
try { visitGlbTriangles(bytes, triangle => { visited.add(triangle); }); known.set(ref, visited); extent = visited; } catch { /* the per-point visit below refuses as before */ }
|
|
281
|
+
}
|
|
282
|
+
if (extent?.within(bounds) === true) return;
|
|
283
|
+
visitGlbTriangles(bytes, triangle => {
|
|
284
|
+
for (const point of triangle) {
|
|
285
|
+
if (Math.abs(point.x) > 250 || Math.abs(point.z) > 250) throw new Error('Prop exceeds cell draw bounds');
|
|
286
|
+
if (bounds !== undefined && (point.x < bounds.min[0] || point.x > bounds.max[0] || point.y < bounds.min[1] || point.y > bounds.max[1] || point.z < bounds.min[2] || point.z > bounds.max[2])) throw new Error('Prop exceeds declared visual draw bounds');
|
|
287
|
+
}
|
|
288
|
+
});
|
|
289
|
+
};
|
|
290
|
+
for (const row of props.tiles) {
|
|
291
|
+
const tile = source.tiles.find(candidate => candidate.lod === row.lod && candidate.x === row.x && candidate.z === row.z);
|
|
292
|
+
if (tile === undefined) throw new Error('Missing prop draw tile');
|
|
293
|
+
for (const ref of [row.file, ...row.additionalFiles ?? []]) validate(ref, tile.drawBounds);
|
|
294
|
+
}
|
|
295
|
+
for (const ref of [...props.panels.map(row => row.file), ...props.wholeLibrary ?? [], ...props.far === null ? [] : [props.far]]) validate(ref);
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
/** Report deterministic declared bounds and measured native execution; the caller supplies trusted provenance policy. */
|
|
299
|
+
export function performanceReport(source: Shardfile, observations: PerformanceObservations, policy: 'refuse' | 'warn' = 'refuse'): PerformanceReport {
|
|
300
|
+
const native = { resident: source.runtime?.cost === undefined ? 0 : runtimeAccountedBytes(source.runtime.cost), evidence: source.runtime?.cost?.evidence ?? null, unmeasuredViewAndDownload: source.runtime !== null };
|
|
301
|
+
const commons = native.resident + Object.values(source.requires.commonsCosts).reduce((sum, row) => sum + row.decoded + row.gpu, 0);
|
|
302
|
+
const worst = worstContentCost(source, commons), spawn = source.spawn;
|
|
303
|
+
const memory = { near: nearbyContentCost(source, spawn.x, spawn.z, commons), worst, playingLimit: C.playing, loadingLimit: C.loading };
|
|
304
|
+
const issues: PerformanceIssue[] = memoryTargetWarnings(source).map(row => ({ code: 'perf-memory-target', metric: `${row.category} resident target (tradeable)`, actual: row.bytes, limit: row.target, severity: 'warning' }));
|
|
305
|
+
issues.push(...performanceTargetIssues(source, policy));
|
|
306
|
+
const check = ([code, metric]: Named, actual: number, limit: number): void => {
|
|
307
|
+
if (!Number.isFinite(actual) || actual < 0 || actual > limit) issues.push({ code, metric, actual, limit, severity: policy === 'warn' ? 'warning' : 'refusal' });
|
|
308
|
+
};
|
|
309
|
+
if (native.unmeasuredViewAndDownload) check(['perf-native-view-unmeasured', 'native view/download measurement required'], 1, 0);
|
|
310
|
+
if (source.runtime !== null && source.runtime.cost === undefined) check(['perf-native-resident-unmeasured', 'native resident measurement required'], 1, 0);
|
|
311
|
+
// G433: while src/format/memoryGates.json is report-only the totals print as warnings and never refuse a build.
|
|
312
|
+
const total = ([code, metric]: Named, actual: number, limit: number): void => {
|
|
313
|
+
if (MEMORY_GATES.reportOnly && actual > limit) issues.push({ code, metric: `${metric} (report-only, G433)`, actual, limit, severity: 'warning' }); else check([code, metric], actual, limit);
|
|
314
|
+
};
|
|
315
|
+
total(['perf-playing-memory', 'worst playing total bytes'], worst.playing, C.playing); total(['perf-loading-memory', 'worst loading total bytes'], worst.loading, C.loading);
|
|
316
|
+
const library = reportCardClosure(source, source.library), critical = reportCardClosure(source, source.critical);
|
|
317
|
+
const tileRoots = source.tiles.flatMap(tile => tile.files), farRoots = source.far?.files ?? [], nearRoots = nearPlaceholderRoots(source.near);
|
|
318
|
+
const playable = reportCardClosure(source, [...source.critical, ...source.library, ...farRoots, ...source.tiles.filter(tile => tile.lod === 1 || near(tile, spawn.x, spawn.z)).flatMap(tile => tile.files)]);
|
|
319
|
+
const download = { critical: totals(source, critical).bytes, tiles: totals(source, reportCardClosure(source, tileRoots)).bytes,
|
|
320
|
+
library: totals(source, library).bytes, far: totals(source, reportCardClosure(source, farRoots)).bytes,
|
|
321
|
+
...(source.near === undefined ? {} : { near: totals(source, reportCardClosure(source, nearRoots)).bytes }),
|
|
322
|
+
total: totals(source, reportCardClosure(source, [...source.critical, ...source.library, ...tileRoots, ...farRoots, ...nearRoots])).bytes, playable: totals(source, playable).bytes };
|
|
323
|
+
const libraryView = totals(source, library);
|
|
324
|
+
const views = [['spawn', spawn.x, spawn.z], ['worst memory', ...worst.location]].map(([name, x, z]) => {
|
|
325
|
+
if (typeof name !== 'string' || typeof x !== 'number' || typeof z !== 'number') throw new Error('Invalid report view');
|
|
326
|
+
const tiles = source.tiles.filter(tile => tile.lod === 1 || near(tile, x, z));
|
|
327
|
+
return { name, x, z, draws: libraryView.draws + (source.far?.draws ?? 0) + tiles.reduce((sum, tile) => sum + tile.draws, 0),
|
|
328
|
+
triangles: libraryView.triangles + (source.far?.triangles ?? 0) + tiles.reduce((sum, tile) => sum + tile.triangles, 0) };
|
|
329
|
+
});
|
|
330
|
+
// D74: every material graph is a graph file, costed and held to its budget with its bytes at product admission
|
|
331
|
+
// (graphFileRules); a preset is engine-owned, under its own budget. The report carries no inline graph rows.
|
|
332
|
+
const graphs: PerformanceReport['graphs'] = [];
|
|
333
|
+
const scriptLimit = Math.min(source.serverBudget.tickMicros, 1_000_000 / 60 / 4);
|
|
334
|
+
for (const [group, data] of ([['scripts', observations.scripts], ['fuel', observations.fuel]] as const)) for (const [metric, value] of Object.entries(data)) {
|
|
335
|
+
if (!Number.isFinite(value) || value < 0) check(['perf-script-sample-invalid', `invalid measured ${group}.${metric}`], value, 0);
|
|
336
|
+
}
|
|
337
|
+
check(['perf-script-cpu', 'script CPU p95 us/tick'], observations.scripts.p95Micros, scriptLimit);
|
|
338
|
+
check(['perf-script-fuel', 'script fuel/tick'], observations.fuel.max, SCRIPT_LIMITS.fuelPerTick);
|
|
339
|
+
if (observations.scripts.samples < 60 || observations.fuel.samples < 60) check(['perf-script-samples-missing', 'missing execution samples'], 60, Math.min(observations.scripts.samples, observations.fuel.samples));
|
|
340
|
+
// An explicit cold-network estimate, not a measured phone loading claim. The guide names both assumptions.
|
|
341
|
+
const bytesPerSecond = 1_000_000, setupSeconds = 1;
|
|
342
|
+
return { slug: source.identity.slug, policy, pass: !issues.some(issue => issue.severity === 'refusal'), native, memory, views, graphs, scripts: observations, download,
|
|
343
|
+
estimatedPlayable: { seconds: setupSeconds + download.playable / bytesPerSecond, bytesPerSecond, setupSeconds }, issues };
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
/** Human-readable card keeps estimates visibly distinct from measurements and prints every enforced limit. */
|
|
347
|
+
export function performanceReportLines(report: PerformanceReport): string[] {
|
|
348
|
+
const mb = (bytes: number): string => `${(bytes / 1_000_000).toFixed(3)} MB`;
|
|
349
|
+
return [`PERFORMANCE REPORT ${report.slug}: ${report.pass ? 'PASS' : 'REFUSED'} (${report.policy})`,
|
|
350
|
+
`native runtime: charged ${mb(report.native.resident)}${report.native.evidence === null ? '' : ` from ${report.native.evidence}`}; ${report.native.unmeasuredViewAndDownload ? 'view/download remainder UNMEASURED (port required)' : 'none'}`,
|
|
351
|
+
`estimated memory near player (${report.memory.near.location.join(', ')}): play ${mb(report.memory.near.playing)}, load ${mb(report.memory.near.loading)}`,
|
|
352
|
+
`estimated worst grid memory (${report.memory.worst.location.join(', ')}): play ${mb(report.memory.worst.playing)} / ${mb(report.memory.playingLimit)}, load ${mb(report.memory.worst.loading)} / ${mb(report.memory.loadingLimit)}`,
|
|
353
|
+
...report.views.map(view => `declared view bounds ${view.name} (${view.x}, ${view.z}): ${view.draws} draws, ${view.triangles} triangles (before frustum/occlusion; excludes engine/native recipes)`),
|
|
354
|
+
...report.graphs.map(graph => `graph ${graph.id}: ${graph.nodes}/${DEFAULT_GRAPH_BUDGET.nodes} nodes, ${graph.samplers}/${DEFAULT_GRAPH_BUDGET.samplers} samplers, ${graph.instructions}/${DEFAULT_GRAPH_BUDGET.instructions} instructions`),
|
|
355
|
+
...(report.graphs.length === 0 ? ['graphs: 0 authored graphs; platform family shader presets'] : []),
|
|
356
|
+
report.scripts.scripts.samples === 0 ? 'scripts CPU/fuel: UNMEASURED (execution proof required)' : `measured scripts (${report.scripts.scripts.samples} ticks): p95 ${report.scripts.scripts.p95Micros.toFixed(1)} us/tick, max ${report.scripts.scripts.maxMicros.toFixed(1)} us/tick; fuel p95 ${report.scripts.fuel.p95}, max ${report.scripts.fuel.max}/${SCRIPT_LIMITS.fuelPerTick}`,
|
|
357
|
+
`download closures: critical ${mb(report.download.critical)}, tiles ${mb(report.download.tiles)}, library ${mb(report.download.library)}, far ${mb(report.download.far)}${report.download.near === undefined ? '' : `, near ${mb(report.download.near)}`}, unique total ${mb(report.download.total)}`,
|
|
358
|
+
`estimated playable ${report.estimatedPlayable.seconds.toFixed(3)} s: ${mb(report.download.playable)} at ${mb(report.estimatedPlayable.bytesPerSecond)}/s + ${report.estimatedPlayable.setupSeconds} s setup (assumptions, not a phone reading)`,
|
|
359
|
+
...report.issues.map(issue => `${issue.severity.toUpperCase()}: ${issue.metric}: ${issue.actual} > ${issue.limit}`)];
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
/** The memory admission an offline author build uses: strict for `refuse` unless src/format/memoryGates.json is
|
|
363
|
+
* report-only (G433), when an over-envelope total is accepted and printed by the performance report instead. */
|
|
364
|
+
export function offlineMemoryAdmission(policy: 'warn' | 'refuse'): MemoryAdmission | undefined {
|
|
365
|
+
return policy === 'warn' || MEMORY_GATES.reportOnly ? new MemoryAdmission(() => true) : undefined;
|
|
366
|
+
}
|
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
import { cookMountPath, readCookData } from './cook-data.ts';
|
|
2
|
+
import { requireCookPreparation } from './cook-preparation.ts';
|
|
3
|
+
import { parseOutputIndex, validateOutputSection, assembleOutputShardfile, type OutputFile, type OutputIndex } from './outputIndex.ts';
|
|
4
|
+
import { decisionModuleContracts, scriptAdmissionRows, type ScriptAdmissionRows, type ScriptContract } from './scriptContract.ts';
|
|
5
|
+
import { registeredJsonContract, validateRegisteredJson } from './registeredJson.ts';
|
|
6
|
+
import { validatePlatformFile } from './platformFileFamilies.ts';
|
|
7
|
+
import { parseNamedJson } from './json.ts';
|
|
8
|
+
import { ktx2DeviceCosts } from './ktx2Cost.ts';
|
|
9
|
+
import { isTerrainTileData } from './terrainTileBytes.ts';
|
|
10
|
+
import { parseImageAsset } from './stillImage.ts';
|
|
11
|
+
import { parseWorldTargets, worldTargetRules } from './worldTargets.ts';
|
|
12
|
+
import { parseShardfile, type Shardfile } from './shardSchema.ts';
|
|
13
|
+
import { assetCost, offlineMemoryAdmission, performanceTargetIssues } from './product.ts';
|
|
14
|
+
import { preflightDeclaredCosts, validateShardfileAssets } from './assetAdmission.ts';
|
|
15
|
+
import { validationSourceBytes } from './validationReceipt.ts';
|
|
16
|
+
import { SHARDFILE_ADMISSION_LIMITS as limits } from './admissionLimits.ts';
|
|
17
|
+
import { assetStore, checkPacks, mountSharesBlob } from './product-reads.ts';
|
|
18
|
+
import { assertSectionSides } from './feature-sides.ts';
|
|
19
|
+
import { assertScriptSides } from './script-sides.ts';
|
|
20
|
+
import { productRecordings } from './product-audio.ts';
|
|
21
|
+
import type { RecordingMeasure } from './audio-measure.ts';
|
|
22
|
+
import { issueError, withIssueCode as coded } from './issue-codes.ts';
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* P1-F3 format validation of a built shardfile product (format 2: `shard.json`, sections, blobs, packs): the schema,
|
|
26
|
+
* the exact file inventory, hashes and sizes, byte kinds, declared costs, budgets and script admission rows. It needs
|
|
27
|
+
* only this package. It never executes script bytes: re-running admitted WASM (G491) is the execution proof, which
|
|
28
|
+
* stays with the author CLI and the cook worker.
|
|
29
|
+
*
|
|
30
|
+
* Call `prepareAssetDecoders()` (`@wildshard/shard-format/product`) once before validating; GLB costs need the decoder.
|
|
31
|
+
*/
|
|
32
|
+
|
|
33
|
+
/** Read access to one product folder. Paths are `/`-separated and relative to the product root. */
|
|
34
|
+
export interface ProductFiles {
|
|
35
|
+
/** The bytes of one regular file, refusing symlinks and anything larger than `maxBytes`. */
|
|
36
|
+
readonly read: (path: string, maxBytes: number) => Uint8Array;
|
|
37
|
+
/** Every non-directory entry under the root (symlinks and special files included, so they are refused as unlisted). */
|
|
38
|
+
readonly paths: () => Iterable<string>;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/** The host services format validation needs but does not own. */
|
|
42
|
+
export interface ProductValidationPorts {
|
|
43
|
+
/** Lowercase hex SHA-256 of exact bytes. */
|
|
44
|
+
readonly hash: (bytes: Uint8Array) => string;
|
|
45
|
+
/** Whether bytes have the expected hash; `whole` marks a complete inventory file a caller may remember. Default: `hash`. */
|
|
46
|
+
readonly verify?: (bytes: Uint8Array, expected: string, whole: boolean) => boolean;
|
|
47
|
+
/** Extra JSON Schema check of a named blob against its embedded `jsonSchema` (the author SDK runs Ajv). Registered names
|
|
48
|
+
* are always parsed by their defining format schema; an unregistered name with an embedded schema needs this port. */
|
|
49
|
+
readonly definedJson?: (schemaBytes: Uint8Array, bytes: Uint8Array, name: string | undefined) => void;
|
|
50
|
+
/** Import check for a copied `runtime/` file (the retired copied-runtime arm). Without it such files are refused. */
|
|
51
|
+
readonly runtimeImports?: (path: string, source: string) => void;
|
|
52
|
+
/** D31: hold no file's bytes between checks. `assets`, here and in the result, reads each file again from `files`, so a
|
|
53
|
+
* host's peak is its largest file rather than the shard, at the cost of those repeat reads. */
|
|
54
|
+
readonly readThrough?: boolean;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/** A product that passed format validation. */
|
|
58
|
+
export interface ValidatedProduct {
|
|
59
|
+
readonly index: OutputIndex;
|
|
60
|
+
readonly shard: Shardfile;
|
|
61
|
+
/** Admitted bytes by hash (`commons:<hash>` for pinned commons). */
|
|
62
|
+
readonly assets: ReadonlyMap<string, Uint8Array>;
|
|
63
|
+
/** The parsed section payloads by section name. */
|
|
64
|
+
readonly sections: ReadonlyMap<string, unknown>;
|
|
65
|
+
/** The script admission rows the product was admitted with. */
|
|
66
|
+
readonly scripts: ScriptAdmissionRows;
|
|
67
|
+
/** Admitted with a warning: grandfathered script side lines (`SCRIPT_SIDE_GRANDFATHER`, SERVER-PARITY SS11). */
|
|
68
|
+
readonly warnings: readonly string[];
|
|
69
|
+
/** AUDIO AU5: the shard's own recordings (audio mounts and non-commons `audio.recordings`), measured from their bytes. */
|
|
70
|
+
readonly audio: readonly RecordingMeasure[];
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const decoder = (): TextDecoder => new TextDecoder('utf-8', { fatal: true });
|
|
74
|
+
|
|
75
|
+
/** Parse canonical JSON bytes (sorted keys, one trailing newline), refusing any other encoding of the same value. */
|
|
76
|
+
export function readCanonicalJson(bytes: Uint8Array): unknown {
|
|
77
|
+
const text = decoder().decode(bytes), value: unknown = JSON.parse(text);
|
|
78
|
+
if (decoder().decode(validationSourceBytes(value)) !== text) throw new Error('Output JSON must use canonical encoding');
|
|
79
|
+
return value;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/** The output kind of an asset's bytes, from its declared shardfile kind (`commons` sniffs the bytes). */
|
|
83
|
+
export function outputBlobKind(kind: string, bytes: Uint8Array): OutputFile['kind'] {
|
|
84
|
+
if (kind === 'binary') return isTerrainTileData(bytes) ? 'tile' : 'bin';
|
|
85
|
+
if (kind === 'commons') {
|
|
86
|
+
const head = new TextDecoder().decode(bytes.subarray(0, 4));
|
|
87
|
+
if (head === 'glTF') return 'glb'; if (bytes[0] === 171) return 'ktx2';
|
|
88
|
+
if (head === 'RIFF' || new TextDecoder().decode(bytes.subarray(4, 8)) === 'ftyp') return 'audio';
|
|
89
|
+
return isTerrainTileData(bytes) ? 'tile' : 'bin';
|
|
90
|
+
}
|
|
91
|
+
if (kind === 'glb' || kind === 'ktx2' || kind === 'audio' || kind === 'json' || kind === 'wasm' || kind === 'image') return kind;
|
|
92
|
+
throw new Error('Unsupported output asset kind');
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/** The file extension an output blob of this kind and these bytes is written with. */
|
|
96
|
+
export function outputBlobExtension(kind: OutputFile['kind'], bytes: Uint8Array): string {
|
|
97
|
+
if (kind === 'tile') return 'wtt';
|
|
98
|
+
if (kind === 'image') return { 'image/webp': 'webp', 'image/jpeg': 'jpg', 'image/png': 'png' }[parseImageAsset(bytes).mime];
|
|
99
|
+
if (kind === 'audio') {
|
|
100
|
+
const head = new TextDecoder().decode(bytes.subarray(0, 4));
|
|
101
|
+
if (head === 'RIFF') return 'wav'; if (head === 'OggS') return 'ogg';
|
|
102
|
+
if (new TextDecoder().decode(bytes.subarray(4, 8)) === 'ftyp') return 'm4a';
|
|
103
|
+
return 'mp3';
|
|
104
|
+
}
|
|
105
|
+
return kind;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/** Refuse the declared targets a policy treats as refusals, before any byte is read or executed. */
|
|
109
|
+
export function assertProductTargets(source: Shardfile, policy: 'warn' | 'refuse'): void {
|
|
110
|
+
const issues = performanceTargetIssues(source, policy).filter(issue => issue.severity === 'refusal');
|
|
111
|
+
if (issues.length === 0) return;
|
|
112
|
+
throw issueError('performance-targets', issues.map(issue => `REFUSAL: ${issue.metric}: ${issue.actual} > ${issue.limit}`).join('\n'));
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/** Admit a whole shardfile's declared costs and its actual immutable bytes through the defining contracts. */
|
|
116
|
+
export function admitShardfileProduct(input: unknown, assets: ReadonlyMap<string, Uint8Array>, hash: (bytes: Uint8Array) => string,
|
|
117
|
+
policy: 'warn' | 'refuse' = 'refuse', scripts: ScriptAdmissionRows = []): Shardfile {
|
|
118
|
+
const source = coded('shard-schema', (): Shardfile => parseShardfile(input));
|
|
119
|
+
coded('declared-costs', (): void => { preflightDeclaredCosts(source, offlineMemoryAdmission(policy)); });
|
|
120
|
+
coded('performance-targets', (): void => { assertProductTargets(source, policy); });
|
|
121
|
+
return coded('asset-admission', (): Shardfile => validateShardfileAssets(source, assets, hash, offlineMemoryAdmission(policy), undefined, scripts));
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/** Refuse world target rows that name items or quests the shardfile does not declare. */
|
|
125
|
+
export function checkWorldTargets(source: Shardfile, input: unknown): void {
|
|
126
|
+
if (input === undefined) return;
|
|
127
|
+
const errors = coded('world-targets', (): string[] => worldTargetRules(parseWorldTargets(input), source));
|
|
128
|
+
if (errors.length > 0) throw issueError('world-targets', errors.join('; '));
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function inspectBlob(file: OutputFile, bytes: Uint8Array, ports: ProductValidationPorts, script?: ScriptContract): void {
|
|
132
|
+
const contract = file.name === undefined ? undefined : registeredJsonContract(file.name);
|
|
133
|
+
if (contract !== undefined && (file.kind !== 'json' || file.jsonSchema === undefined)) throw new Error('Registered JSON requires its defining schema');
|
|
134
|
+
if (file.jsonSchema !== undefined) {
|
|
135
|
+
if (ports.definedJson !== undefined) ports.definedJson(validationSourceBytes(file.jsonSchema), bytes, file.name);
|
|
136
|
+
else if (contract === undefined || file.name === undefined) throw new Error('Unregistered named JSON with a schema needs a JSON Schema checker');
|
|
137
|
+
else {
|
|
138
|
+
if (file.jsonSchema['$comment'] !== contract.source) throw new Error('Registered JSON requires its exact defining format contract');
|
|
139
|
+
validateRegisteredJson(file.name, parseNamedJson(bytes));
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
if (file.kind === 'json' && file.name !== undefined) {
|
|
143
|
+
const source = file.jsonSchema?.['$comment'];
|
|
144
|
+
if (validatePlatformFile(file.name, typeof source === 'string' ? source : undefined, parseNamedJson(bytes)) === undefined) throw new Error(`Unregistered named JSON: ${file.name}`);
|
|
145
|
+
}
|
|
146
|
+
const legacy = file.kind === 'bin' || file.kind === 'tile' ? 'binary' : file.kind;
|
|
147
|
+
if (outputBlobKind(legacy, bytes) !== file.kind || !file.path.endsWith(`.${outputBlobExtension(file.kind, bytes)}`)) throw new Error('Output blob bytes differ from their declared kind');
|
|
148
|
+
const cost = assetCost(legacy, bytes, script);
|
|
149
|
+
if ((['decoded', 'gpu', 'triangles', 'draws'] as const).some(key => cost[key] > file[key])) throw new Error('Output blob understates parsed costs');
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
type ReadListed = (entry: Readonly<{ path: string; hash: string; bytes: number }>) => Uint8Array;
|
|
153
|
+
|
|
154
|
+
/** Each section: listed, canonical, a declared side, its schema (`section-invalid`). */
|
|
155
|
+
// oxlint-disable-next-line typescript/prefer-readonly-parameter-types -- valibot's output type, only read
|
|
156
|
+
function readSections(index: OutputIndex, read: ReadListed): Map<string, unknown> {
|
|
157
|
+
const payloads = new Map<string, unknown>();
|
|
158
|
+
for (const entry of index.sections) {
|
|
159
|
+
coded('section-invalid', (): void => { const value = readCanonicalJson(read(entry)); assertSectionSides(entry.name, value); validateOutputSection(entry.name, value); payloads.set(entry.name, value); });
|
|
160
|
+
}
|
|
161
|
+
return payloads;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/** J91: server files pass the same hash, size and schema checks; they stay out of the client's admitted assets. Then the
|
|
165
|
+
* declared KTX2 device costs against the verified bytes. */
|
|
166
|
+
// oxlint-disable-next-line typescript/prefer-readonly-parameter-types -- valibot's output type and the admitted bytes, only read
|
|
167
|
+
function checkServerAndKtx2(index: OutputIndex, read: ReadListed, assets: ReadonlyMap<string, Uint8Array>): void {
|
|
168
|
+
for (const entry of index.admission.server ?? []) {
|
|
169
|
+
const bytes = read(entry);
|
|
170
|
+
coded('server-file-invalid', (): void => {
|
|
171
|
+
if (entry.kind === 'json') {
|
|
172
|
+
if (validatePlatformFile(entry.name, entry.schema, readCanonicalJson(bytes)) === undefined) throw new Error(`Unregistered named JSON: ${entry.name}`);
|
|
173
|
+
} else if (outputBlobKind('binary', bytes) !== entry.kind) throw new Error('Output blob bytes differ from their declared kind');
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
coded('ktx2-costs', (): void => {
|
|
177
|
+
for (const [hash, cost] of Object.entries(index.ktx2Costs ?? {})) {
|
|
178
|
+
const bytes = assets.get(hash);
|
|
179
|
+
if (bytes === undefined || decoder().decode(validationSourceBytes(cost)) !== decoder().decode(validationSourceBytes(ktx2DeviceCosts(bytes)))) throw new Error('KTX2 device costs differ from verified bytes');
|
|
180
|
+
}
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/** C0 (J137): the cook file; a mount passes the same hash and size checks as any listed file (`cook-invalid`). */
|
|
185
|
+
// oxlint-disable-next-line typescript/prefer-readonly-parameter-types -- valibot's output type, only read
|
|
186
|
+
function readCook(index: OutputIndex, read: ReadListed, hash: (bytes: Uint8Array) => string): ReturnType<typeof readCookData> | undefined {
|
|
187
|
+
return coded('cook-invalid', (): ReturnType<typeof readCookData> | undefined => {
|
|
188
|
+
const cook = index.cook === undefined ? undefined : readCookData(readCanonicalJson(read(index.cook)));
|
|
189
|
+
requireCookPreparation(index, cook, hash);
|
|
190
|
+
for (const mount of cook?.mounts ?? []) {
|
|
191
|
+
if (!mountSharesBlob(mount, index.files)) {
|
|
192
|
+
if (mount.path !== cookMountPath(mount.url)) { throw new Error(`Mount path differs from its URL: ${mount.url}`); }
|
|
193
|
+
read(mount);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
return cook;
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/** Validate a built product folder with format alone: the index and section schemas, the exact inventory (no unlisted,
|
|
201
|
+
* missing or changed file), every hash and size, byte kinds against declared kinds and costs, KTX2 device costs, pack
|
|
202
|
+
* members, registered named JSON, budgets and admission, world targets and the declared source hash. A `client/plan`
|
|
203
|
+
* kind with no declared side (SERVER-PARITY SS2, `feature-sides.ts`) is refused by name before its section schema runs, and
|
|
204
|
+
* a script run on the wrong side (SS7, `script-sides.ts`) once the sections are read. A refusal carries the `code` of the
|
|
205
|
+
* check that refused (SA41, `issue-codes.ts`). */
|
|
206
|
+
export function validateShardfileProduct(files: ProductFiles, ports: ProductValidationPorts): ValidatedProduct {
|
|
207
|
+
const verify = ports.verify ?? ((bytes: Uint8Array, expected: string): boolean => ports.hash(bytes) === expected);
|
|
208
|
+
const index = coded('index-invalid', (): OutputIndex => parseOutputIndex(readCanonicalJson(files.read('shard.json', limits.sourceBytes))));
|
|
209
|
+
const listed = new Set(['shard.json', 'validation.json']), { assets, keep } = assetStore(files.read, ports.readThrough === true);
|
|
210
|
+
const read: ReadListed = (entry): Uint8Array => coded('file-mismatch', (): Uint8Array => {
|
|
211
|
+
listed.add(entry.path);
|
|
212
|
+
const bytes = files.read(entry.path, entry.bytes);
|
|
213
|
+
if (bytes.length !== entry.bytes || !verify(bytes, entry.hash, true)) throw new Error(`Output hash or size mismatch: ${entry.path}`);
|
|
214
|
+
return bytes;
|
|
215
|
+
});
|
|
216
|
+
const payloads = readSections(index, read), warnings = coded('script-side', (): string[] => assertScriptSides(payloads, index, { ...files, verify }));
|
|
217
|
+
const scripts = coded('script-admission', (): ScriptAdmissionRows => scriptAdmissionRows(payloads));
|
|
218
|
+
const contracts = coded('script-admission', (): ReturnType<typeof decisionModuleContracts> => decisionModuleContracts(scripts, index.files));
|
|
219
|
+
for (const entry of index.files) {
|
|
220
|
+
const bytes = read({ path: entry.path, hash: entry.hash, bytes: entry.compressed });
|
|
221
|
+
coded('blob-invalid', (): void => { inspectBlob(entry, bytes, ports, entry.kind === 'wasm' ? contracts.get(entry.hash) ?? { abi: 0 } : undefined); });
|
|
222
|
+
keep(entry, bytes, index.requires.commons.includes(entry.hash));
|
|
223
|
+
}
|
|
224
|
+
checkServerAndKtx2(index, read, assets);
|
|
225
|
+
coded('pack-invalid', (): void => { checkPacks(index, new Set(files.paths()), { readFile: files.read, readListed: read, verify, hash: ports.hash }); });
|
|
226
|
+
const cook = readCook(index, read, ports.hash);
|
|
227
|
+
for (const entry of index.runtime?.files ?? []) {
|
|
228
|
+
if (ports.runtimeImports === undefined) throw issueError('runtime-files', 'Copied runtime files need a runtime import checker');
|
|
229
|
+
coded('runtime-files', (): void => { ports.runtimeImports?.(entry.path, decoder().decode(read(entry))); });
|
|
230
|
+
}
|
|
231
|
+
for (const path of files.paths()) if (!listed.has(path)) throw issueError('unlisted-file', `Unlisted output file: ${path}`);
|
|
232
|
+
const shard = admitShardfileProduct(coded('shard-schema', (): unknown => assembleOutputShardfile(index, payloads)), assets, ports.hash, 'warn', scripts);
|
|
233
|
+
checkWorldTargets(shard, payloads.get('world/targets'));
|
|
234
|
+
if (ports.hash(validationSourceBytes(shard)) !== index.build.sourceHash) throw issueError('source-hash', 'Output sections differ from the declared source hash');
|
|
235
|
+
return { index, shard, assets, sections: payloads, scripts, warnings, audio: productRecordings({ cook, read: files.read, shard, assets }) };
|
|
236
|
+
}
|