rgui
Version:
RPG Maker MV GUI framework.
428 lines (396 loc) • 10.4 kB
JavaScript
/**
* Svent
* version 0.0.8
* @author shitake <z1522716486@hotmail.com>
* @license MIT <https://mit-license.org/>
*/
/*
* Fibers
* version 1.0.15
* @author laverdet <https://www.npmjs.com/package/fibers>
* @license MIT <https://mit-license.org/>
*/
var fs = require('fs'), path = require('path');
// Seed random numbers [gh-82]
Math.random();
// Look for binary for this platform
var modPath = path.join(__dirname, 'bin', process.platform+ '-'+ process.arch+ '-'+ process.versions.modules, 'fibers');
try {
fs.statSync(modPath+ '.node');
} catch (ex) {
// No binary!
console.error(
'## There is an issue with `node-fibers` ##\n'+
'`'+ modPath+ '.node` is missing.\n\n'+
'Try running this to fix the issue: '+ process.execPath+ ' '+ __dirname.replace(' ', '\\ ')+ '/build'
);
throw new Error('Missing binary. See message above.');
}
// Pull in fibers implementation
const Fiber = require(modPath).Fiber;
/**
* Class Event.
* @extends Array
* @author shitake <z1522716486@hotmail.com>
* @license MIT <https://mit-license.org/>
*/
class Event extends Array {
constructor(name, info) {
super();
this.name = name;
this.info = info;
}
}
/**
* Class EventCallbackFiber.
* @author shitake <z1522716486@hotmail.com>
* @license MIT <https://mit-license.org/>
*/
class EventCallbackFiber {
constructor(em, name, callback, info) {
this.objectId = Date.now().toString();
this.name = name;
this.info = info;
this.callback = callback;
this.alive = true;
let self = this;
this.fiber = new Fiber(()=>{
self.callback(em, self.info);
self.fiber = null;
this.alive = false
});
if(callback.immediately) {
em.self = this;
em.fiberDeep += 1;
this.next();
if(em.fiberDeep == 1) em.self = null;
em.fiberDeep -= 1
}
}
next() {
if(!this.fiber){
return console.error(`Fiber(${this.name}) is not alive!`)
}
if(this.return) {
this.fiber = null;
this.alive = false
} else {
this.return = this.fiber.run()
}
}
}
/**
* Class eventManager.
* @author shitake <z1522716486@hotmail.com>
* @license MIT <https://mit-license.org/>
*/
class EventManager {
/**
* Create a eventManager.
*/
constructor() {
this.fiberDeep = 0;
this.events = new Map();
this.eventCallbackFibers = [];
this.eventCallbackFibers.delete = function (obj) {
this.splice(this.indexOf(obj), 1)
};
this.timers = new Map();
this.counters = new Map();
this.timerFilters = new Map();
this.counterfilters = new Map();
}
/**
* Update evnManager.
*/
update() {
if(this.eventCallbackFibers.size != 0) {
this.eventCallbackFibers.forEach(obj => {
this.self = obj;
this.fiberDeep += 1;
obj.next();
this.fiberDeep -= 1;
this.self = null;
if(!obj.alive) this.eventCallbackFibers.delete(obj)
})
}
}
/**
* trigger a event.
* @param {String} name - The event name.
* @param {Object} info - The event info.
*/
trigger(name, info = {}) {
let event = this.events[name];
if(event) {
event.map(callback => {
if(callback.async) {
this.eventCallbackFibers.push(new EventCallbackFiber(this, name, callback, info))
} else {
if(callback.immediately){
callback(this, info)
} else {
let callbackFiber = {
name: name,
info: info,
alive: true,
callback: callback,
next: function () {
callback(this, this.info);
this.alive = false
}
};
this.eventCallbackFibers.push(callbackFiber)
}
}
})
}
}
/**
* change event info.
* @param name - event name.
* @param key - event info key.
* @param value event info value.
*/
eventInfo(name, key, value) {
let event = this.events[name];
if(event) {
event.info = event.info || {};
event.info[key] = value
}
}
/**
* Whether to include the specified event.
* @param name
* @returns {boolean}
*/
have(name) {
return this.events[name] != void 0
}
_on(name, conf, callback, immediately) {
if(name == 'isEventManagerStop'){
Error("error:The event(isEventManagerStop) can only have one callback.")
}
let event = this.events[name] = this.events[name] ? this.events[name] : new Event(name, conf.info);
callback.immediately = immediately;
conf.index == void 0 ? event.push(callback) : event[conf.index] = callback
}
/**
* on a async event callback.
* @param {String} name - The event name.
* @param {Object} conf - The event callback conf.
* @param {EventManager~eventCallback} callback - The event callback.
* @param {Boolean} immediately
*/
onAsync(name, conf, callback, immediately = false) {
callback.async = true;
this._on(name, conf, callback, immediately)
}
/**
* on a event callback.
* @param {String} name - The event name.
* @param {Object} conf - The event callback conf.
* @param {EventManager~eventCallback} callback - The event callback.
* @param {Boolean} immediately
*/
on(name, conf, callback, immediately = false) {
callback.async = false;
this._on(name, conf, callback, immediately)
}
/**
* This eventCallback is added a event event.
* @callback eventManager~eventCallback
* @param {EventManager} eventManager
* @param {Object} callback info.
*/
/**
* Stop eventManager.
*/
stop() {
this.trigger('eventManagerStop');
this.trigger('isEventManagerStop')
}
/**
* Determines whether the eventManager is stopped.
*/
isStop() {
return this.eventCallbackFibers.length == 1 && this.eventCallbackFibers[0].name == 'isEventManagerStop'
}
// helper function
/**
* kill the designated event callback.
* @param {String|RegExp} name - The event name. It can be a regexp(exact match).
*/
killEventCallback(name) {
if(typeof name == "string") {
this.eventCallbackFibers.forEach((obj)=>{
if(obj.name == name) this.eventCallbackFibers.delete(obj)
})
} else {
this.eventCallbackFibers.forEach((obj)=>{
if(obj.name.match(name) == obj.name) this.eventCallbackFibers.delete(obj)
})
}
}
/**
* if the event callback is running, it returns true.
* @param {String|RegExp} name - The event name. It can be a regexp(exact match).
* @returns {boolean}
*/
isEventCallbackRun(name) {
let back = false;
if(typeof name == "string") {
this.eventCallbackFibers.forEach((obj)=>{if(obj.name == name) return back = true})
} else {
this.eventCallbackFibers.forEach((obj)=>{if(obj.name.match(name) == obj.name) return back = true})
}
return back
}
/**
* Helper methods.<br>
* Delete this callback.
*/
delete() {
this.afterDelete();
Fiber.yield(true)
}
/**
* Helper methods.<br>
* Delete this callback.
*/
afterDelete() {
let event = this.events[this.self.name];
let index = event.indexOf(this.self.callback);
event.splice(index, 1)
}
/**
* Helper methods.<br>
* isOk.
* @param {EventManager~isOkCallback} callback
*/
isOk(callback) {
while(true){
if(callback()) break;
Fiber.yield()
}
}
/**
* This isOkCallback is added a event event.
* @callback eventManager~isOkCallback
* @return {Boolean} The callback function executes the result.
*/
/**
* Helper methods.<br>
* @param {EventManager~filterCallback} callback
*/
filter(callback) {
if(!callback()) Fiber.yield(true)
}
/**
* This filterCallback is added a event event.
* @callback eventManager~filterCallback
* @return {Boolean} The callback function executes the result.
*/
/**
* Helper methods.<br>
* @param {Number} value - sec.
*/
wait(value) {
if(this.timers[this.self.objectId] == void 0) this.timers[this.self.objectId] = Date.now();
while(true) {
if(Date.now() - this.timers[this.self.objectId] > value * 1000) break;
Fiber.yield()
}
this.timers.delete(this.self.objectId)
}
/**
* Helper methods.<br>
* @param {Number} value - times.
*/
times(value) {
if (this.counters[this.self.name]) {
this.counters[this.self.name] += 1;
} else {
this.counters[this.self.name] = 1;
}
while(true) {
if(this.counters[this.self.name] >= value) {
this.counters[this.self.name] = 0;
break
}
Fiber.yield()
}
}
/**
* Helper methods.<br>
* @param {Number} value - sec.
*/
waitFilter(value) {
if(!this.timerFilters[this.self.name]) this.timerFilters[this.self.name] = Date.now();
while(true){
if(Date.now() - this.timerFilters[this.self.name] > value * 1000) {
this.timerFilters[this.self.name] = Date.now();
break
}
Fiber.yield(true)
}
}
/**
* Helper methods.<br>
* @param {Number} value - times.
*/
timesFilter(value) {
if( this.counterfilters[this.self.name]) {
this.counterfilters[this.self.name] += 1
} else {
return this.counterfilters[this.self.name] = 1
}
while(true) {
if( this.counterfilters[this.self.name] > value) {
this.counterfilters[this.self.name] = 0;
break
}
Fiber.yield(true)
}
}
}
/**
* @module Svent
*/
const Svent = {
VERSION: '0.0.8',
EventManager: EventManager,
/**
* @method run
* @description Run a Svent server.
* @param {EventManager} eventManager a eventManager object.
* @param {Function} func callback func.
*/
run: function (eventManager, func) {
this.eventManager = eventManager || new this.EventManager();
this.isStop = false;
func(this.eventManager);
while(!this.isStop) {
this.eventManager.update()
}
},
/**
* @method stop
* @description Stop Svent server.
*/
stop: function () {
this.eventManager.onAsync('isEventManagerStop', {}, (em)=>{
em.isOk(()=>{ return em.isStop() });
this.isStop = true
});
this.eventManager.stop()
},
/**
* @method kill
* @description Kill Svent server.
*/
kill: function () {
this.isStop = true
},
};
module.exports = Svent;