mirror of
https://github.com/4ian/GDevelop.git
synced 2025-10-15 10:19:04 +00:00
335 lines
10 KiB
TypeScript
335 lines
10 KiB
TypeScript
/*
|
|
* GDevelop JS Platform
|
|
* Copyright 2013-2016 Florian Rival (Florian.Rival@gmail.com). All rights reserved.
|
|
* This project is released under the MIT License.
|
|
*/
|
|
namespace gdjs {
|
|
/**
|
|
* VariablesContainer stores variables, usually for a a RuntimeGame, a RuntimeScene
|
|
* or a RuntimeObject.
|
|
*/
|
|
export class VariablesContainer {
|
|
_variables: Hashtable<gdjs.Variable>;
|
|
_variablesArray: gdjs.Variable[] = [];
|
|
|
|
/**
|
|
* @param [initialVariablesData] Optional array containing representations of the base variables.
|
|
*/
|
|
constructor(initialVariablesData?: VariableData[]) {
|
|
this._variables = new Hashtable();
|
|
|
|
if (initialVariablesData !== undefined) {
|
|
this.initFrom(initialVariablesData);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Initialize variables from a container data.<br>
|
|
* If `keepOldVariables` is set to false (by default), all already existing variables will be
|
|
* erased, but the new variables will be accessible thanks to getFromIndex. <br>
|
|
* if `keepOldVariables` is set to true, already existing variables won't be erased and will be
|
|
* still accessible thanks to getFromIndex.
|
|
*
|
|
* @param data The array containing data used to initialize variables.
|
|
* @param [keepOldVariables] If set to true, already existing variables won't be erased.
|
|
*/
|
|
initFrom(data: VariableData[], keepOldVariables?: Boolean) {
|
|
if (keepOldVariables === undefined) {
|
|
keepOldVariables = false;
|
|
}
|
|
if (!keepOldVariables) {
|
|
VariablesContainer._deletedVars = VariablesContainer._deletedVars || [];
|
|
// @ts-ignore
|
|
this._variables.keys(VariablesContainer._deletedVars);
|
|
}
|
|
const that = this;
|
|
let i = 0;
|
|
for (let j = 0; j < data.length; ++j) {
|
|
const varData = data[j];
|
|
if (!varData.name) continue;
|
|
|
|
//Get the variable:
|
|
const variable = that.get(varData.name);
|
|
variable.reinitialize(varData);
|
|
if (!keepOldVariables) {
|
|
//Register the variable in the extra array to ensure a fast lookup using getFromIndex.
|
|
if (i < that._variablesArray.length) {
|
|
that._variablesArray[i] = variable;
|
|
} else {
|
|
that._variablesArray.push(variable);
|
|
}
|
|
++i;
|
|
|
|
//Remove the variable from the list of variables to be deleted.
|
|
const idx = VariablesContainer._deletedVars.indexOf(varData.name);
|
|
if (idx !== -1) {
|
|
VariablesContainer._deletedVars[idx] = undefined;
|
|
}
|
|
}
|
|
}
|
|
if (!keepOldVariables) {
|
|
this._variablesArray.length = i;
|
|
|
|
//If we do not want to keep the already existing variables,
|
|
//remove all the variables not assigned above.
|
|
//(Here, remove means flag the variable as not existing, to avoid garbage creation ).
|
|
for (
|
|
let i = 0, len = VariablesContainer._deletedVars.length;
|
|
i < len;
|
|
++i
|
|
) {
|
|
const variableName = VariablesContainer._deletedVars[i];
|
|
if (variableName !== undefined) {
|
|
this._variables.get(variableName).setUndefinedInContainer();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Declare a new variable.
|
|
* This should only be used by generated code.
|
|
*
|
|
* @param name Variable name
|
|
* @param newVariable The variable to be declared
|
|
*/
|
|
_declare(name: string, newVariable: gdjs.Variable): void {
|
|
this._variables.put(name, newVariable);
|
|
this._variablesArray.push(newVariable);
|
|
}
|
|
|
|
/**
|
|
* Add a new variable.
|
|
* This can be costly, don't use in performance sensitive paths.
|
|
*
|
|
* @param name Variable name
|
|
* @param newVariable The variable to be added
|
|
*/
|
|
add(name: string, newVariable: gdjs.Variable) {
|
|
const oldVariable = this._variables.get(name);
|
|
|
|
// Variable is either already defined, considered as undefined
|
|
// in the container or missing in the container.
|
|
// Whatever the case, replace it by the new.
|
|
this._variables.put(name, newVariable);
|
|
if (oldVariable) {
|
|
// If variable is indexed, ensure that the variable as the index
|
|
// is replaced too. This can be costly (indexOf) but we assume `add` is not
|
|
// used in performance sensitive code.
|
|
const variableIndex = this._variablesArray.indexOf(oldVariable);
|
|
if (variableIndex !== -1) {
|
|
this._variablesArray[variableIndex] = newVariable;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Remove a variable.
|
|
* (the variable is not really removed from the container to avoid creating garbage, but marked as undefined)
|
|
* @param name Variable to be removed
|
|
*/
|
|
remove(name: string) {
|
|
const variable = this._variables.get(name);
|
|
if (variable) {
|
|
variable.setUndefinedInContainer();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get a variable.
|
|
* @param name The variable's name
|
|
* @return The specified variable. If not found, an empty variable is added to the container.
|
|
*/
|
|
get(name: string): gdjs.Variable {
|
|
let variable = this._variables.get(name);
|
|
if (!variable) {
|
|
//Add automatically non-existing variables.
|
|
variable = new gdjs.Variable();
|
|
this._variables.put(name, variable);
|
|
} else {
|
|
if (
|
|
//Reuse variables removed before.
|
|
variable.isUndefinedInContainer()
|
|
) {
|
|
variable.reinitialize();
|
|
}
|
|
}
|
|
return variable;
|
|
}
|
|
|
|
/**
|
|
* Get a variable using its index. If you're unsure about how to use this method, prefer to use `get`.
|
|
* The index of a variable is its index in the data passed to initFrom.
|
|
*
|
|
* This method is generally used by events generated code to increase lookup speed for variables.
|
|
*
|
|
* @param id The variable index
|
|
* @return The specified variable. If not found, an empty variable is added to the container, but it
|
|
* should not happen.
|
|
*/
|
|
getFromIndex(id: number): gdjs.Variable {
|
|
if (id >= this._variablesArray.length) {
|
|
//Add automatically non-existing variables.
|
|
let variable = new gdjs.Variable();
|
|
this._variables.put('', variable);
|
|
return variable;
|
|
} else {
|
|
let variable: gdjs.Variable = this._variablesArray[id];
|
|
//Reuse variables removed before.
|
|
if (variable.isUndefinedInContainer()) {
|
|
variable.reinitialize();
|
|
}
|
|
return variable;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Check if a variable exists in the container.
|
|
* @param name The variable's name
|
|
* @return true if the variable exists.
|
|
*/
|
|
has(name: string): boolean {
|
|
const variable = this._variables.get(name);
|
|
return variable && !variable.isUndefinedInContainer();
|
|
}
|
|
static _deletedVars: Array<string | undefined> = [];
|
|
|
|
/**
|
|
* "Bad" variable container, used by events when no other valid container can be found.
|
|
* This container has no state and always returns the bad variable ( see VariablesContainer.badVariable ).
|
|
* @static
|
|
*/
|
|
static badVariablesContainer: VariablesContainer = {
|
|
_variables: new Hashtable(),
|
|
_variablesArray: [],
|
|
has: function () {
|
|
return false;
|
|
},
|
|
getFromIndex: function () {
|
|
return VariablesContainer.badVariable;
|
|
},
|
|
get: function () {
|
|
return VariablesContainer.badVariable;
|
|
},
|
|
remove: function () {
|
|
return;
|
|
},
|
|
add: function () {
|
|
return;
|
|
},
|
|
_declare: function () {
|
|
return;
|
|
},
|
|
initFrom: function () {
|
|
return;
|
|
},
|
|
};
|
|
|
|
/**
|
|
* "Bad" variable, used by events when no other valid variable can be found.
|
|
* This variable has no state and always return 0 or the empty string.
|
|
* @static
|
|
*/
|
|
static badVariable: Variable = {
|
|
_type: 'number',
|
|
_bool: false,
|
|
_children: {},
|
|
_childrenArray: [],
|
|
_str: '',
|
|
_undefinedInContainer: true,
|
|
_value: 0,
|
|
fromJSON: () => gdjs.VariablesContainer.badVariable,
|
|
toJSObject: () => 0,
|
|
fromJSObject: () => gdjs.VariablesContainer.badVariable,
|
|
reinitialize: () => {},
|
|
addChild: () => gdjs.VariablesContainer.badVariable,
|
|
castTo: () => {},
|
|
clearChildren: () => {},
|
|
clone: () => gdjs.VariablesContainer.badVariable,
|
|
getChildrenCount: () => 0,
|
|
replaceChildren: () => {},
|
|
replaceChildrenArray: () => {},
|
|
getType: function () {
|
|
return 'number';
|
|
},
|
|
isPrimitive: function () {
|
|
return true;
|
|
},
|
|
setValue: () => {},
|
|
toggle: () => {},
|
|
getValue: () => 0,
|
|
getChild: () => gdjs.VariablesContainer.badVariable,
|
|
getChildAt: () => gdjs.VariablesContainer.badVariable,
|
|
getChildNamed: () => gdjs.VariablesContainer.badVariable,
|
|
hasChild: function () {
|
|
return false;
|
|
},
|
|
isStructure: function () {
|
|
return false;
|
|
},
|
|
isNumber: function () {
|
|
return true;
|
|
},
|
|
removeChild: function () {
|
|
return;
|
|
},
|
|
setNumber: function () {
|
|
return;
|
|
},
|
|
setString: function () {
|
|
return;
|
|
},
|
|
setBoolean: function () {
|
|
return;
|
|
},
|
|
getAsString: function () {
|
|
return '0';
|
|
},
|
|
getAsNumber: function () {
|
|
return 0;
|
|
},
|
|
getAsNumberOrString: function () {
|
|
return 0;
|
|
},
|
|
getAsBoolean: function () {
|
|
return false;
|
|
},
|
|
getAllChildren: function () {
|
|
return {};
|
|
},
|
|
getAllChildrenArray: function () {
|
|
return [];
|
|
},
|
|
pushVariableCopy: () => {},
|
|
pushValue: () => {},
|
|
removeAtIndex: function () {
|
|
return;
|
|
},
|
|
add: function () {
|
|
return;
|
|
},
|
|
sub: function () {
|
|
return;
|
|
},
|
|
mul: function () {
|
|
return;
|
|
},
|
|
div: function () {
|
|
return;
|
|
},
|
|
concatenate: function () {
|
|
return;
|
|
},
|
|
concatenateString: function () {
|
|
return;
|
|
},
|
|
setUndefinedInContainer: function () {
|
|
return;
|
|
},
|
|
isUndefinedInContainer: function () {
|
|
return true;
|
|
},
|
|
};
|
|
}
|
|
}
|