mirror of
https://github.com/overte-org/overte.git
synced 2025-04-19 15:03:53 +02:00
Creating the master / agent hiring system
This commit is contained in:
parent
184669762a
commit
3273fbcad4
2 changed files with 292 additions and 212 deletions
|
@ -10,235 +10,305 @@
|
|||
//
|
||||
|
||||
function printDebug(message) {
|
||||
print(message);
|
||||
print(message);
|
||||
}
|
||||
|
||||
(function() {
|
||||
var COMMAND_CHANNEL = "com.highfidelity.PlaybackChannel1";
|
||||
var ANNOUNCE_CHANNEL = "com.highfidelity.playbackAgent.announceID";
|
||||
var COMMAND_CHANNEL = "com.highfidelity.PlaybackChannel1";
|
||||
var ANNOUNCE_CHANNEL = "com.highfidelity.playbackAgent.announceID";
|
||||
|
||||
// The time between alive messages on the command channel
|
||||
var ALIVE_PERIOD = 3;
|
||||
var NUM_CYCLES_BEFORE_RESET = 5;
|
||||
// The time between alive messages on the command channel
|
||||
var ALIVE_PERIOD = 3;
|
||||
var NUM_CYCLES_BEFORE_RESET = 8;
|
||||
|
||||
// Service Actions
|
||||
var AGENT_READY = "ready";
|
||||
var INVALID_ACTOR = -2;
|
||||
// Service Actions
|
||||
var MASTER_ID = -1;
|
||||
var AGENT_READY = "ready";
|
||||
var AGENT_LOST = "agentLost";
|
||||
|
||||
var MASTER_INDEX = -1;
|
||||
var INVALID_ACTOR = -2;
|
||||
|
||||
var MASTER_ALIVE = -1;
|
||||
var MASTER_FIRE_AGENT = -2;
|
||||
|
||||
var makeMessage = function(id, action, argument) {
|
||||
var message = {
|
||||
var AGENTS_BROADCAST = -1;
|
||||
var MASTER_ALIVE = -1;
|
||||
var MASTER_FIRE_AGENT = -2;
|
||||
|
||||
var makeUniqueUUID = function(SEUUID) {
|
||||
//return SEUUID + Math.random();
|
||||
// forget complexity, just give me a four digit pin
|
||||
return (Math.random() * 10000).toFixed(0);
|
||||
}
|
||||
|
||||
var packAnnounceMessage = function(dest, command, src) {
|
||||
var message = {
|
||||
dest: dest,
|
||||
command: command,
|
||||
src: src
|
||||
};
|
||||
return JSON.stringify(message);
|
||||
};
|
||||
|
||||
var unpackAnnounceMessage = function(message) {
|
||||
return JSON.parse(message);
|
||||
};
|
||||
|
||||
var packCommandMessage = function(id, action, argument) {
|
||||
var message = {
|
||||
id_key: id,
|
||||
action_key: action,
|
||||
argument_key: argument
|
||||
};
|
||||
return message;
|
||||
};
|
||||
|
||||
var unpackMessage = function(message) {
|
||||
return JSON.parse(message);
|
||||
};
|
||||
|
||||
// master side
|
||||
//---------------------------------
|
||||
var MasterController = function() {
|
||||
this.timeSinceLastAlive = 0;
|
||||
this.knownAgents = new Array;
|
||||
this.subscribed = false;
|
||||
};
|
||||
return JSON.stringify(message);
|
||||
};
|
||||
|
||||
MasterController.prototype.destroy = function() {
|
||||
if (this.subscribed) {
|
||||
Messages.unsubscribe(ANNOUNCE_CHANNEL);
|
||||
Messages.unsubscribe(COMMAND_CHANNEL);
|
||||
this.subscribed = true;
|
||||
}
|
||||
};
|
||||
var unpackCommandMessage = function(message) {
|
||||
return JSON.parse(message);
|
||||
};
|
||||
|
||||
// master side
|
||||
//---------------------------------
|
||||
var MasterController = function() {
|
||||
this.timeSinceLastAlive = 0;
|
||||
this.knownAgents = new Array;
|
||||
this.hiringAgentsQueue = new Array;
|
||||
this.subscribed = false;
|
||||
};
|
||||
|
||||
MasterController.prototype.reset = function() {
|
||||
this.timeSinceLastAlive = 0;
|
||||
MasterController.prototype.destroy = function() {
|
||||
if (this.subscribed) {
|
||||
Messages.unsubscribe(ANNOUNCE_CHANNEL);
|
||||
Messages.unsubscribe(COMMAND_CHANNEL);
|
||||
this.subscribed = true;
|
||||
}
|
||||
};
|
||||
|
||||
if (!this.subscribed) {
|
||||
Messages.subscribe(COMMAND_CHANNEL);
|
||||
Messages.subscribe(ANNOUNCE_CHANNEL);
|
||||
var localThis = this;
|
||||
Messages.messageReceived.connect(function (channel, message, senderID) {
|
||||
if (channel == ANNOUNCE_CHANNEL) {
|
||||
localThis._processAnnounceMessage(message, senderID);
|
||||
return;
|
||||
}
|
||||
});
|
||||
}
|
||||
// ready to roll, enable
|
||||
this.subscribed = true;
|
||||
printDebug("Master Started");
|
||||
MasterController.prototype.reset = function() {
|
||||
this.timeSinceLastAlive = 0;
|
||||
|
||||
if (!this.subscribed) {
|
||||
Messages.subscribe(COMMAND_CHANNEL);
|
||||
Messages.subscribe(ANNOUNCE_CHANNEL);
|
||||
var localThis = this;
|
||||
Messages.messageReceived.connect(function (channel, message, senderID) {
|
||||
if (channel == ANNOUNCE_CHANNEL) {
|
||||
localThis._processAnnounceMessage(message, senderID);
|
||||
return;
|
||||
}
|
||||
});
|
||||
}
|
||||
// ready to roll, enable
|
||||
this.subscribed = true;
|
||||
printDebug("Master Started");
|
||||
};
|
||||
|
||||
MasterController.prototype._processAnnounceMessage = function(message, senderID) {
|
||||
if (message == AGENT_READY) {
|
||||
|
||||
// check to see if we know about this agent
|
||||
if (this.knownAgents.indexOf(senderID) < 0) {
|
||||
|
||||
var indexOfNewAgent = this.knownAgents.length;
|
||||
this.knownAgents[indexOfNewAgent] = senderID;
|
||||
printDebug("New agent available to be hired " + senderID);
|
||||
|
||||
var acknowledgeMessage = senderID + "." + indexOfNewAgent;
|
||||
Messages.sendMessage(ANNOUNCE_CHANNEL, acknowledgeMessage);
|
||||
} else {
|
||||
printDebug("New agent still sending ready ? " + senderID);
|
||||
}
|
||||
}
|
||||
var message = unpackAnnounceMessage(message);
|
||||
if (message.dest == MASTER_ID) {
|
||||
if (message.command == AGENT_READY) {
|
||||
// check to see if we know about this agent
|
||||
var agentIndex = this.knownAgents.indexOf(message.src);
|
||||
if (agentIndex < 0) {
|
||||
if (this.hiringAgentsQueue.length > 0) {
|
||||
var hiringHandler = this.hiringAgentsQueue.pop();
|
||||
hiringHandler(message.src);
|
||||
} else {
|
||||
//No hiring in queue so bail
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
// Master think the agent is hired but not the other way around, forget about it
|
||||
printDebug("New agent still sending ready ? " + message.src + " " + agentIndex + " Forgeting about it");
|
||||
this.knownAgents[agentIndex] = INVALID_ACTOR;
|
||||
}
|
||||
} else if (message.command == AGENT_LOST) {
|
||||
// check to see if we know about this agent
|
||||
var agentIndex = this.knownAgents.indexOf(message.src);
|
||||
if (agentIndex < 0) {
|
||||
printDebug("Lost agent " + message.src + " " + agentIndex + " Forgeting about it");
|
||||
this.knownAgents[agentIndex] = INVALID_ACTOR;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
MasterController.prototype.sendCommand = function(target, action, argument) {
|
||||
if (this.subscribed) {
|
||||
var messageJSON = JSON.stringify(makeMessage(target, action, argument));
|
||||
var messageJSON = packCommandMessage(target, action, argument);
|
||||
Messages.sendMessage(COMMAND_CHANNEL, messageJSON);
|
||||
printDebug("Master sent message: " + messageJSON);
|
||||
}
|
||||
};
|
||||
|
||||
MasterController.prototype.update = function(deltaTime) {
|
||||
this.timeSinceLastAlive += deltaTime;
|
||||
if (this.timeSinceLastAlive > ALIVE_PERIOD) {
|
||||
this.timeSinceLastAlive = 0;
|
||||
printDebug("Master ping alive");
|
||||
this.sendCommand(MASTER_INDEX, MASTER_ALIVE);
|
||||
}
|
||||
};
|
||||
|
||||
this.MasterController = MasterController;
|
||||
|
||||
// agent side
|
||||
//---------------------------------
|
||||
var AgentController = function() {
|
||||
this.subscribed = false;
|
||||
|
||||
this.timeSinceLastAlive = 0;
|
||||
this.numCyclesWithoutAlive = 0;
|
||||
this.actorIndex = INVALID_ACTOR;
|
||||
this.notifyAlive = false;
|
||||
|
||||
this.onHired = function() {};
|
||||
this.onCommand = function(command) {};
|
||||
this.onFired = function() {};
|
||||
};
|
||||
|
||||
AgentController.prototype.destroy = function() {
|
||||
if (this.subscribed) {
|
||||
this.fire();
|
||||
Messages.unsubscribe(ANNOUNCE_CHANNEL);
|
||||
Messages.unsubscribe(COMMAND_CHANNEL);
|
||||
this.subscribed = true;
|
||||
}
|
||||
};
|
||||
|
||||
AgentController.prototype.reset = function() {
|
||||
// If already hired, fire
|
||||
this.fired();
|
||||
|
||||
if (!this.subscribed) {
|
||||
Messages.subscribe(COMMAND_CHANNEL);
|
||||
Messages.subscribe(ANNOUNCE_CHANNEL);
|
||||
var localThis = this;
|
||||
Messages.messageReceived.connect(function (channel, message, senderID) {
|
||||
if (channel == ANNOUNCE_CHANNEL) {
|
||||
localThis._processAnnounceMessage(message, senderID);
|
||||
return;
|
||||
}
|
||||
if (channel == COMMAND_CHANNEL) {
|
||||
localThis._processCommandMessage(message, senderID);
|
||||
return;
|
||||
}
|
||||
});
|
||||
}
|
||||
this.subscribed = true;
|
||||
printDebug("Client Started");
|
||||
MasterController.prototype.update = function(deltaTime) {
|
||||
this.timeSinceLastAlive += deltaTime;
|
||||
if (this.timeSinceLastAlive > ALIVE_PERIOD) {
|
||||
this.timeSinceLastAlive = 0;
|
||||
this.sendCommand(AGENTS_BROADCAST, MASTER_ALIVE);
|
||||
}
|
||||
};
|
||||
|
||||
AgentController.prototype._processAnnounceMessage = function(message, senderID) {
|
||||
//printDebug("Client " + this.actorIndex + " Received Announcement = " + message);
|
||||
if (message != AGENT_READY) {
|
||||
// this may be a message to hire me if i m not already
|
||||
if (this.actorIndex == INVALID_ACTOR) {
|
||||
var parts = message.split(".");
|
||||
var agentID = parts[0];
|
||||
var actorIndex = parts[1];
|
||||
//printDebug("Client " + Agent.sessionUUID + " - " + agentID + " Hired!");
|
||||
if (agentID == Agent.sessionUUID) {
|
||||
this.actorIndex = actorIndex;
|
||||
printDebug("Client " + this.actorIndex + " Hired!");
|
||||
this.onHired();
|
||||
// Messages.unsubscribe(ANNOUNCE_CHANNEL); // id announce channel
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AgentController.prototype._processCommandMessage = function(message, senderID) {
|
||||
var command = unpackMessage(message);
|
||||
//printDebug("Received command = " + JSON.stringify(command));
|
||||
MasterController.prototype.hireAgent = function(onHired) {
|
||||
var localThis = this;
|
||||
this.hiringAgentsQueue.unshift(function(agentID) {
|
||||
printDebug("hiring callback with agent " + agentID);
|
||||
|
||||
var indexOfNewAgent = localThis.knownAgents.length;
|
||||
localThis.knownAgents[indexOfNewAgent] = agentID;
|
||||
|
||||
printDebug("New agent available to be hired " + agentID + " " + index);
|
||||
var hireMessage = "HIRE." + index;
|
||||
var answerMessage = packAnnounceMessage(agentID, hireMessage, MASTER_ID);
|
||||
Messages.sendMessage(ANNOUNCE_CHANNEL, answerMessage);
|
||||
|
||||
if (command.id_key == localThis.actorIndex || command.id_key == MASTER_INDEX) {
|
||||
if (command.action_key == MASTER_ALIVE) {
|
||||
this.notifyAlive = true;
|
||||
} else if (command.action_key == MASTER_FIRE_AGENT) {
|
||||
printDebug("Master firing Agent");
|
||||
this.fire();
|
||||
} else {
|
||||
printDebug("True action received = " + JSON.stringify(command) + senderID);
|
||||
this.onCommand(command);
|
||||
}
|
||||
} else {
|
||||
// ignored
|
||||
}
|
||||
if (onHired != null) {
|
||||
onHired(index);
|
||||
}
|
||||
})
|
||||
};
|
||||
|
||||
AgentController.prototype.update = function(deltaTime) {
|
||||
this.timeSinceLastAlive += deltaTime;
|
||||
if (this.timeSinceLastAlive > ALIVE_PERIOD) {
|
||||
if (this.subscribed) {
|
||||
if (this.actorIndex == INVALID_ACTOR) {
|
||||
Messages.sendMessage(ANNOUNCE_CHANNEL, AGENT_READY);
|
||||
//printDebug("Client Ready" + ANNOUNCE_CHANNEL + AGENT_READY);
|
||||
} else {
|
||||
this.numCyclesWithoutAlive++;
|
||||
if (this.notifyAlive) {
|
||||
this.notifyAlive = false;
|
||||
this.numCyclesWithoutAlive = 0;
|
||||
printDebug("Master Alive");
|
||||
} else if (this.numCyclesWithoutAlive > NUM_CYCLES_BEFORE_RESET) {
|
||||
printDebug("Master Lost, firing Agent");
|
||||
this.fired();
|
||||
}
|
||||
}
|
||||
}
|
||||
this.MasterController = MasterController;
|
||||
|
||||
this.timeSinceLastAlive = 0;
|
||||
}
|
||||
};
|
||||
// agent side
|
||||
//---------------------------------
|
||||
var AgentController = function() {
|
||||
this.subscribed = false;
|
||||
|
||||
this._init();
|
||||
|
||||
AgentController.prototype.fired = function() {
|
||||
// clear the state first
|
||||
var wasHired = (this.actorIndex != INVALID_ACTOR);
|
||||
this.actorIndex= INVALID_ACTOR;
|
||||
this.onHired = function() {};
|
||||
this.onCommand = function(command) {};
|
||||
this.onFired = function() {};
|
||||
};
|
||||
|
||||
AgentController.prototype._init = function() {
|
||||
this.actorIndex= INVALID_ACTOR;
|
||||
this.notifyAlive = false;
|
||||
this.timeSinceLastAlive = 0;
|
||||
this.numCyclesWithoutAlive = 0;
|
||||
this.actorUUID = makeUniqueUUID(Agent.sessionUUID);
|
||||
printDebug("this.actorUUID = " + this.actorUUID);
|
||||
}
|
||||
|
||||
AgentController.prototype.destroy = function() {
|
||||
if (this.subscribed) {
|
||||
this.fire();
|
||||
Messages.unsubscribe(ANNOUNCE_CHANNEL);
|
||||
Messages.unsubscribe(COMMAND_CHANNEL);
|
||||
this.subscribed = true;
|
||||
}
|
||||
};
|
||||
|
||||
AgentController.prototype.reset = function() {
|
||||
// If already hired, fire
|
||||
this.fired();
|
||||
|
||||
if (!this.subscribed) {
|
||||
Messages.subscribe(COMMAND_CHANNEL);
|
||||
Messages.subscribe(ANNOUNCE_CHANNEL);
|
||||
var localThis = this;
|
||||
Messages.messageReceived.connect(function (channel, message, senderID) {
|
||||
if (channel == ANNOUNCE_CHANNEL) {
|
||||
localThis._processAnnounceMessage(message, senderID);
|
||||
return;
|
||||
}
|
||||
if (channel == COMMAND_CHANNEL) {
|
||||
localThis._processCommandMessage(message, senderID);
|
||||
return;
|
||||
}
|
||||
});
|
||||
}
|
||||
this.subscribed = true;
|
||||
printDebug("Client Started");
|
||||
};
|
||||
|
||||
AgentController.prototype._processAnnounceMessage = function(message, senderID) {
|
||||
var announce = unpackCommandMessage(message);
|
||||
//printDebug("Client " + this.actorIndex + " Received Announcement = " + message);
|
||||
if (announce.dest == this.actorUUID) {
|
||||
if (announce.command != AGENT_READY) {
|
||||
// this may be a message to hire me if i m not already
|
||||
if (this.actorIndex == INVALID_ACTOR) {
|
||||
printDebug(announce.command);
|
||||
|
||||
var parts = announce.command.split(".");
|
||||
var agentID = parts[0];
|
||||
var actorIndex = parts[1];
|
||||
//printDebug("Client " + Agent.sessionUUID + " - " + agentID + " Hired!");
|
||||
// if (agentID == Agent.sessionUUID) {
|
||||
this.actorIndex = actorIndex;
|
||||
printDebug("Client " + this.actorIndex + " Hired!");
|
||||
this.onHired();
|
||||
// Messages.unsubscribe(ANNOUNCE_CHANNEL); // id announce channel
|
||||
// }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AgentController.prototype._processCommandMessage = function(message, senderID) {
|
||||
var command = unpackCommandMessage(message);
|
||||
//printDebug("Received command = " + JSON.stringify(command));
|
||||
|
||||
if ((command.id_key == this.actorUUID) || (command.id_key == AGENTS_BROADCAST)) {
|
||||
if (command.action_key == MASTER_ALIVE) {
|
||||
this.notifyAlive = true;
|
||||
} else if (command.action_key == MASTER_FIRE_AGENT) {
|
||||
printDebug("Master firing Agent");
|
||||
this.fire();
|
||||
} else {
|
||||
printDebug("True action received = " + JSON.stringify(command) + senderID);
|
||||
this.onCommand(command);
|
||||
}
|
||||
} else {
|
||||
// ignored
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
AgentController.prototype.update = function(deltaTime) {
|
||||
this.timeSinceLastAlive += deltaTime;
|
||||
if (this.timeSinceLastAlive > ALIVE_PERIOD) {
|
||||
if (this.subscribed) {
|
||||
if (this.actorIndex == INVALID_ACTOR) {
|
||||
Messages.sendMessage(ANNOUNCE_CHANNEL, packAnnounceMessage(MASTER_ID, AGENT_READY, this.actorUUID));
|
||||
//printDebug("Client Ready" + ANNOUNCE_CHANNEL + AGENT_READY);
|
||||
} else {
|
||||
this.numCyclesWithoutAlive++;
|
||||
if (this.notifyAlive) {
|
||||
this.notifyAlive = false;
|
||||
this.numCyclesWithoutAlive = 0;
|
||||
printDebug("Master Alive");
|
||||
} else if (this.numCyclesWithoutAlive > NUM_CYCLES_BEFORE_RESET) {
|
||||
printDebug("Master Lost, firing Agent");
|
||||
this.fired();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.timeSinceLastAlive = 0;
|
||||
}
|
||||
};
|
||||
|
||||
AgentController.prototype.fired = function() {
|
||||
// clear the state first
|
||||
var wasHired = (this.actorIndex != INVALID_ACTOR);
|
||||
|
||||
// Post a last message to master in case it still listen to warn that this agent is losing it
|
||||
if (wasHired) {
|
||||
Messages.sendMessage(ANNOUNCE_CHANNEL, packAnnounceMessage(MASTER_ID, AGENT_LOST, this.actorUUID));
|
||||
}
|
||||
|
||||
// reset
|
||||
this._init();
|
||||
|
||||
// then custom fire if was hired
|
||||
if (wasHired) {
|
||||
this.onFired();
|
||||
}
|
||||
}
|
||||
if (wasHired) {
|
||||
this.onFired();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
this.AgentController = AgentController;
|
||||
this.AgentController = AgentController;
|
||||
})();
|
||||
|
||||
|
||||
|
|
|
@ -54,13 +54,23 @@ var performanceLoadedNeedUpdate = false;
|
|||
|
||||
setupPlayback();
|
||||
|
||||
function onHiring(agentID, index) {
|
||||
print("agent hired from playbackMaster! " + agentID + " " + index)
|
||||
}
|
||||
|
||||
function setupPlayback() {
|
||||
ac_number = Window.prompt("Insert number of agents: ","1");
|
||||
if (ac_number === "" || ac_number === null) {
|
||||
ac_number = 1;
|
||||
}
|
||||
setupToolBars();
|
||||
}
|
||||
masterController.reset();
|
||||
|
||||
for (var i = 0; i < ac_number; i++) {
|
||||
masterController.hireAgent(onHiring);
|
||||
}
|
||||
|
||||
setupToolBars();
|
||||
|
||||
}
|
||||
|
||||
function setupToolBars() {
|
||||
|
@ -96,13 +106,13 @@ function setupToolBars() {
|
|||
|
||||
var playLoopWidthFactor = 1.65;
|
||||
playLoopIcon[i] = toolBars[i].addTool({
|
||||
imageURL: TOOL_ICON_URL + "play-and-loop.svg",
|
||||
subImage: { x: 0, y: 0, width: playLoopWidthFactor * Tool.IMAGE_WIDTH, height: Tool.IMAGE_HEIGHT },
|
||||
width: playLoopWidthFactor * Tool.IMAGE_WIDTH,
|
||||
height: Tool.IMAGE_HEIGHT,
|
||||
alpha: ALPHA_OFF,
|
||||
visible: true
|
||||
}, false);
|
||||
imageURL: TOOL_ICON_URL + "play-and-loop.svg",
|
||||
subImage: { x: 0, y: 0, width: playLoopWidthFactor * Tool.IMAGE_WIDTH, height: Tool.IMAGE_HEIGHT },
|
||||
width: playLoopWidthFactor * Tool.IMAGE_WIDTH,
|
||||
height: Tool.IMAGE_HEIGHT,
|
||||
alpha: ALPHA_OFF,
|
||||
visible: true
|
||||
}, false);
|
||||
|
||||
stopIcon[i] = toolBars[i].addTool({
|
||||
imageURL: TOOL_ICON_URL + "recording-stop.svg",
|
||||
|
@ -121,20 +131,20 @@ function setupToolBars() {
|
|||
}, false);
|
||||
|
||||
nameOverlays.push(Overlays.addOverlay("text", {
|
||||
backgroundColor: { red: 0, green: 0, blue: 0 },
|
||||
font: { size: TEXT_HEIGHT },
|
||||
text: (i == ac_number) ? "Master" : i + ". " +
|
||||
((i < names.length) ? names[i] :
|
||||
"AC" + i),
|
||||
x: 0, y: 0,
|
||||
width: toolBars[i].width + ToolBar.SPACING,
|
||||
height: TEXT_HEIGHT + TEXT_MARGIN,
|
||||
leftMargin: TEXT_MARGIN,
|
||||
topMargin: TEXT_MARGIN,
|
||||
alpha: ALPHA_OFF,
|
||||
backgroundAlpha: ALPHA_OFF,
|
||||
visible: true
|
||||
}));
|
||||
backgroundColor: { red: 0, green: 0, blue: 0 },
|
||||
font: { size: TEXT_HEIGHT },
|
||||
text: (i == ac_number) ? "Master" : i + ". " +
|
||||
((i < names.length) ? names[i] :
|
||||
"AC" + i),
|
||||
x: 0, y: 0,
|
||||
width: toolBars[i].width + ToolBar.SPACING,
|
||||
height: TEXT_HEIGHT + TEXT_MARGIN,
|
||||
leftMargin: TEXT_MARGIN,
|
||||
topMargin: TEXT_MARGIN,
|
||||
alpha: ALPHA_OFF,
|
||||
backgroundAlpha: ALPHA_OFF,
|
||||
visible: true
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue