@@ -2,7 +2,9 @@
|
|
2
2
|
|
3
3
|
let didLogCanNotFindConfig = false;
|
4
4
|
|
5
|
-
/**
|
5
|
+
/** the codegen meta file
|
6
|
+
* @returns {import("../types/needleConfig").needleMeta | null}
|
7
|
+
*/
|
6
8
|
export async function loadConfig(path) {
|
7
9
|
try {
|
8
10
|
// First try to get the path from the config
|
@@ -19,7 +21,7 @@
|
|
19
21
|
if (existsSync(path)) {
|
20
22
|
const text = readFileSync(path, 'utf8');
|
21
23
|
if (!text) return null;
|
22
|
-
/**@type {import("../types/needleConfig").
|
24
|
+
/**@type {import("../types/needleConfig").needleMeta} */
|
23
25
|
const meta = JSON.parse(text);
|
24
26
|
return meta;
|
25
27
|
}
|
@@ -38,7 +40,9 @@
|
|
38
40
|
}
|
39
41
|
}
|
40
42
|
|
41
|
-
/** get the needle.config.json
|
43
|
+
/** get the needle.config.json
|
44
|
+
* @returns {import("../types/needleConfig").needleConfig | null}
|
45
|
+
*/
|
42
46
|
export function tryLoadProjectConfig() {
|
43
47
|
try {
|
44
48
|
const root = process.cwd();
|
@@ -64,3 +68,7 @@
|
|
64
68
|
return "assets";
|
65
69
|
}
|
66
70
|
|
71
|
+
export function getOutputDirectory() {
|
72
|
+
const projectConfig = tryLoadProjectConfig();
|
73
|
+
return process.cwd() + "/" + (projectConfig?.buildDirectory || "dist");
|
74
|
+
}
|
@@ -37,6 +37,9 @@
|
|
37
37
|
import { needleDependencyWatcher } from "./dependency-watcher.js";
|
38
38
|
export { needleDependencyWatcher } from "./dependency-watcher.js";
|
39
39
|
|
40
|
+
import { needleFacebookInstantGames } from "./facebook-instant-games.js";
|
41
|
+
export { needleFacebookInstantGames } from "./facebook-instant-games.js";
|
42
|
+
|
40
43
|
import { vite_4_4_hack } from "./vite-4.4-hack.js";
|
41
44
|
|
42
45
|
|
@@ -68,7 +71,8 @@
|
|
68
71
|
needleDrop(command, config, userSettings),
|
69
72
|
needlePeerjs(command, config, userSettings),
|
70
73
|
needleDependencyWatcher(command, config, userSettings),
|
71
|
-
vite_4_4_hack(command, config, userSettings)
|
74
|
+
vite_4_4_hack(command, config, userSettings),
|
75
|
+
needleFacebookInstantGames(command, config, userSettings),
|
72
76
|
];
|
73
77
|
array.push(await editorConnection(command, config, userSettings, array));
|
74
78
|
return array;
|
@@ -456,7 +456,6 @@
|
|
456
456
|
public get world(): World | undefined { return this._world };
|
457
457
|
|
458
458
|
private _tempPosition: Vector3 = new Vector3();
|
459
|
-
private _tempPosition2: Vector3 = new Vector3();
|
460
459
|
private _tempQuaternion: Quaternion = new Quaternion();
|
461
460
|
private _tempScale: Vector3 = new Vector3();
|
462
461
|
private _tempMatrix: Matrix4 = new Matrix4();
|
@@ -782,12 +781,10 @@
|
|
782
781
|
|
783
782
|
if (!this.world) throw new Error("Physics world not initialized");
|
784
783
|
let rigidBody: RigidBody | null = null;
|
785
|
-
let useExplicitMassProperties = false;
|
786
784
|
|
787
785
|
if (collider.attachedRigidbody) {
|
788
786
|
const rb = collider.attachedRigidbody;
|
789
787
|
rigidBody = rb[$bodyKey];
|
790
|
-
useExplicitMassProperties = rb.autoMass === false;
|
791
788
|
if (!rigidBody) {
|
792
789
|
const kinematic = rb.isKinematic && !debugColliderPlacement;
|
793
790
|
if (debugPhysics)
|
@@ -1090,18 +1087,25 @@
|
|
1090
1087
|
// body.setBodyType(bodyType);
|
1091
1088
|
}
|
1092
1089
|
|
1090
|
+
private readonly _tempCenterPos: Vector3 = new Vector3();
|
1091
|
+
private readonly _tempCenterVec:Vector3 = new Vector3();
|
1092
|
+
private readonly _tempCenterQuaternion:Quaternion = new Quaternion();
|
1093
1093
|
private tryApplyCenter(collider: ICollider, targetVector: Vector3) {
|
1094
1094
|
const center = collider.center;
|
1095
1095
|
if (center && collider.gameObject) {
|
1096
|
-
|
1097
|
-
|
1098
|
-
|
1099
|
-
|
1100
|
-
|
1101
|
-
|
1102
|
-
|
1103
|
-
|
1104
|
-
|
1096
|
+
if (center.x !== 0 || center.y !== 0 || center.z !== 0) {
|
1097
|
+
// TODO: fix export of center in editor integrations so we dont have to flip here
|
1098
|
+
this._tempCenterPos.x = -center.x;
|
1099
|
+
this._tempCenterPos.y = center.y;
|
1100
|
+
this._tempCenterPos.z = center.z;
|
1101
|
+
getWorldScale(collider.gameObject, this._tempCenterVec);
|
1102
|
+
this._tempCenterPos.multiply(this._tempCenterVec);
|
1103
|
+
const rot = getWorldQuaternion(collider.gameObject, this._tempCenterQuaternion);
|
1104
|
+
this._tempCenterPos.applyQuaternion(rot);
|
1105
|
+
targetVector.x += this._tempCenterPos.x;
|
1106
|
+
targetVector.y += this._tempCenterPos.y;
|
1107
|
+
targetVector.z += this._tempCenterPos.z;
|
1108
|
+
}
|
1105
1109
|
}
|
1106
1110
|
}
|
1107
1111
|
|
@@ -1,4 +1,4 @@
|
|
1
|
-
export type
|
1
|
+
export type needleMeta = {
|
2
2
|
needleEditor: string | null,
|
3
3
|
meta: string | null;
|
4
4
|
absolutePath: string | null,
|
@@ -9,4 +9,14 @@
|
|
9
9
|
allowHotReload: boolean,
|
10
10
|
license: string | null,
|
11
11
|
useRapier: boolean,
|
12
|
+
}
|
13
|
+
|
14
|
+
|
15
|
+
/** The content of the needle.config.json in the project directory */
|
16
|
+
export type needleConfig = {
|
17
|
+
baseUrL?: string;
|
18
|
+
buildDirectory?: string;
|
19
|
+
assetsDirectory?: string;
|
20
|
+
scriptsDirectory?: string;
|
21
|
+
codegenDirectory?: string;
|
12
22
|
}
|
@@ -21,6 +21,7 @@
|
|
21
21
|
/** set to true to disable reload plugin */
|
22
22
|
noReload: boolean;
|
23
23
|
noCodegenTransform: boolean;
|
24
|
+
noFacebookInstantGames: boolean;
|
24
25
|
|
25
26
|
/** required for @serializable https://github.com/vitejs/vite/issues/13736 */
|
26
27
|
vite44Hack: boolean;
|
@@ -0,0 +1,100 @@
|
|
1
|
+
import { copyFile, copyFileSync, existsSync, readFileSync, writeFileSync } from 'fs';
|
2
|
+
import { getOutputDirectory } from './config.js';
|
3
|
+
|
4
|
+
const loadInstantGamesStr = `/* needle: injected to initialize facebook instant games */
|
5
|
+
let __progress = 0;
|
6
|
+
function onNeedleEngineInstantGamesLoadingProgress(_ctx, evt) {
|
7
|
+
FBInstant.setLoadingProgress(evt.detail.totalProgress01 * 100);
|
8
|
+
}
|
9
|
+
document.addEventListener("DOMContentLoaded", function () {
|
10
|
+
FBInstant.initializeAsync().then(function () { FBInstant.startGameAsync() });
|
11
|
+
});
|
12
|
+
`
|
13
|
+
|
14
|
+
// https://regex101.com/r/4ApFD9/1
|
15
|
+
function insertCallToOnProgress(html) {
|
16
|
+
const match = /(?<component><needle-engine.*?.*?>)/g.exec(html);
|
17
|
+
if (!match) {
|
18
|
+
log("!!! Could not find needle-engine component in index.html");
|
19
|
+
return html;
|
20
|
+
}
|
21
|
+
const progressEvtSignature = "progress=\"onNeedleEngineInstantGamesLoadingProgress\"";
|
22
|
+
const component = match.groups.component;
|
23
|
+
if (component.includes("progress")) return html;
|
24
|
+
log("Inserting progress callback event into needle-engine component")
|
25
|
+
const newComponent = component.replace(">", ` ${progressEvtSignature}>`);
|
26
|
+
return html.replace(component, newComponent);
|
27
|
+
}
|
28
|
+
|
29
|
+
function log(...any) {
|
30
|
+
console.log("[needle facebook instant games] ", ...any);
|
31
|
+
}
|
32
|
+
|
33
|
+
/**
|
34
|
+
* @param {{facebookInstantGames?:object}} config
|
35
|
+
* @param {import('../types').userSettings} userSettings
|
36
|
+
*/
|
37
|
+
export const needleFacebookInstantGames = (command, config, userSettings) => {
|
38
|
+
|
39
|
+
if (userSettings.noFacebookInstantGames === true) return;
|
40
|
+
|
41
|
+
// If the config is not present it means that we don't want to use fb instant games
|
42
|
+
if (!config.facebookInstantGames) return;
|
43
|
+
|
44
|
+
log("Setup Facebook Instant Games", config.facebookInstantGames);
|
45
|
+
|
46
|
+
|
47
|
+
// https://developers.facebook.com/docs/games/build/instant-games/reference/bundle-config
|
48
|
+
let bundleConfig = {}
|
49
|
+
const bundleConfigPath = process.cwd() + "/fbapp-config.json";
|
50
|
+
if (existsSync(bundleConfigPath)) {
|
51
|
+
log("Found facebook bundle config exists at " + bundleConfigPath + " ...");
|
52
|
+
bundleConfig = JSON.parse(readFileSync(bundleConfigPath, 'utf8'));
|
53
|
+
}
|
54
|
+
else {
|
55
|
+
log("No facebook bundle config exists at " + bundleConfigPath + " - will generate one now");
|
56
|
+
}
|
57
|
+
|
58
|
+
// Make sure the bundle has the required arguments:
|
59
|
+
if (!bundleConfig.instant_games) bundleConfig.instant_games = {}
|
60
|
+
const gamesConfig = bundleConfig.instant_games;
|
61
|
+
if (!gamesConfig.orientation) gamesConfig.orientation = "PORTRAIT";
|
62
|
+
if (!gamesConfig.override_web_orientation) gamesConfig.override_web_orientation = "LANDSCAPE";
|
63
|
+
if (!gamesConfig.navigation_menu_version) gamesConfig.navigation_menu_version = "NAV_BAR";
|
64
|
+
|
65
|
+
const outputDir = getOutputDirectory();
|
66
|
+
|
67
|
+
return {
|
68
|
+
name: 'needle-facebook-instant-games',
|
69
|
+
transformIndexHtml: {
|
70
|
+
enforce: 'post',
|
71
|
+
transform(html, _ctx) {
|
72
|
+
// post transform so we want to linebreak after the vite logs
|
73
|
+
console.log("\n");
|
74
|
+
|
75
|
+
writeFileSync(outputDir + "/fbapp-config.json", JSON.stringify(bundleConfig), 'utf8');
|
76
|
+
|
77
|
+
html = insertCallToOnProgress(html);
|
78
|
+
|
79
|
+
return {
|
80
|
+
html,
|
81
|
+
tags: [
|
82
|
+
{
|
83
|
+
tag: 'script',
|
84
|
+
attrs: {
|
85
|
+
src: 'https://connect.facebook.net/en_US/fbinstant.6.3.js',
|
86
|
+
async: true,
|
87
|
+
},
|
88
|
+
injectTo: 'head',
|
89
|
+
},
|
90
|
+
{
|
91
|
+
tag: 'script',
|
92
|
+
children: loadInstantGamesStr,
|
93
|
+
injectTo: 'body',
|
94
|
+
},
|
95
|
+
]
|
96
|
+
}
|
97
|
+
}
|
98
|
+
},
|
99
|
+
}
|
100
|
+
}
|