Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ESM Script base class #6367

Merged
merged 84 commits into from
Jun 18, 2024
Merged
Show file tree
Hide file tree
Changes from 54 commits
Commits
Show all changes
84 commits
Select commit Hold shift + click to select a range
73593d2
refactored script type
marklundin May 14, 2024
d69897f
Merge branch 'main' into esm-script-class
marklundin May 14, 2024
f8a555e
removed attribute check on esm scripts
marklundin May 14, 2024
e538826
linting fixes
marklundin May 14, 2024
b4bc2b2
Delete redundant scripts
marklundin May 14, 2024
642147b
Remove engines field from package-lock.json
marklundin May 14, 2024
c653cca
Fix event name in ScriptType class
marklundin May 15, 2024
c1c8393
Merge branch 'main' into esm-script-class
marklundin May 15, 2024
3cef556
Merge branch 'main' into esm-script-class
marklundin May 16, 2024
b3ef790
Add export to rawToValue function and update script schema in ScriptH…
marklundin May 17, 2024
3fa721f
linting
marklundin May 20, 2024
b3305b7
Merge branch 'main' into esm-script-class
marklundin May 20, 2024
9bee249
Update script attribute assignment in ScriptComponent
marklundin May 21, 2024
7173b9d
Merge branch 'main' into esm-script-class
marklundin May 21, 2024
eb8b603
Merge branch 'main' into esm-script-class
marklundin May 21, 2024
651af13
Merge branch 'main' into esm-script-class
marklundin May 21, 2024
b09fb70
Fix script initialization and enablement
marklundin May 23, 2024
b6bc0d5
Fix missing semicolon in ScriptRegistry class
marklundin May 23, 2024
78c6e4d
Refactor script component and handler
marklundin May 28, 2024
a3da9d5
GS reorder fix (#6410)
slimbuck May 21, 2024
d21b271
USDZ / GLTF exporter supports exposing of compressed textures on WebG…
mvaligursky May 22, 2024
471d4d2
restore default color when setting axis shape disable to false (#6587)
kpal81xd May 22, 2024
a3b652d
[Fix] Add missing exposure handling from the Neutral tonemapping (#6592)
mvaligursky May 23, 2024
6ac0179
SSAO engine example (#6586)
mvaligursky May 23, 2024
c6821ba
[BREAKING] Removed backwards compatibility for few functions (#6408)
mvaligursky May 23, 2024
7c64690
Examples app bundle optimizations (#6588)
kpal81xd May 23, 2024
8e7df13
Fix to just submitted AO example to disabled baked in occlusion maps …
mvaligursky May 23, 2024
ef587ef
added publint to ci; removed build:publish (#6363)
kpal81xd May 23, 2024
d1430e9
Fix types for calcAabb functions (#6596)
willeastcott May 23, 2024
8d0cdb0
vercel setup (#6600)
kpal81xd May 23, 2024
b16cb33
replaces slashes for windows (#6601)
kpal81xd May 23, 2024
80421cf
fixed using query params with iframe example (#6604)
kpal81xd May 23, 2024
8e85ada
New texture formats: R8 and RG8 (#6602)
mvaligursky May 23, 2024
89f0fe2
Added orthogonal facing translation to gizmo (#6607)
kpal81xd May 24, 2024
9fcc31f
set shader chunk type to record (#6621)
kpal81xd May 24, 2024
f73bd44
Gizmo example update (#6622)
kpal81xd May 24, 2024
fd252b4
Exports and types fixes (#6623)
kpal81xd May 24, 2024
c0cc2b5
added package json for linting of example modules and renamed @exampl…
kpal81xd May 24, 2024
1bc0015
PR commit (#6626)
kpal81xd May 24, 2024
6f089bd
fixed fallback options (#6628)
kpal81xd May 24, 2024
7bb07c3
fixed example types (#6634)
kpal81xd May 28, 2024
9bc5c1a
fixed selection bug (#6637)
kpal81xd May 28, 2024
de2a1cd
Fix URL handling in ScriptHandler (#6639)
marklundin May 28, 2024
084fb50
Fix mesh collider creation (#6630)
LeXXik May 28, 2024
6edf21f
Docs update (#6631)
LeXXik May 28, 2024
44aacab
Update script component to use getSchema method instead of tSchema
marklundin May 31, 2024
865fd80
Refactor script component attribute initialization
marklundin May 31, 2024
ad685e6
Merge branch 'main' into esm-script-class
marklundin Jun 3, 2024
029e93e
merge fix
marklundin Jun 3, 2024
90d88d0
linting
marklundin Jun 3, 2024
f979323
Update import statement in script.js
marklundin Jun 3, 2024
e774454
Refactor script attribute assignment
marklundin Jun 3, 2024
a7f5c23
linting
marklundin Jun 3, 2024
72ecdcd
Refactor script component initialization
marklundin Jun 3, 2024
6485fa4
Refactor script component and script handler
marklundin Jun 3, 2024
66fefb4
linting + comments
marklundin Jun 4, 2024
ff5d3c4
Merge branch 'main' into esm-script-class
marklundin Jun 5, 2024
6bda6e7
Fix the definition of sheenTint Standard Material property (#6665)
mvaligursky Jun 5, 2024
8e7c2a2
Update to skybox shader to map it closer to the infinity (#6664)
mvaligursky Jun 5, 2024
a2650f4
[Fix] Particle system handle different IB formats of incoming mesh (#…
mvaligursky Jun 5, 2024
2ad518a
[BREAKING] Remove deprecated AudioSourceComponent component (#6407)
mvaligursky Jun 6, 2024
c8885c8
Cubemap fix for webgpu (#6669)
slimbuck Jun 6, 2024
f4352e1
[BREAKING] Remove support for legacy scripts (#6584)
mvaligursky Jun 6, 2024
630bb32
Fix shader chunk error for tonemapped compressed GS (#6670)
slimbuck Jun 6, 2024
7dd1e58
Remove support for legacy scripts
marklundin Jun 6, 2024
cfe9df4
merge main
marklundin Jun 6, 2024
44b1227
Merge branch 'esm-script-class' of https://github.com/playcanvas/engi…
marklundin Jun 6, 2024
3c7d7db
Remove legacy script system
marklundin Jun 6, 2024
5272a62
Add getScriptName function and toLowerCamelCase utility function
marklundin Jun 7, 2024
5bf5dc4
Merge branch 'main' into esm-script-class
marklundin Jun 12, 2024
bc235e3
jsdoc improvements
marklundin Jun 13, 2024
ea80a53
Update src/framework/script/script.js
marklundin Jun 17, 2024
9dfe5f9
Update src/framework/script/script-attributes.js
marklundin Jun 18, 2024
d89b4e5
linting + feedback
marklundin Jun 18, 2024
e9ce2c5
Update src/framework/script/script.js
marklundin Jun 18, 2024
d48b290
removed redundant error link
marklundin Jun 18, 2024
c0d70b7
Merge branch 'esm-script-class' of https://github.com/playcanvas/engi…
marklundin Jun 18, 2024
0efb4ee
Update src/framework/script/script.js
marklundin Jun 18, 2024
ad73575
Update src/framework/script/script.js
marklundin Jun 18, 2024
70a27b9
Update src/framework/script/script.js
marklundin Jun 18, 2024
83e1f68
Update src/framework/script/script-attributes.js
marklundin Jun 18, 2024
6cf195c
Update src/framework/script/script-type.js
marklundin Jun 18, 2024
5afc9f2
Update src/framework/components/script/component.js
marklundin Jun 18, 2024
c2158d8
Refactor attributeToValue function
marklundin Jun 18, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
88 changes: 78 additions & 10 deletions src/framework/components/script/component.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,18 @@
import { Debug } from '../../../core/debug.js';
import { SortedLoopArray } from '../../../core/sorted-loop-array.js';

import { ScriptAttributes } from '../../script/script-attributes.js';
import { ScriptAttributes, assignAttributesToScript } from '../../script/script-attributes.js';
import {
SCRIPT_INITIALIZE, SCRIPT_POST_INITIALIZE, SCRIPT_UPDATE,
SCRIPT_POST_UPDATE, SCRIPT_SWAP
} from '../../script/constants.js';

import { Component } from '../component.js';
import { Entity } from '../../entity.js';
import { ScriptType } from '../../script/script-type.js';
import { getScriptName } from '../../script/script.js';

const toLowerCamelCase = str => str[0].toLowerCase() + str.substring(1);

/**
* The ScriptComponent allows you to extend the functionality of an Entity by attaching your own
Expand All @@ -18,6 +22,13 @@ import { Entity } from '../../entity.js';
* @category Script
*/
class ScriptComponent extends Component {
/**
* A map of the script name and the initialized component data
marklundin marked this conversation as resolved.
Show resolved Hide resolved
* @private
* @type {Map<string, object>}
*/
_attributeDataMap = new Map();

/**
* Fired when a {@link ScriptType} instance is created and attached to the script component.
* This event is available in two forms. They are as follows:
Expand Down Expand Up @@ -191,7 +202,7 @@ class ScriptComponent extends Component {
* An array of all script instances attached to an entity. This array is read-only and should
* not be modified by developer.
*
* @type {import('../../script/script-type.js').ScriptType[]}
* @type {import('../../script/script.js').Script[]}
marklundin marked this conversation as resolved.
Show resolved Hide resolved
*/
set scripts(value) {
this._scriptsData = value;
Expand All @@ -205,8 +216,9 @@ class ScriptComponent extends Component {
// existing script

// enabled
if (typeof value[key].enabled === 'boolean')
if (typeof value[key].enabled === 'boolean') {
script.enabled = !!value[key].enabled;
}

// attributes
if (typeof value[key].attributes === 'object') {
Expand Down Expand Up @@ -325,6 +337,18 @@ class ScriptComponent extends Component {

for (let i = 0, len = this.scripts.length; i < len; i++) {
const script = this.scripts[i];

// initialize attributes when enabled
if (!script._initialized) {
const onFirstEnabled = () => {
if (!script._initialized && script.enabled) {
this.initializeAttributes(script);
script.off('enable', onFirstEnabled);
}
};
script.on('enable', onFirstEnabled);
marklundin marked this conversation as resolved.
Show resolved Hide resolved
}

script.enabled = script._enabled;
}

Expand Down Expand Up @@ -363,8 +387,41 @@ class ScriptComponent extends Component {
}

_onInitializeAttributes() {
for (let i = 0, len = this.scripts.length; i < len; i++)
this.scripts[i].__initializeAttributes();
this.initializeAllScriptAttributes();
}

initializeAllScriptAttributes() {

for (let i = 0, len = this.scripts.length; i < len; i++) {
const script = this.scripts[i];
this.initializeAttributes(script);
}
}
marklundin marked this conversation as resolved.
Show resolved Hide resolved

initializeAttributes(script) {

// if script has __initializeAttributes method assume it has a runtime schema
if (script instanceof ScriptType) {

script.__initializeAttributes();

} else {

// otherwise we need to manually initialize attributes from the schema
const name = script.__scriptType.__name || toLowerCamelCase(getScriptName(script.__scriptType));
marklundin marked this conversation as resolved.
Show resolved Hide resolved
const data = this._attributeDataMap.get(name);

// If not data exists return early
if (!data) return;
marklundin marked this conversation as resolved.
Show resolved Hide resolved

// Fetch schema and warn if it doesn't exist
const schema = this.system.app.scripts?.getSchema(name);
if (!schema) Debug.warnOnce(`No schema exists for the script '${name}'. A schema must exist for data to be instantiated on the script.`);
marklundin marked this conversation as resolved.
Show resolved Hide resolved

// Assign the attributes to the script instance based on the attribute schema
assignAttributesToScript(this.system.app, schema.attributes, data, script);

}
}

_scriptMethod(script, method, arg) {
Expand Down Expand Up @@ -594,8 +651,8 @@ class ScriptComponent extends Component {
/**
* Create a script instance and attach to an entity script component.
*
* @param {string|typeof import('../../script/script-type.js').ScriptType} nameOrType - The
* name or type of {@link ScriptType}.
* @param {string|typeof import('../../script/script.js').Script} nameOrType - The
* name or type of {@link Script}.
* @param {object} [args] - Object with arguments for a script.
* @param {boolean} [args.enabled] - If script instance is enabled after creation. Defaults to
* true.
Expand Down Expand Up @@ -626,7 +683,7 @@ class ScriptComponent extends Component {
if (typeof scriptType === 'string') {
scriptType = this.system.app.scripts.get(scriptType);
} else if (scriptType) {
scriptName = scriptType.__name;
scriptName = scriptType.__name ?? toLowerCamelCase(ScriptType.__getScriptName(scriptType));
}

if (scriptType) {
Expand All @@ -639,6 +696,15 @@ class ScriptComponent extends Component {
attributes: args.attributes
});


// If the script is not a ScriptType then we must store attribute data on the component
if (!(scriptInstance instanceof ScriptType)) {

// Store the Attribute data
this._attributeDataMap.set(scriptName, args.attributes);

}

const len = this._scripts.length;
let ind = -1;
if (typeof args.ind === 'number' && args.ind !== -1 && len > args.ind)
Expand All @@ -656,7 +722,7 @@ class ScriptComponent extends Component {
this[scriptName] = scriptInstance;

if (!args.preloading)
scriptInstance.__initializeAttributes();
this.initializeAttributes(scriptInstance);

this.fire('create', scriptName, scriptInstance);
this.fire('create:' + scriptName, scriptInstance);
Expand Down Expand Up @@ -720,6 +786,8 @@ class ScriptComponent extends Component {
delete this._scriptsIndex[scriptName];
if (!scriptData) return false;

this._attributeDataMap.delete(scriptName);

const scriptInstance = scriptData.instance;
if (scriptInstance && !scriptInstance._destroyed) {
scriptInstance.enabled = false;
Expand Down Expand Up @@ -788,7 +856,7 @@ class ScriptComponent extends Component {
if (!scriptInstance.swap)
return false;

scriptInstance.__initializeAttributes();
this.initializeAttributes(scriptInstance);

// add to component
this._scripts[ind] = scriptInstance;
Expand Down
23 changes: 9 additions & 14 deletions src/framework/handlers/script.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
import { platform } from '../../core/platform.js';
import { script } from '../script.js';
import { ScriptType } from '../script/script-type.js';
import { ScriptTypes } from '../script/script-types.js';
import { registerScript } from '../script/script.js';
import { registerScript } from '../script/script-create.js';
import { ResourceLoader } from './loader.js';

import { ResourceHandler } from './handler.js';
import { ScriptAttributes } from '../script/script-attributes.js';
import { Script, getScriptName } from '../script/script.js';

const toLowerCamelCase = str => str[0].toLowerCase() + str.substring(1);

Expand Down Expand Up @@ -152,21 +151,17 @@ class ScriptHandler extends ResourceHandler {
// @ts-ignore
import(importUrl.toString()).then((module) => {

const filename = importUrl.pathname.split('/').pop();
const scriptSchema = this._app.assets.find(filename, 'script').data.scripts;

for (const key in module) {
const scriptClass = module[key];
const extendsScriptType = scriptClass.prototype instanceof ScriptType;
const scriptName = getScriptName(scriptClass);
const extendsScriptType = scriptClass.prototype instanceof Script;

if (extendsScriptType) {

// Check if attributes is defined directly on the class and not inherited
if (scriptClass.hasOwnProperty('attributes')) {
const attributes = new ScriptAttributes(scriptClass);
for (const key in scriptClass.attributes) {
attributes.add(key, scriptClass.attributes[key]);
}
scriptClass.attributes = attributes;
}
registerScript(scriptClass, toLowerCamelCase(scriptClass.name));
registerScript(scriptClass, toLowerCamelCase(scriptName));
this._app.scripts.addSchema(toLowerCamelCase(scriptName), scriptSchema);
}
}

Expand Down
54 changes: 52 additions & 2 deletions src/framework/script/script-attributes.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,7 @@ import { CurveSet } from '../../core/math/curve-set.js';
import { Vec2 } from '../../core/math/vec2.js';
import { Vec3 } from '../../core/math/vec3.js';
import { Vec4 } from '../../core/math/vec4.js';

import { GraphNode } from '../../scene/graph-node.js';

import { Asset } from '../asset/asset.js';

const components = ['x', 'y', 'z', 'w'];
Expand Down Expand Up @@ -148,6 +146,56 @@ function rawToValue(app, args, value, old) {
return value;
}

/**
* @typedef {Object} AttributeSchema
* @property {"boolean"|"number"|"string"|"json"|"asset"|"entity"|"rgb"|"rgba"|"vec2"|"vec3"|"vec4"|"curve"} type - The Attribute type
* @property {boolean} [array] - True if this attribute is an array of `type`
* @property {number} [step] - The precision of the attribute. (Only necessary for numerical attributes)
* @property {number} [min] - The expected minimum range of the attributes (Only necessary for numerical attributes)
* @property {number} [max] - The expected minimum range of the attributes (Only necessary for numerical attributes)
marklundin marked this conversation as resolved.
Show resolved Hide resolved
*/

/**
* Takes an attribute schema, a value and current value, and return a new value
marklundin marked this conversation as resolved.
Show resolved Hide resolved
*
* @param {import('../../framework/application.js').Application} app - The working application
* @param {AttributeSchema} schema - The attribute schema used to resolve properties
* @param {*} value - The raw value to create
* @param {*} current - The existing value
* @returns {*} The return value
*/
export function attributeToValue(app, schema, value, current) {
marklundin marked this conversation as resolved.
Show resolved Hide resolved
if (schema.array) {
const arr = [];
for (let i = 0, len = value.length; i < len; i++) {
arr.push(rawToValue(app, schema, value[i], current ? current[i] : null));
}
return arr;
marklundin marked this conversation as resolved.
Show resolved Hide resolved
}

return rawToValue(app, schema, value, current);
}

/**
* This will assign values to a script instance based on a map of attributes schemas and a corresponding map of data
marklundin marked this conversation as resolved.
Show resolved Hide resolved
*
* @param {*} app - The application instance
* @param {Object<string, AttributeSchema>} attributeSchemaMap - A map of attribute names to Attribute Schemas
* @param {Object<string, *>} data - A Map of data to assign to the Script instance
* @param {Script} script - The Script instance to assign values onto
*/
export function assignAttributesToScript(app, attributeSchemaMap, data, script) {

// Iterate over the schema and assign corresponding data
for (const attributeName in attributeSchemaMap) {
const attributeSchema = attributeSchemaMap[attributeName];
const dataToAssign = data[attributeName];

// Assign the value to the script based on the attribute schema
script[attributeName] = attributeToValue(app, attributeSchema, dataToAssign, script);
}
}

/**
* Container of Script Attribute definitions. Implements an interface to add/remove attributes and
* store their definition for a {@link ScriptType}. Note: An instance of ScriptAttributes is
Expand All @@ -156,6 +204,8 @@ function rawToValue(app, args, value, old) {
* @category Script
*/
class ScriptAttributes {
static assignAttributesToScript = assignAttributesToScript;

/**
* Create a new ScriptAttributes instance.
*
Expand Down
Loading
Loading