radar4mob
Version:
Detects and emits an event when the position of an mob with coordinates changes.
380 lines (373 loc) • 12.4 kB
JavaScript
"use strict";
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __commonJS = (cb, mod) => function __require() {
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
};
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// node_modules/eventemitter3/index.js
var require_eventemitter3 = __commonJS({
"node_modules/eventemitter3/index.js"(exports, module2) {
"use strict";
var has = Object.prototype.hasOwnProperty;
var prefix = "~";
function Events() {
}
if (Object.create) {
Events.prototype = /* @__PURE__ */ Object.create(null);
if (!new Events().__proto__) prefix = false;
}
function EE(fn, context, once) {
this.fn = fn;
this.context = context;
this.once = once || false;
}
function addListener(emitter, event, fn, context, once) {
if (typeof fn !== "function") {
throw new TypeError("The listener must be a function");
}
var listener = new EE(fn, context || emitter, once), evt = prefix ? prefix + event : event;
if (!emitter._events[evt]) emitter._events[evt] = listener, emitter._eventsCount++;
else if (!emitter._events[evt].fn) emitter._events[evt].push(listener);
else emitter._events[evt] = [emitter._events[evt], listener];
return emitter;
}
function clearEvent(emitter, evt) {
if (--emitter._eventsCount === 0) emitter._events = new Events();
else delete emitter._events[evt];
}
function EventEmitter2() {
this._events = new Events();
this._eventsCount = 0;
}
EventEmitter2.prototype.eventNames = function eventNames() {
var names = [], events, name;
if (this._eventsCount === 0) return names;
for (name in events = this._events) {
if (has.call(events, name)) names.push(prefix ? name.slice(1) : name);
}
if (Object.getOwnPropertySymbols) {
return names.concat(Object.getOwnPropertySymbols(events));
}
return names;
};
EventEmitter2.prototype.listeners = function listeners(event) {
var evt = prefix ? prefix + event : event, handlers = this._events[evt];
if (!handlers) return [];
if (handlers.fn) return [handlers.fn];
for (var i = 0, l = handlers.length, ee = new Array(l); i < l; i++) {
ee[i] = handlers[i].fn;
}
return ee;
};
EventEmitter2.prototype.listenerCount = function listenerCount(event) {
var evt = prefix ? prefix + event : event, listeners = this._events[evt];
if (!listeners) return 0;
if (listeners.fn) return 1;
return listeners.length;
};
EventEmitter2.prototype.emit = function emit(event, a1, a2, a3, a4, a5) {
var evt = prefix ? prefix + event : event;
if (!this._events[evt]) return false;
var listeners = this._events[evt], len = arguments.length, args, i;
if (listeners.fn) {
if (listeners.once) this.removeListener(event, listeners.fn, void 0, true);
switch (len) {
case 1:
return listeners.fn.call(listeners.context), true;
case 2:
return listeners.fn.call(listeners.context, a1), true;
case 3:
return listeners.fn.call(listeners.context, a1, a2), true;
case 4:
return listeners.fn.call(listeners.context, a1, a2, a3), true;
case 5:
return listeners.fn.call(listeners.context, a1, a2, a3, a4), true;
case 6:
return listeners.fn.call(listeners.context, a1, a2, a3, a4, a5), true;
}
for (i = 1, args = new Array(len - 1); i < len; i++) {
args[i - 1] = arguments[i];
}
listeners.fn.apply(listeners.context, args);
} else {
var length = listeners.length, j;
for (i = 0; i < length; i++) {
if (listeners[i].once) this.removeListener(event, listeners[i].fn, void 0, true);
switch (len) {
case 1:
listeners[i].fn.call(listeners[i].context);
break;
case 2:
listeners[i].fn.call(listeners[i].context, a1);
break;
case 3:
listeners[i].fn.call(listeners[i].context, a1, a2);
break;
case 4:
listeners[i].fn.call(listeners[i].context, a1, a2, a3);
break;
default:
if (!args) for (j = 1, args = new Array(len - 1); j < len; j++) {
args[j - 1] = arguments[j];
}
listeners[i].fn.apply(listeners[i].context, args);
}
}
}
return true;
};
EventEmitter2.prototype.on = function on(event, fn, context) {
return addListener(this, event, fn, context, false);
};
EventEmitter2.prototype.once = function once(event, fn, context) {
return addListener(this, event, fn, context, true);
};
EventEmitter2.prototype.removeListener = function removeListener(event, fn, context, once) {
var evt = prefix ? prefix + event : event;
if (!this._events[evt]) return this;
if (!fn) {
clearEvent(this, evt);
return this;
}
var listeners = this._events[evt];
if (listeners.fn) {
if (listeners.fn === fn && (!once || listeners.once) && (!context || listeners.context === context)) {
clearEvent(this, evt);
}
} else {
for (var i = 0, events = [], length = listeners.length; i < length; i++) {
if (listeners[i].fn !== fn || once && !listeners[i].once || context && listeners[i].context !== context) {
events.push(listeners[i]);
}
}
if (events.length) this._events[evt] = events.length === 1 ? events[0] : events;
else clearEvent(this, evt);
}
return this;
};
EventEmitter2.prototype.removeAllListeners = function removeAllListeners(event) {
var evt;
if (event) {
evt = prefix ? prefix + event : event;
if (this._events[evt]) clearEvent(this, evt);
} else {
this._events = new Events();
this._eventsCount = 0;
}
return this;
};
EventEmitter2.prototype.off = EventEmitter2.prototype.removeListener;
EventEmitter2.prototype.addListener = EventEmitter2.prototype.on;
EventEmitter2.prefixed = prefix;
EventEmitter2.EventEmitter = EventEmitter2;
if ("undefined" !== typeof module2) {
module2.exports = EventEmitter2;
}
}
});
// src/index.ts
var src_exports = {};
__export(src_exports, {
Area: () => Area,
Mob: () => Mob
});
module.exports = __toCommonJS(src_exports);
// node_modules/eventemitter3/index.mjs
var import_index = __toESM(require_eventemitter3(), 1);
var eventemitter3_default = import_index.default;
// src/Position.ts
var Position = class {
__area;
__mob;
__x = 0;
__y = 0;
__z = 0;
__w = 0;
static GetDistance(a, b) {
const x = Math.abs(a.__x) - Math.abs(b.__x);
const y = Math.abs(a.__y) - Math.abs(b.__y);
const z = Math.abs(a.__z) - Math.abs(b.__z);
const w = Math.abs(a.__w) - Math.abs(b.__w);
return Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2) + Math.pow(z, 2) + Math.pow(w, 2));
}
constructor(area, mob) {
this.__area = area;
this.__mob = mob;
}
get x() {
return this.__x;
}
get y() {
return this.__y;
}
get z() {
return this.__z;
}
get w() {
return this.__w;
}
set x(v) {
this.__x = v;
this.__area.dirties.add(this.__mob);
}
set y(v) {
this.__y = v;
this.__area.dirties.add(this.__mob);
}
set z(v) {
this.__z = v;
this.__area.dirties.add(this.__mob);
}
set w(v) {
this.__w = v;
this.__area.dirties.add(this.__mob);
}
set(x, y = 0, z = 0, w = 0) {
if (typeof x === "number") {
this.x = x;
this.y = y;
this.z = z;
this.w = w;
} else {
this.x = x.x ?? this.x;
this.y = x.y ?? this.y;
this.z = x.z ?? this.z;
this.w = x.w ?? this.w;
}
return this;
}
};
// src/Mob.ts
var Mob = class {
id;
position;
emitter;
neighbors = /* @__PURE__ */ new Set();
__thresholdRadius;
area;
constructor(id, thresholdRadius, area) {
this.id = id;
this.area = area;
this.position = new Position(area, this);
this.emitter = new eventemitter3_default();
this.__thresholdRadius = thresholdRadius;
this.__setDirty();
}
get thresholdRadius() {
return this.__thresholdRadius;
}
set thresholdRadius(v) {
this.__thresholdRadius = v;
this.area.dirties.add(this);
}
__setDirty() {
this.area.dirties.add(this);
}
/**
* It is same as `area.removeMob(mob.id)`
*/
destroy() {
this.neighbors.clear();
this.area.dirties.delete(this);
this.area.mobs.delete(this.id);
this.area.mobs.forEach((mob) => {
const isExists = mob.neighbors.delete(this);
if (isExists) {
mob.emitter.emit("out", this);
}
});
}
};
// src/Area.ts
var Area = class {
mobs = /* @__PURE__ */ new Map();
dirties = /* @__PURE__ */ new Set();
/**
* Create a new mobility object. You can use `mob.id` property for `getMob` or `removeMob` method.
* @param id Mobility identifier. If same id is already exists, it will be not create mob and returns exists one.
* @param thresholdRadius Sight of mob.
*/
addMob(id, thresholdRadius) {
const alreadyExists = this.getMob(id);
if (alreadyExists) {
return alreadyExists;
}
const mob = new Mob(id, thresholdRadius, this);
this.mobs.set(mob.id, mob);
return mob;
}
/**
* Get a added mobility object from area instance. If object not exists, It will be returns `null`.
* @param id Mobility identifier what you want find.
*/
getMob(id) {
return this.mobs.get(id) || null;
}
/**
* Remove a added mobility. If object exists, returns `true`. otherwise, returns `false`.
* @param id Mobility identifier what you want remove.
*/
removeMob(id) {
const mob = this.getMob(id);
if (mob) {
mob.destroy();
}
return !!mob;
}
/**
* When this function is called, an 'in', 'out' event emits according to the coordinates of the mob.
*/
update() {
for (const dirty of this.dirties) {
for (const current of this.mobs.values()) {
if (current === dirty) {
continue;
}
const isNeighbor = dirty.neighbors.has(current);
const threshold = dirty.thresholdRadius;
const distance = Position.GetDistance(dirty.position, current.position);
if (isNeighbor && threshold < distance) {
dirty.emitter.emit("out", current);
dirty.neighbors.delete(current);
} else if (!isNeighbor && threshold > distance) {
dirty.emitter.emit("in", current);
dirty.neighbors.add(current);
}
}
}
this.dirties.clear();
}
/**
* Destroys all mob.
*/
destroy() {
this.mobs.forEach((mob) => mob.destroy());
this.mobs.clear();
this.dirties.clear();
}
};