@penabt/pixi-expo 0.6.0 → 0.6.1
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/README.md +1 -1
- package/dist/index.d.mts +1 -8
- package/dist/index.d.ts +1 -8
- package/dist/index.js +111 -18
- package/dist/index.mjs +104 -11
- package/package.json +1 -1
- package/src/adapter/loadExpoBitmapFont.ts +127 -16
- package/src/index.ts +1 -1
- package/src/utils/designResolution.ts +1 -1
package/README.md
CHANGED
|
@@ -292,7 +292,7 @@ module.exports = config;
|
|
|
292
292
|
|
|
293
293
|
## Design Resolution
|
|
294
294
|
|
|
295
|
-
|
|
295
|
+
Fixed coordinate system for your game. Define a virtual resolution and the library automatically scales the stage to fit any device screen.
|
|
296
296
|
|
|
297
297
|
```tsx
|
|
298
298
|
<PixiView
|
package/dist/index.d.mts
CHANGED
|
@@ -543,13 +543,6 @@ declare const loadExpoFont: LoaderParser<string>;
|
|
|
543
543
|
* ```
|
|
544
544
|
*/
|
|
545
545
|
declare function registerBitmapFont(xmlModuleId: number, pageModuleIds: number[]): string;
|
|
546
|
-
/**
|
|
547
|
-
* Expo Bitmap Font Loader
|
|
548
|
-
*
|
|
549
|
-
* A PixiJS LoadParser that handles local bitmap fonts registered via
|
|
550
|
-
* registerBitmapFont(). Runs at High priority to intercept before
|
|
551
|
-
* PixiJS's built-in loadBitmapFont (which can't handle module IDs).
|
|
552
|
-
*/
|
|
553
546
|
declare const loadExpoBitmapFont: LoaderParser;
|
|
554
547
|
|
|
555
548
|
/**
|
|
@@ -627,7 +620,7 @@ declare function createExpoManifest(manifest: ExpoAssetsManifest): AssetsManifes
|
|
|
627
620
|
/**
|
|
628
621
|
* Design resolution scaling utilities.
|
|
629
622
|
*
|
|
630
|
-
* Provides
|
|
623
|
+
* Provides design resolution support: define a fixed logical
|
|
631
624
|
* size (e.g. 768×1024) and the library automatically scales the PixiJS stage
|
|
632
625
|
* to fit the device screen.
|
|
633
626
|
*/
|
package/dist/index.d.ts
CHANGED
|
@@ -543,13 +543,6 @@ declare const loadExpoFont: LoaderParser<string>;
|
|
|
543
543
|
* ```
|
|
544
544
|
*/
|
|
545
545
|
declare function registerBitmapFont(xmlModuleId: number, pageModuleIds: number[]): string;
|
|
546
|
-
/**
|
|
547
|
-
* Expo Bitmap Font Loader
|
|
548
|
-
*
|
|
549
|
-
* A PixiJS LoadParser that handles local bitmap fonts registered via
|
|
550
|
-
* registerBitmapFont(). Runs at High priority to intercept before
|
|
551
|
-
* PixiJS's built-in loadBitmapFont (which can't handle module IDs).
|
|
552
|
-
*/
|
|
553
546
|
declare const loadExpoBitmapFont: LoaderParser;
|
|
554
547
|
|
|
555
548
|
/**
|
|
@@ -627,7 +620,7 @@ declare function createExpoManifest(manifest: ExpoAssetsManifest): AssetsManifes
|
|
|
627
620
|
/**
|
|
628
621
|
* Design resolution scaling utilities.
|
|
629
622
|
*
|
|
630
|
-
* Provides
|
|
623
|
+
* Provides design resolution support: define a fixed logical
|
|
631
624
|
* size (e.g. 768×1024) and the library automatically scales the PixiJS stage
|
|
632
625
|
* to fit the device screen.
|
|
633
626
|
*/
|
package/dist/index.js
CHANGED
|
@@ -1463,6 +1463,7 @@ var loadExpoFont = {
|
|
|
1463
1463
|
// src/adapter/loadExpoBitmapFont.ts
|
|
1464
1464
|
var import_expo_asset3 = require("expo-asset");
|
|
1465
1465
|
var import_expo_file_system = require("expo-file-system");
|
|
1466
|
+
var import_react_native2 = require("react-native");
|
|
1466
1467
|
var import_pixi3 = require("pixi.js");
|
|
1467
1468
|
var BMFONT_PREFIX = "__expo_bmfont_";
|
|
1468
1469
|
var bitmapFontRegistry = /* @__PURE__ */ new Map();
|
|
@@ -1472,6 +1473,57 @@ function registerBitmapFont(xmlModuleId, pageModuleIds) {
|
|
|
1472
1473
|
bitmapFontRegistry.set(key, { xmlModuleId, pageModuleIds });
|
|
1473
1474
|
return key;
|
|
1474
1475
|
}
|
|
1476
|
+
async function readTextFromUri(uri) {
|
|
1477
|
+
console.log(`[bmfont] readTextFromUri: ${uri}`);
|
|
1478
|
+
if (uri.startsWith("file:///android_asset/") || uri.startsWith("http://") || uri.startsWith("https://")) {
|
|
1479
|
+
console.log(`[bmfont] Using fetch for: ${uri}`);
|
|
1480
|
+
const response = await fetch(uri);
|
|
1481
|
+
if (!response.ok) throw new Error(`HTTP ${response.status} for ${uri}`);
|
|
1482
|
+
const text = await response.text();
|
|
1483
|
+
console.log(`[bmfont] Fetch OK, length: ${text.length}`);
|
|
1484
|
+
return text;
|
|
1485
|
+
}
|
|
1486
|
+
if (uri.startsWith("file://") || uri.startsWith("/")) {
|
|
1487
|
+
const fileUri = uri.startsWith("/") ? `file://${uri}` : uri;
|
|
1488
|
+
console.log(`[bmfont] Using File API for: ${fileUri}`);
|
|
1489
|
+
const file = new import_expo_file_system.File(fileUri);
|
|
1490
|
+
const content = await file.text();
|
|
1491
|
+
console.log(`[bmfont] File read OK, length: ${content.length}`);
|
|
1492
|
+
return content;
|
|
1493
|
+
}
|
|
1494
|
+
throw new Error(`Unsupported URI scheme: ${uri.substring(0, 30)}`);
|
|
1495
|
+
}
|
|
1496
|
+
function getMetroBaseUrl() {
|
|
1497
|
+
try {
|
|
1498
|
+
const scriptURL = import_react_native2.NativeModules.SourceCode?.getConstants?.()?.scriptURL ?? import_react_native2.NativeModules.SourceCode?.scriptURL;
|
|
1499
|
+
if (scriptURL) {
|
|
1500
|
+
const match = scriptURL.match(/^(https?:\/\/[^/]+)/);
|
|
1501
|
+
if (match) return match[1];
|
|
1502
|
+
}
|
|
1503
|
+
} catch {
|
|
1504
|
+
}
|
|
1505
|
+
return null;
|
|
1506
|
+
}
|
|
1507
|
+
function getAndroidAssetCandidates(asset) {
|
|
1508
|
+
const candidates = [];
|
|
1509
|
+
const name = asset.name;
|
|
1510
|
+
const type = asset.type;
|
|
1511
|
+
const hash = asset.hash;
|
|
1512
|
+
const metroBase = getMetroBaseUrl();
|
|
1513
|
+
if (metroBase && name && type) {
|
|
1514
|
+
candidates.push(`${metroBase}/assets/assets/fonts/${name}.${type}?platform=android`);
|
|
1515
|
+
candidates.push(`${metroBase}/assets/fonts/${name}.${type}?platform=android`);
|
|
1516
|
+
}
|
|
1517
|
+
if (name && type) {
|
|
1518
|
+
candidates.push(`file:///android_asset/assets/fonts/${name}.${type}`);
|
|
1519
|
+
candidates.push(`file:///android_asset/fonts/${name}.${type}`);
|
|
1520
|
+
candidates.push(`file:///android_asset/${name}.${type}`);
|
|
1521
|
+
}
|
|
1522
|
+
if (hash && type) {
|
|
1523
|
+
candidates.push(`file:///android_asset/${hash}.${type}`);
|
|
1524
|
+
}
|
|
1525
|
+
return candidates;
|
|
1526
|
+
}
|
|
1475
1527
|
var loadExpoBitmapFont = {
|
|
1476
1528
|
extension: {
|
|
1477
1529
|
type: import_pixi3.ExtensionType.LoadParser,
|
|
@@ -1492,20 +1544,61 @@ var loadExpoBitmapFont = {
|
|
|
1492
1544
|
throw new Error(`[loadExpoBitmapFont] No registered bitmap font for key: ${url}`);
|
|
1493
1545
|
}
|
|
1494
1546
|
const expoAsset = import_expo_asset3.Asset.fromModule(entry.xmlModuleId);
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1547
|
+
const errors = [];
|
|
1548
|
+
console.log(`[bmfont] === Loading ${url} ===`);
|
|
1549
|
+
console.log(`[bmfont] moduleId: ${entry.xmlModuleId}`);
|
|
1550
|
+
console.log(`[bmfont] name: ${expoAsset.name}`);
|
|
1551
|
+
console.log(`[bmfont] type: ${expoAsset.type}`);
|
|
1552
|
+
console.log(`[bmfont] hash: ${expoAsset.hash}`);
|
|
1553
|
+
console.log(`[bmfont] localUri: ${expoAsset.localUri}`);
|
|
1554
|
+
console.log(`[bmfont] uri: ${expoAsset.uri}`);
|
|
1555
|
+
console.log(`[bmfont] downloaded: ${expoAsset.downloaded}`);
|
|
1556
|
+
console.log(`[bmfont] Platform: ${import_react_native2.Platform.OS}`);
|
|
1557
|
+
if (expoAsset.localUri) {
|
|
1558
|
+
console.log(`[bmfont] Strategy 1: localUri`);
|
|
1559
|
+
try {
|
|
1560
|
+
return await readTextFromUri(expoAsset.localUri);
|
|
1561
|
+
} catch (e) {
|
|
1562
|
+
console.log(`[bmfont] Strategy 1 FAILED: ${e.message}`);
|
|
1563
|
+
errors.push(`localUri: ${e.message}`);
|
|
1564
|
+
}
|
|
1499
1565
|
}
|
|
1500
|
-
if (
|
|
1501
|
-
|
|
1566
|
+
if (import_react_native2.Platform.OS === "android") {
|
|
1567
|
+
const candidates = getAndroidAssetCandidates(expoAsset);
|
|
1568
|
+
console.log(`[bmfont] Strategy 2: trying ${candidates.length} android_asset candidates`);
|
|
1569
|
+
console.log(`[bmfont] httpServerLocation: ${expoAsset.httpServerLocation}`);
|
|
1570
|
+
for (const candidate of candidates) {
|
|
1571
|
+
try {
|
|
1572
|
+
console.log(`[bmfont] Trying: ${candidate}`);
|
|
1573
|
+
const content = await readTextFromUri(candidate);
|
|
1574
|
+
console.log(`[bmfont] SUCCESS with: ${candidate}`);
|
|
1575
|
+
return content;
|
|
1576
|
+
} catch (e) {
|
|
1577
|
+
console.log(`[bmfont] Failed: ${candidate} \u2192 ${e.message}`);
|
|
1578
|
+
}
|
|
1579
|
+
}
|
|
1580
|
+
errors.push(`android_asset: all ${candidates.length} candidates failed`);
|
|
1502
1581
|
}
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
console.log(`[
|
|
1582
|
+
console.log(`[bmfont] Strategy 3: downloadAsync`);
|
|
1583
|
+
try {
|
|
1584
|
+
await expoAsset.downloadAsync();
|
|
1585
|
+
console.log(`[bmfont] downloadAsync OK, localUri: ${expoAsset.localUri}`);
|
|
1586
|
+
const uri = expoAsset.localUri || expoAsset.uri;
|
|
1587
|
+
if (uri) return await readTextFromUri(uri);
|
|
1588
|
+
} catch (e) {
|
|
1589
|
+
console.log(`[bmfont] Strategy 3 FAILED: ${e.message}`);
|
|
1590
|
+
errors.push(`downloadAsync: ${e.message}`);
|
|
1507
1591
|
}
|
|
1508
|
-
|
|
1592
|
+
if (expoAsset.uri) {
|
|
1593
|
+
console.log(`[bmfont] Strategy 4: uri \u2192 ${expoAsset.uri}`);
|
|
1594
|
+
try {
|
|
1595
|
+
return await readTextFromUri(expoAsset.uri);
|
|
1596
|
+
} catch (e) {
|
|
1597
|
+
console.log(`[bmfont] Strategy 4 FAILED: ${e.message}`);
|
|
1598
|
+
errors.push(`uri(${expoAsset.uri.substring(0, 50)}): ${e.message}`);
|
|
1599
|
+
}
|
|
1600
|
+
}
|
|
1601
|
+
throw new Error(`[loadExpoBitmapFont] All strategies failed for ${url}: ${errors.join("; ")}`);
|
|
1509
1602
|
},
|
|
1510
1603
|
async parse(asset, data, loader) {
|
|
1511
1604
|
if (__DEV__) console.log(`[loadExpoBitmapFont] parse() called, src=${data.src}`);
|
|
@@ -1611,16 +1704,16 @@ function createExpoManifest(manifest) {
|
|
|
1611
1704
|
|
|
1612
1705
|
// src/components/PixiView.tsx
|
|
1613
1706
|
var import_react = require("react");
|
|
1614
|
-
var
|
|
1707
|
+
var import_react_native4 = require("react-native");
|
|
1615
1708
|
var import_expo_gl = require("expo-gl");
|
|
1616
1709
|
var import_pixi4 = require("pixi.js");
|
|
1617
1710
|
|
|
1618
1711
|
// src/utils/touchEventBridge.ts
|
|
1619
|
-
var
|
|
1712
|
+
var import_react_native3 = require("react-native");
|
|
1620
1713
|
var touchPositions = /* @__PURE__ */ new Map();
|
|
1621
1714
|
function createPointerEvent(touch, eventType, options, isPrimary, nativeEvent) {
|
|
1622
1715
|
const { canvas, offsetX = 0, offsetY = 0 } = options;
|
|
1623
|
-
const ratio =
|
|
1716
|
+
const ratio = import_react_native3.PixelRatio.get();
|
|
1624
1717
|
const x = (touch.locationX ?? touch.pageX - offsetX) * ratio;
|
|
1625
1718
|
const y = (touch.locationY ?? touch.pageY - offsetY) * ratio;
|
|
1626
1719
|
const prevPos = touchPositions.get(touch.identifier);
|
|
@@ -1838,7 +1931,7 @@ var PixiView = (0, import_react.forwardRef)((props, ref) => {
|
|
|
1838
1931
|
const { width, height } = event.nativeEvent.layout;
|
|
1839
1932
|
layoutRef.current = { width, height };
|
|
1840
1933
|
if (appRef.current) {
|
|
1841
|
-
const res = resolution ||
|
|
1934
|
+
const res = resolution || import_react_native4.PixelRatio.get();
|
|
1842
1935
|
appRef.current.renderer.resize(width * res, height * res);
|
|
1843
1936
|
applyDesignScale(appRef.current, width, height);
|
|
1844
1937
|
}
|
|
@@ -1947,7 +2040,7 @@ var PixiView = (0, import_react.forwardRef)((props, ref) => {
|
|
|
1947
2040
|
const handleContextCreate = (0, import_react.useCallback)(
|
|
1948
2041
|
async (gl) => {
|
|
1949
2042
|
glRef.current = gl;
|
|
1950
|
-
const pixelRatio =
|
|
2043
|
+
const pixelRatio = import_react_native4.PixelRatio.get();
|
|
1951
2044
|
const { width: layoutWidth, height: layoutHeight } = layoutRef.current;
|
|
1952
2045
|
const logicalWidth = layoutWidth || gl.drawingBufferWidth / pixelRatio;
|
|
1953
2046
|
const logicalHeight = layoutHeight || gl.drawingBufferHeight / pixelRatio;
|
|
@@ -2052,7 +2145,7 @@ var PixiView = (0, import_react.forwardRef)((props, ref) => {
|
|
|
2052
2145
|
onResponderTerminationRequest: () => true
|
|
2053
2146
|
} : {};
|
|
2054
2147
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
2055
|
-
|
|
2148
|
+
import_react_native4.View,
|
|
2056
2149
|
{
|
|
2057
2150
|
ref: containerRef,
|
|
2058
2151
|
style: [styles.container, style],
|
|
@@ -2063,7 +2156,7 @@ var PixiView = (0, import_react.forwardRef)((props, ref) => {
|
|
|
2063
2156
|
);
|
|
2064
2157
|
});
|
|
2065
2158
|
PixiView.displayName = "PixiView";
|
|
2066
|
-
var styles =
|
|
2159
|
+
var styles = import_react_native4.StyleSheet.create({
|
|
2067
2160
|
container: {
|
|
2068
2161
|
flex: 1,
|
|
2069
2162
|
overflow: "hidden"
|
package/dist/index.mjs
CHANGED
|
@@ -1371,6 +1371,7 @@ var loadExpoFont = {
|
|
|
1371
1371
|
// src/adapter/loadExpoBitmapFont.ts
|
|
1372
1372
|
import { Asset as Asset3 } from "expo-asset";
|
|
1373
1373
|
import { File } from "expo-file-system";
|
|
1374
|
+
import { Platform, NativeModules } from "react-native";
|
|
1374
1375
|
import {
|
|
1375
1376
|
ExtensionType as ExtensionType3,
|
|
1376
1377
|
LoaderParserPriority as LoaderParserPriority2,
|
|
@@ -1386,6 +1387,57 @@ function registerBitmapFont(xmlModuleId, pageModuleIds) {
|
|
|
1386
1387
|
bitmapFontRegistry.set(key, { xmlModuleId, pageModuleIds });
|
|
1387
1388
|
return key;
|
|
1388
1389
|
}
|
|
1390
|
+
async function readTextFromUri(uri) {
|
|
1391
|
+
console.log(`[bmfont] readTextFromUri: ${uri}`);
|
|
1392
|
+
if (uri.startsWith("file:///android_asset/") || uri.startsWith("http://") || uri.startsWith("https://")) {
|
|
1393
|
+
console.log(`[bmfont] Using fetch for: ${uri}`);
|
|
1394
|
+
const response = await fetch(uri);
|
|
1395
|
+
if (!response.ok) throw new Error(`HTTP ${response.status} for ${uri}`);
|
|
1396
|
+
const text = await response.text();
|
|
1397
|
+
console.log(`[bmfont] Fetch OK, length: ${text.length}`);
|
|
1398
|
+
return text;
|
|
1399
|
+
}
|
|
1400
|
+
if (uri.startsWith("file://") || uri.startsWith("/")) {
|
|
1401
|
+
const fileUri = uri.startsWith("/") ? `file://${uri}` : uri;
|
|
1402
|
+
console.log(`[bmfont] Using File API for: ${fileUri}`);
|
|
1403
|
+
const file = new File(fileUri);
|
|
1404
|
+
const content = await file.text();
|
|
1405
|
+
console.log(`[bmfont] File read OK, length: ${content.length}`);
|
|
1406
|
+
return content;
|
|
1407
|
+
}
|
|
1408
|
+
throw new Error(`Unsupported URI scheme: ${uri.substring(0, 30)}`);
|
|
1409
|
+
}
|
|
1410
|
+
function getMetroBaseUrl() {
|
|
1411
|
+
try {
|
|
1412
|
+
const scriptURL = NativeModules.SourceCode?.getConstants?.()?.scriptURL ?? NativeModules.SourceCode?.scriptURL;
|
|
1413
|
+
if (scriptURL) {
|
|
1414
|
+
const match = scriptURL.match(/^(https?:\/\/[^/]+)/);
|
|
1415
|
+
if (match) return match[1];
|
|
1416
|
+
}
|
|
1417
|
+
} catch {
|
|
1418
|
+
}
|
|
1419
|
+
return null;
|
|
1420
|
+
}
|
|
1421
|
+
function getAndroidAssetCandidates(asset) {
|
|
1422
|
+
const candidates = [];
|
|
1423
|
+
const name = asset.name;
|
|
1424
|
+
const type = asset.type;
|
|
1425
|
+
const hash = asset.hash;
|
|
1426
|
+
const metroBase = getMetroBaseUrl();
|
|
1427
|
+
if (metroBase && name && type) {
|
|
1428
|
+
candidates.push(`${metroBase}/assets/assets/fonts/${name}.${type}?platform=android`);
|
|
1429
|
+
candidates.push(`${metroBase}/assets/fonts/${name}.${type}?platform=android`);
|
|
1430
|
+
}
|
|
1431
|
+
if (name && type) {
|
|
1432
|
+
candidates.push(`file:///android_asset/assets/fonts/${name}.${type}`);
|
|
1433
|
+
candidates.push(`file:///android_asset/fonts/${name}.${type}`);
|
|
1434
|
+
candidates.push(`file:///android_asset/${name}.${type}`);
|
|
1435
|
+
}
|
|
1436
|
+
if (hash && type) {
|
|
1437
|
+
candidates.push(`file:///android_asset/${hash}.${type}`);
|
|
1438
|
+
}
|
|
1439
|
+
return candidates;
|
|
1440
|
+
}
|
|
1389
1441
|
var loadExpoBitmapFont = {
|
|
1390
1442
|
extension: {
|
|
1391
1443
|
type: ExtensionType3.LoadParser,
|
|
@@ -1406,20 +1458,61 @@ var loadExpoBitmapFont = {
|
|
|
1406
1458
|
throw new Error(`[loadExpoBitmapFont] No registered bitmap font for key: ${url}`);
|
|
1407
1459
|
}
|
|
1408
1460
|
const expoAsset = Asset3.fromModule(entry.xmlModuleId);
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1461
|
+
const errors = [];
|
|
1462
|
+
console.log(`[bmfont] === Loading ${url} ===`);
|
|
1463
|
+
console.log(`[bmfont] moduleId: ${entry.xmlModuleId}`);
|
|
1464
|
+
console.log(`[bmfont] name: ${expoAsset.name}`);
|
|
1465
|
+
console.log(`[bmfont] type: ${expoAsset.type}`);
|
|
1466
|
+
console.log(`[bmfont] hash: ${expoAsset.hash}`);
|
|
1467
|
+
console.log(`[bmfont] localUri: ${expoAsset.localUri}`);
|
|
1468
|
+
console.log(`[bmfont] uri: ${expoAsset.uri}`);
|
|
1469
|
+
console.log(`[bmfont] downloaded: ${expoAsset.downloaded}`);
|
|
1470
|
+
console.log(`[bmfont] Platform: ${Platform.OS}`);
|
|
1471
|
+
if (expoAsset.localUri) {
|
|
1472
|
+
console.log(`[bmfont] Strategy 1: localUri`);
|
|
1473
|
+
try {
|
|
1474
|
+
return await readTextFromUri(expoAsset.localUri);
|
|
1475
|
+
} catch (e) {
|
|
1476
|
+
console.log(`[bmfont] Strategy 1 FAILED: ${e.message}`);
|
|
1477
|
+
errors.push(`localUri: ${e.message}`);
|
|
1478
|
+
}
|
|
1413
1479
|
}
|
|
1414
|
-
if (
|
|
1415
|
-
|
|
1480
|
+
if (Platform.OS === "android") {
|
|
1481
|
+
const candidates = getAndroidAssetCandidates(expoAsset);
|
|
1482
|
+
console.log(`[bmfont] Strategy 2: trying ${candidates.length} android_asset candidates`);
|
|
1483
|
+
console.log(`[bmfont] httpServerLocation: ${expoAsset.httpServerLocation}`);
|
|
1484
|
+
for (const candidate of candidates) {
|
|
1485
|
+
try {
|
|
1486
|
+
console.log(`[bmfont] Trying: ${candidate}`);
|
|
1487
|
+
const content = await readTextFromUri(candidate);
|
|
1488
|
+
console.log(`[bmfont] SUCCESS with: ${candidate}`);
|
|
1489
|
+
return content;
|
|
1490
|
+
} catch (e) {
|
|
1491
|
+
console.log(`[bmfont] Failed: ${candidate} \u2192 ${e.message}`);
|
|
1492
|
+
}
|
|
1493
|
+
}
|
|
1494
|
+
errors.push(`android_asset: all ${candidates.length} candidates failed`);
|
|
1416
1495
|
}
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
console.log(`[
|
|
1496
|
+
console.log(`[bmfont] Strategy 3: downloadAsync`);
|
|
1497
|
+
try {
|
|
1498
|
+
await expoAsset.downloadAsync();
|
|
1499
|
+
console.log(`[bmfont] downloadAsync OK, localUri: ${expoAsset.localUri}`);
|
|
1500
|
+
const uri = expoAsset.localUri || expoAsset.uri;
|
|
1501
|
+
if (uri) return await readTextFromUri(uri);
|
|
1502
|
+
} catch (e) {
|
|
1503
|
+
console.log(`[bmfont] Strategy 3 FAILED: ${e.message}`);
|
|
1504
|
+
errors.push(`downloadAsync: ${e.message}`);
|
|
1421
1505
|
}
|
|
1422
|
-
|
|
1506
|
+
if (expoAsset.uri) {
|
|
1507
|
+
console.log(`[bmfont] Strategy 4: uri \u2192 ${expoAsset.uri}`);
|
|
1508
|
+
try {
|
|
1509
|
+
return await readTextFromUri(expoAsset.uri);
|
|
1510
|
+
} catch (e) {
|
|
1511
|
+
console.log(`[bmfont] Strategy 4 FAILED: ${e.message}`);
|
|
1512
|
+
errors.push(`uri(${expoAsset.uri.substring(0, 50)}): ${e.message}`);
|
|
1513
|
+
}
|
|
1514
|
+
}
|
|
1515
|
+
throw new Error(`[loadExpoBitmapFont] All strategies failed for ${url}: ${errors.join("; ")}`);
|
|
1423
1516
|
},
|
|
1424
1517
|
async parse(asset, data, loader) {
|
|
1425
1518
|
if (__DEV__) console.log(`[loadExpoBitmapFont] parse() called, src=${data.src}`);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@penabt/pixi-expo",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.1",
|
|
4
4
|
"description": "PixiJS v8 adapter for React Native Expo. Enables hardware-accelerated 2D graphics using expo-gl WebGL context.",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"module": "./dist/index.mjs",
|
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
|
|
17
17
|
import { Asset } from 'expo-asset';
|
|
18
18
|
import { File } from 'expo-file-system';
|
|
19
|
+
import { Platform, NativeModules } from 'react-native';
|
|
19
20
|
import {
|
|
20
21
|
ExtensionType,
|
|
21
22
|
LoaderParserPriority,
|
|
@@ -90,6 +91,82 @@ export function registerBitmapFont(xmlModuleId: number, pageModuleIds: number[])
|
|
|
90
91
|
* registerBitmapFont(). Runs at High priority to intercept before
|
|
91
92
|
* PixiJS's built-in loadBitmapFont (which can't handle module IDs).
|
|
92
93
|
*/
|
|
94
|
+
/** Read text from a URI using the most appropriate method */
|
|
95
|
+
async function readTextFromUri(uri: string): Promise<string> {
|
|
96
|
+
console.log(`[bmfont] readTextFromUri: ${uri}`);
|
|
97
|
+
|
|
98
|
+
// android_asset or http(s) → use fetch (RN's fetch supports file:///android_asset/)
|
|
99
|
+
if (uri.startsWith('file:///android_asset/') || uri.startsWith('http://') || uri.startsWith('https://')) {
|
|
100
|
+
console.log(`[bmfont] Using fetch for: ${uri}`);
|
|
101
|
+
const response = await fetch(uri);
|
|
102
|
+
if (!response.ok) throw new Error(`HTTP ${response.status} for ${uri}`);
|
|
103
|
+
const text = await response.text();
|
|
104
|
+
console.log(`[bmfont] Fetch OK, length: ${text.length}`);
|
|
105
|
+
return text;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// file:// or absolute path → use expo-file-system File API
|
|
109
|
+
if (uri.startsWith('file://') || uri.startsWith('/')) {
|
|
110
|
+
const fileUri = uri.startsWith('/') ? `file://${uri}` : uri;
|
|
111
|
+
console.log(`[bmfont] Using File API for: ${fileUri}`);
|
|
112
|
+
const file = new File(fileUri);
|
|
113
|
+
const content = await file.text();
|
|
114
|
+
console.log(`[bmfont] File read OK, length: ${content.length}`);
|
|
115
|
+
return content;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
throw new Error(`Unsupported URI scheme: ${uri.substring(0, 30)}`);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Get Metro dev server base URL from the JS bundle source URL.
|
|
123
|
+
* Returns null if not available (e.g., production build).
|
|
124
|
+
*/
|
|
125
|
+
function getMetroBaseUrl(): string | null {
|
|
126
|
+
try {
|
|
127
|
+
const scriptURL: string | undefined =
|
|
128
|
+
NativeModules.SourceCode?.getConstants?.()?.scriptURL ??
|
|
129
|
+
(NativeModules.SourceCode as any)?.scriptURL;
|
|
130
|
+
if (scriptURL) {
|
|
131
|
+
// scriptURL is like "http://192.168.1.105:8081/index.bundle?platform=android&..."
|
|
132
|
+
const match = scriptURL.match(/^(https?:\/\/[^/]+)/);
|
|
133
|
+
if (match) return match[1];
|
|
134
|
+
}
|
|
135
|
+
} catch {}
|
|
136
|
+
return null;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Generate candidate URIs for reading a font asset on Android.
|
|
141
|
+
* Includes both Metro HTTP URLs (dev) and APK asset paths (prod).
|
|
142
|
+
*/
|
|
143
|
+
function getAndroidAssetCandidates(asset: Asset): string[] {
|
|
144
|
+
const candidates: string[] = [];
|
|
145
|
+
const name = asset.name;
|
|
146
|
+
const type = asset.type;
|
|
147
|
+
const hash = asset.hash;
|
|
148
|
+
|
|
149
|
+
// In dev builds, Metro serves assets over HTTP
|
|
150
|
+
const metroBase = getMetroBaseUrl();
|
|
151
|
+
if (metroBase && name && type) {
|
|
152
|
+
// Metro asset URL patterns
|
|
153
|
+
candidates.push(`${metroBase}/assets/assets/fonts/${name}.${type}?platform=android`);
|
|
154
|
+
candidates.push(`${metroBase}/assets/fonts/${name}.${type}?platform=android`);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// file:///android_asset/ patterns for production builds
|
|
158
|
+
if (name && type) {
|
|
159
|
+
candidates.push(`file:///android_asset/assets/fonts/${name}.${type}`);
|
|
160
|
+
candidates.push(`file:///android_asset/fonts/${name}.${type}`);
|
|
161
|
+
candidates.push(`file:///android_asset/${name}.${type}`);
|
|
162
|
+
}
|
|
163
|
+
if (hash && type) {
|
|
164
|
+
candidates.push(`file:///android_asset/${hash}.${type}`);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
return candidates;
|
|
168
|
+
}
|
|
169
|
+
|
|
93
170
|
export const loadExpoBitmapFont = {
|
|
94
171
|
extension: {
|
|
95
172
|
type: ExtensionType.LoadParser,
|
|
@@ -114,29 +191,63 @@ export const loadExpoBitmapFont = {
|
|
|
114
191
|
throw new Error(`[loadExpoBitmapFont] No registered bitmap font for key: ${url}`);
|
|
115
192
|
}
|
|
116
193
|
|
|
117
|
-
// Resolve XML module ID to local URI via expo-asset
|
|
118
194
|
const expoAsset = Asset.fromModule(entry.xmlModuleId);
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
195
|
+
const errors: string[] = [];
|
|
196
|
+
|
|
197
|
+
console.log(`[bmfont] === Loading ${url} ===`);
|
|
198
|
+
console.log(`[bmfont] moduleId: ${entry.xmlModuleId}`);
|
|
199
|
+
console.log(`[bmfont] name: ${expoAsset.name}`);
|
|
200
|
+
console.log(`[bmfont] type: ${expoAsset.type}`);
|
|
201
|
+
console.log(`[bmfont] hash: ${expoAsset.hash}`);
|
|
202
|
+
console.log(`[bmfont] localUri: ${expoAsset.localUri}`);
|
|
203
|
+
console.log(`[bmfont] uri: ${expoAsset.uri}`);
|
|
204
|
+
console.log(`[bmfont] downloaded: ${expoAsset.downloaded}`);
|
|
205
|
+
console.log(`[bmfont] Platform: ${Platform.OS}`);
|
|
206
|
+
|
|
207
|
+
// Strategy 1: localUri already available (iOS native builds)
|
|
208
|
+
if (expoAsset.localUri) {
|
|
209
|
+
console.log(`[bmfont] Strategy 1: localUri`);
|
|
210
|
+
try {
|
|
211
|
+
return await readTextFromUri(expoAsset.localUri);
|
|
212
|
+
} catch (e: any) { console.log(`[bmfont] Strategy 1 FAILED: ${e.message}`); errors.push(`localUri: ${e.message}`); }
|
|
124
213
|
}
|
|
125
214
|
|
|
126
|
-
|
|
127
|
-
|
|
215
|
+
// Strategy 2: Android bundled asset — try multiple path patterns
|
|
216
|
+
if (Platform.OS === 'android') {
|
|
217
|
+
const candidates = getAndroidAssetCandidates(expoAsset);
|
|
218
|
+
console.log(`[bmfont] Strategy 2: trying ${candidates.length} android_asset candidates`);
|
|
219
|
+
console.log(`[bmfont] httpServerLocation: ${(expoAsset as any).httpServerLocation}`);
|
|
220
|
+
for (const candidate of candidates) {
|
|
221
|
+
try {
|
|
222
|
+
console.log(`[bmfont] Trying: ${candidate}`);
|
|
223
|
+
const content = await readTextFromUri(candidate);
|
|
224
|
+
console.log(`[bmfont] SUCCESS with: ${candidate}`);
|
|
225
|
+
return content;
|
|
226
|
+
} catch (e: any) {
|
|
227
|
+
console.log(`[bmfont] Failed: ${candidate} → ${e.message}`);
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
errors.push(`android_asset: all ${candidates.length} candidates failed`);
|
|
128
231
|
}
|
|
129
232
|
|
|
130
|
-
//
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
233
|
+
// Strategy 3: downloadAsync → localUri (works in Expo Go / dev client)
|
|
234
|
+
console.log(`[bmfont] Strategy 3: downloadAsync`);
|
|
235
|
+
try {
|
|
236
|
+
await expoAsset.downloadAsync();
|
|
237
|
+
console.log(`[bmfont] downloadAsync OK, localUri: ${expoAsset.localUri}`);
|
|
238
|
+
const uri = expoAsset.localUri || expoAsset.uri;
|
|
239
|
+
if (uri) return await readTextFromUri(uri);
|
|
240
|
+
} catch (e: any) { console.log(`[bmfont] Strategy 3 FAILED: ${e.message}`); errors.push(`downloadAsync: ${e.message}`); }
|
|
241
|
+
|
|
242
|
+
// Strategy 4: expo-asset uri (may be HTTP in dev, or asset:// scheme)
|
|
243
|
+
if (expoAsset.uri) {
|
|
244
|
+
console.log(`[bmfont] Strategy 4: uri → ${expoAsset.uri}`);
|
|
245
|
+
try {
|
|
246
|
+
return await readTextFromUri(expoAsset.uri);
|
|
247
|
+
} catch (e: any) { console.log(`[bmfont] Strategy 4 FAILED: ${e.message}`); errors.push(`uri(${expoAsset.uri.substring(0, 50)}): ${e.message}`); }
|
|
137
248
|
}
|
|
138
249
|
|
|
139
|
-
|
|
250
|
+
throw new Error(`[loadExpoBitmapFont] All strategies failed for ${url}: ${errors.join('; ')}`);
|
|
140
251
|
},
|
|
141
252
|
|
|
142
253
|
async parse(asset: string, data: ResolvedAsset, loader: Loader): Promise<any> {
|
package/src/index.ts
CHANGED
|
@@ -180,7 +180,7 @@ export type { PixiViewProps, PixiViewHandle } from './components/PixiView';
|
|
|
180
180
|
|
|
181
181
|
// =============================================================================
|
|
182
182
|
// EXPORTS: DESIGN RESOLUTION
|
|
183
|
-
//
|
|
183
|
+
// Design resolution utilities for fixed coordinate systems.
|
|
184
184
|
// =============================================================================
|
|
185
185
|
|
|
186
186
|
export { calculateDesignScale, calculateDesignSafeArea } from './utils/designResolution';
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Design resolution scaling utilities.
|
|
3
3
|
*
|
|
4
|
-
* Provides
|
|
4
|
+
* Provides design resolution support: define a fixed logical
|
|
5
5
|
* size (e.g. 768×1024) and the library automatically scales the PixiJS stage
|
|
6
6
|
* to fit the device screen.
|
|
7
7
|
*/
|