@combos-fun/engine 0.0.38 → 0.0.40

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.
@@ -1001,7 +1001,7 @@ class Scene extends GameObject {
1001
1001
  }
1002
1002
 
1003
1003
  /** Generated at build from package.json */
1004
- const version = "0.0.38";
1004
+ const version = "0.0.40";
1005
1005
 
1006
1006
  /**
1007
1007
  * Sent to `window.parent` after each `System.init` completes during `Game.addSystem`
@@ -1642,6 +1642,117 @@ class Progress extends EventEmitter__default.default {
1642
1642
  }
1643
1643
  }
1644
1644
 
1645
+ const SLOT_DEFAULT_TYPE = {
1646
+ image: 'png',
1647
+ json: 'json',
1648
+ tex: 'tex',
1649
+ ske: 'ske',
1650
+ audio: 'audio',
1651
+ video: 'video',
1652
+ model: 'glb',
1653
+ mtl: 'mtl',
1654
+ bin: 'bin',
1655
+ };
1656
+ const EXT_TO_TYPE = {
1657
+ png: 'png',
1658
+ jpg: 'jpg',
1659
+ jpeg: 'jpeg',
1660
+ webp: 'webp',
1661
+ json: 'json',
1662
+ tex: 'tex',
1663
+ ske: 'ske',
1664
+ mp3: 'audio',
1665
+ wav: 'audio',
1666
+ aac: 'audio',
1667
+ ogg: 'audio',
1668
+ mp4: 'video',
1669
+ webm: 'video',
1670
+ glb: 'glb',
1671
+ gltf: 'gltf',
1672
+ fbx: 'fbx',
1673
+ obj: 'obj',
1674
+ mtl: 'mtl',
1675
+ stl: 'stl',
1676
+ dae: 'dae',
1677
+ ply: 'ply',
1678
+ bin: 'bin',
1679
+ };
1680
+ function extensionOf(url) {
1681
+ const path = url.split('?')[0].split('#')[0];
1682
+ const dot = path.lastIndexOf('.');
1683
+ if (dot < 0)
1684
+ return '';
1685
+ return path.slice(dot + 1).toLowerCase();
1686
+ }
1687
+ function typeFromUrl(url, slot) {
1688
+ return EXT_TO_TYPE[extensionOf(url)] || SLOT_DEFAULT_TYPE[slot] || 'png';
1689
+ }
1690
+ function defaultSlotForResourceType(resourceType) {
1691
+ if (resourceType === 'AUDIO')
1692
+ return 'audio';
1693
+ if (resourceType === 'VIDEO')
1694
+ return 'video';
1695
+ if (resourceType === 'MODEL' || resourceType === 'GLB')
1696
+ return 'model';
1697
+ return 'image';
1698
+ }
1699
+ function wrapSlot(slot, value, resourceName) {
1700
+ if (typeof value === 'string') {
1701
+ const url = value.trim();
1702
+ if (!url) {
1703
+ throw missingUrlError(resourceName, slot);
1704
+ }
1705
+ return { type: typeFromUrl(url, slot), url };
1706
+ }
1707
+ if (!value || typeof value !== 'object' || Array.isArray(value)) {
1708
+ throw new Error(`Resource "${resourceName}" src.${slot} must be a url string or { type, url }.`);
1709
+ }
1710
+ const slotValue = value;
1711
+ if (slotValue.type === 'data') {
1712
+ return slotValue;
1713
+ }
1714
+ const url = typeof slotValue.url === 'string' ? slotValue.url.trim() : '';
1715
+ if (!url) {
1716
+ throw missingUrlError(resourceName, slot);
1717
+ }
1718
+ return {
1719
+ ...slotValue,
1720
+ type: slotValue.type || typeFromUrl(url, slot),
1721
+ url,
1722
+ };
1723
+ }
1724
+ function missingUrlError(resourceName, slot) {
1725
+ return new Error(`Resource "${resourceName}" src.${slot}.url is required. ` +
1726
+ `Use { type, url } (e.g. { type: "webp", url: "https://..." }). ` +
1727
+ `A flat path string is also accepted and will be normalized.`);
1728
+ }
1729
+ /**
1730
+ * Accept the documented `{ type, url }` slots, plus the common guesses
1731
+ * `src: "file.png"` and `src: { image: "a.webp", json: "a.json" }`.
1732
+ */
1733
+ function normalizeResourceSrc(src, resourceType, resourceName = '(unnamed)') {
1734
+ if (src == null) {
1735
+ throw new Error(`Resource "${resourceName}" src is required.`);
1736
+ }
1737
+ if (typeof src === 'string') {
1738
+ const slot = defaultSlotForResourceType(resourceType);
1739
+ return { [slot]: wrapSlot(slot, src, resourceName) };
1740
+ }
1741
+ if (typeof src !== 'object' || Array.isArray(src)) {
1742
+ throw new Error(`Resource "${resourceName}" src must be a url string or a slot object.`);
1743
+ }
1744
+ const out = {};
1745
+ for (const [slot, value] of Object.entries(src)) {
1746
+ if (value == null)
1747
+ continue;
1748
+ out[slot] = wrapSlot(slot, value, resourceName);
1749
+ }
1750
+ if (Object.keys(out).length === 0) {
1751
+ throw new Error(`Resource "${resourceName}" src has no loadable slots.`);
1752
+ }
1753
+ return out;
1754
+ }
1755
+
1645
1756
  const resourceLoader = {
1646
1757
  AbstractLoadStrategy: resourceLoader$1.AbstractLoadStrategy,
1647
1758
  AudioLoadStrategy: resourceLoader$1.AudioLoadStrategy,
@@ -1656,6 +1767,102 @@ const resourceLoader = {
1656
1767
  ResourceState: resourceLoader$1.ResourceState
1657
1768
  };
1658
1769
 
1770
+ function isFrameMap(frames) {
1771
+ return !!frames && typeof frames === 'object' && !Array.isArray(frames);
1772
+ }
1773
+ function frameFromPackedItem(item) {
1774
+ const frame = item.frame;
1775
+ if (!frame || typeof frame !== 'object')
1776
+ return null;
1777
+ return {
1778
+ ...item,
1779
+ frame: frame,
1780
+ rotated: Boolean(item.rotated),
1781
+ trimmed: Boolean(item.trimmed),
1782
+ spriteSourceSize: item.spriteSourceSize,
1783
+ sourceSize: item.sourceSize,
1784
+ };
1785
+ }
1786
+ function collectArrayFrames(list, frames, animations) {
1787
+ for (const raw of list) {
1788
+ if (!raw || typeof raw !== 'object')
1789
+ continue;
1790
+ const item = raw;
1791
+ const name = String(item.filename || item.name || '');
1792
+ if (!name)
1793
+ continue;
1794
+ const packed = frameFromPackedItem(item);
1795
+ if (!packed)
1796
+ continue;
1797
+ frames[name] = packed;
1798
+ const slash = name.lastIndexOf('/');
1799
+ if (slash > 0) {
1800
+ const anim = name.slice(0, slash);
1801
+ if (!animations[anim])
1802
+ animations[anim] = [];
1803
+ if (!animations[anim].includes(name))
1804
+ animations[anim].push(name);
1805
+ }
1806
+ }
1807
+ }
1808
+ /**
1809
+ * Pixi `Spritesheet` reads `data.meta.scale` and a name→frame `frames` map.
1810
+ * TexturePacker multi-atlas (`textures[].frames` as an array) is accepted and
1811
+ * rewritten to that hash. Always returns a `meta.scale` so construction cannot
1812
+ * throw `Cannot read properties of undefined (reading 'scale')`.
1813
+ */
1814
+ function normalizeSpritesheetData(raw) {
1815
+ if (!raw || typeof raw !== 'object') {
1816
+ return { frames: {}, animations: {}, meta: { scale: 1 } };
1817
+ }
1818
+ const json = raw;
1819
+ if (isFrameMap(json.frames)) {
1820
+ return {
1821
+ ...json,
1822
+ frames: json.frames,
1823
+ animations: { ...(json.animations || {}) },
1824
+ meta: { scale: 1, ...(json.meta || {}) },
1825
+ };
1826
+ }
1827
+ const frames = {};
1828
+ const animations = { ...(json.animations || {}) };
1829
+ if (Array.isArray(json.textures)) {
1830
+ for (const sheet of json.textures) {
1831
+ if (!sheet || typeof sheet !== 'object')
1832
+ continue;
1833
+ if (Array.isArray(sheet.frames)) {
1834
+ collectArrayFrames(sheet.frames, frames, animations);
1835
+ }
1836
+ }
1837
+ const first = json.textures[0] || {};
1838
+ const scale = first.scale ?? json.meta?.scale ?? 1;
1839
+ return {
1840
+ frames,
1841
+ animations,
1842
+ meta: {
1843
+ scale: typeof scale === 'number' || typeof scale === 'string' ? scale : 1,
1844
+ image: typeof first.image === 'string' ? first.image : undefined,
1845
+ size: first.size,
1846
+ format: first.format,
1847
+ ...(json.meta || {}),
1848
+ },
1849
+ };
1850
+ }
1851
+ if (Array.isArray(json.frames)) {
1852
+ collectArrayFrames(json.frames, frames, animations);
1853
+ return {
1854
+ frames,
1855
+ animations,
1856
+ meta: { scale: 1, ...(json.meta || {}) },
1857
+ };
1858
+ }
1859
+ return {
1860
+ frames: {},
1861
+ animations,
1862
+ meta: { scale: 1, ...(json.meta || {}) },
1863
+ };
1864
+ }
1865
+
1659
1866
  /** Resource type */
1660
1867
  exports.RESOURCE_TYPE = void 0;
1661
1868
  (function (RESOURCE_TYPE) {
@@ -1665,6 +1872,7 @@ exports.RESOURCE_TYPE = void 0;
1665
1872
  RESOURCE_TYPE["AUDIO"] = "AUDIO";
1666
1873
  RESOURCE_TYPE["VIDEO"] = "VIDEO";
1667
1874
  RESOURCE_TYPE["GLB"] = "GLB";
1875
+ RESOURCE_TYPE["MODEL"] = "MODEL";
1668
1876
  })(exports.RESOURCE_TYPE || (exports.RESOURCE_TYPE = {}));
1669
1877
  resourceLoader$1.XhrLoadStrategy.setExtensionXhrType('json', resourceLoader$1.XhrResponseType.Json);
1670
1878
  resourceLoader$1.XhrLoadStrategy.setExtensionXhrType('tex', resourceLoader$1.XhrResponseType.Json);
@@ -1675,6 +1883,13 @@ resourceLoader$1.XhrLoadStrategy.setExtensionXhrType('aac', resourceLoader$1.Xhr
1675
1883
  resourceLoader$1.XhrLoadStrategy.setExtensionXhrType('ogg', resourceLoader$1.XhrResponseType.Buffer);
1676
1884
  resourceLoader$1.XhrLoadStrategy.setExtensionXhrType('glb', resourceLoader$1.XhrResponseType.Buffer);
1677
1885
  resourceLoader$1.XhrLoadStrategy.setExtensionXhrType('gltf', resourceLoader$1.XhrResponseType.Json);
1886
+ resourceLoader$1.XhrLoadStrategy.setExtensionXhrType('fbx', resourceLoader$1.XhrResponseType.Buffer);
1887
+ resourceLoader$1.XhrLoadStrategy.setExtensionXhrType('stl', resourceLoader$1.XhrResponseType.Buffer);
1888
+ resourceLoader$1.XhrLoadStrategy.setExtensionXhrType('ply', resourceLoader$1.XhrResponseType.Buffer);
1889
+ resourceLoader$1.XhrLoadStrategy.setExtensionXhrType('bin', resourceLoader$1.XhrResponseType.Buffer);
1890
+ resourceLoader$1.XhrLoadStrategy.setExtensionXhrType('obj', resourceLoader$1.XhrResponseType.Text);
1891
+ resourceLoader$1.XhrLoadStrategy.setExtensionXhrType('mtl', resourceLoader$1.XhrResponseType.Text);
1892
+ resourceLoader$1.XhrLoadStrategy.setExtensionXhrType('dae', resourceLoader$1.XhrResponseType.Text);
1678
1893
  const RESOURCE_TYPE_STRATEGY = {
1679
1894
  png: resourceLoader$1.ImageLoadStrategy,
1680
1895
  jpg: resourceLoader$1.ImageLoadStrategy,
@@ -1687,6 +1902,13 @@ const RESOURCE_TYPE_STRATEGY = {
1687
1902
  video: resourceLoader$1.VideoLoadStrategy,
1688
1903
  glb: resourceLoader$1.XhrLoadStrategy,
1689
1904
  gltf: resourceLoader$1.XhrLoadStrategy,
1905
+ fbx: resourceLoader$1.XhrLoadStrategy,
1906
+ obj: resourceLoader$1.XhrLoadStrategy,
1907
+ mtl: resourceLoader$1.XhrLoadStrategy,
1908
+ stl: resourceLoader$1.XhrLoadStrategy,
1909
+ dae: resourceLoader$1.XhrLoadStrategy,
1910
+ ply: resourceLoader$1.XhrLoadStrategy,
1911
+ bin: resourceLoader$1.XhrLoadStrategy,
1690
1912
  };
1691
1913
  /**
1692
1914
  * Resource manager
@@ -1733,8 +1955,11 @@ class Resource extends EventEmitter__default.default {
1733
1955
  console.warn(res.name + ' was already added');
1734
1956
  continue;
1735
1957
  }
1736
- this.resourcesMap[res.name] = res;
1737
- this.resourcesMap[res.name].data = {};
1958
+ this.resourcesMap[res.name] = {
1959
+ ...res,
1960
+ src: normalizeResourceSrc(res.src, String(res.type), res.name),
1961
+ data: {},
1962
+ };
1738
1963
  }
1739
1964
  }
1740
1965
  /** dd resource preprocesser*/
@@ -1823,6 +2048,7 @@ class Resource extends EventEmitter__default.default {
1823
2048
  for (const handler of this.preProcessResourceHandlers) {
1824
2049
  handler(res);
1825
2050
  }
2051
+ res.src = normalizeResourceSrc(res.src, String(res.type), res.name);
1826
2052
  for (const key in res.src) {
1827
2053
  const resourceType = res.src[key].type;
1828
2054
  if (resourceType === 'data') {
@@ -1949,6 +2175,8 @@ exports.componentObserver = componentObserver;
1949
2175
  exports.decorators = decorators;
1950
2176
  exports.isAllowedMessageOrigin = isAllowedMessageOrigin;
1951
2177
  exports.mergeAllowedMessageOrigins = mergeAllowedMessageOrigins;
2178
+ exports.normalizeResourceSrc = normalizeResourceSrc;
2179
+ exports.normalizeSpritesheetData = normalizeSpritesheetData;
1952
2180
  exports.parseSetPlayingMessage = parseSetPlayingMessage;
1953
2181
  exports.postParentGameReady = postParentGameReady;
1954
2182
  exports.postParentGameState = postParentGameState;