You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

379 lines
7.2 KiB

  1. const eventEmitter = require('../misc/events');
  2. let objBase = require('./objBase');
  3. module.exports = {
  4. lastId: 0,
  5. instance: null,
  6. objects: [],
  7. init: function (_instance) {
  8. this.instance = _instance;
  9. this.physics = this.instance.physics;
  10. },
  11. getNextId: function () {
  12. return ++this.lastId;
  13. },
  14. build: function (isClientObj, id) {
  15. let o = extend({}, objBase);
  16. if (isClientObj)
  17. o.update = null;
  18. else {
  19. o.id = id || this.getNextId();
  20. o.addComponent('syncer');
  21. o.instance = this.instance;
  22. }
  23. return o;
  24. },
  25. pushObjectToList: function (obj) {
  26. this.objects.push(obj);
  27. },
  28. transferObject: function (o) {
  29. const obj = this.build();
  30. let components = o.components;
  31. delete o.components;
  32. delete o.id;
  33. for (let p in o)
  34. obj[p] = o[p];
  35. const cLen = components.length;
  36. for (let i = 0; i < cLen; i++) {
  37. let c = components[i];
  38. const cpn = obj.addComponent(c.type, null, true);
  39. for (let p in c)
  40. cpn[p] = c[p];
  41. if (cpn.transfer)
  42. cpn.transfer();
  43. }
  44. this.pushObjectToList(obj);
  45. this.physics.addObject(obj, obj.x, obj.y);
  46. return obj;
  47. },
  48. buildObjects: function (list, skipPush) {
  49. let lLen = list.length;
  50. for (let i = 0; i < lLen; i++) {
  51. let l = list[i];
  52. let obj = this.build(l.clientObj, l.id);
  53. obj.sheetName = l.sheetName;
  54. obj.cell = l.cell;
  55. obj.name = l.name;
  56. obj.x = l.x;
  57. obj.y = l.y;
  58. if (l.ttl)
  59. obj.ttl = l.ttl;
  60. if (l.width) {
  61. obj.width = l.width;
  62. obj.height = l.height;
  63. }
  64. if (l.area)
  65. obj.area = l.area;
  66. //Add components (certain ones need to happen first)
  67. //TODO: Clean this part up
  68. let properties = extend({}, l.properties);
  69. ['cpnMob'].forEach(function (c) {
  70. let blueprint = properties[c] || null;
  71. if ((blueprint) && (typeof (blueprint) === 'string'))
  72. blueprint = JSON.parse(blueprint);
  73. if (!blueprint)
  74. return;
  75. delete properties[c];
  76. let type = c.replace('cpn', '').toLowerCase();
  77. obj.addComponent(type, blueprint);
  78. }, this);
  79. for (let p in properties) {
  80. if (p.indexOf('cpn') === -1) {
  81. obj[p] = properties[p];
  82. continue;
  83. }
  84. let type = p.replace('cpn', '');
  85. type = type[0].toLowerCase() + type.substr(1);
  86. let blueprint = properties[p] || null;
  87. if ((blueprint) && (typeof (blueprint) === 'string'))
  88. blueprint = JSON.parse(blueprint);
  89. obj.addComponent(type, blueprint);
  90. }
  91. let extraProperties = l.extraProperties || {};
  92. for (let p in extraProperties) {
  93. let cpn = obj[p];
  94. let e = extraProperties[p];
  95. for (let pp in e)
  96. cpn[pp] = e[pp];
  97. if (cpn.init)
  98. cpn.init();
  99. }
  100. if ((this.physics) && (!obj.dead)) {
  101. if (!obj.width)
  102. this.physics.addObject(obj, obj.x, obj.y);
  103. else
  104. this.physics.addRegion(obj);
  105. }
  106. if (obj.aggro)
  107. obj.aggro.move();
  108. if (!skipPush)
  109. this.pushObjectToList(obj);
  110. if (lLen === 1)
  111. return obj;
  112. }
  113. },
  114. find: function (callback) {
  115. return this.objects.find(callback);
  116. },
  117. filter: function (callback) {
  118. return this.objects.filter(callback);
  119. },
  120. removeObject: function (obj, callback, useServerId) {
  121. let found = this.objects.spliceFirstWhere(o => obj.id === (useServerId ? o.serverId : o.id));
  122. if (!found)
  123. return;
  124. let physics = this.physics;
  125. if (physics) {
  126. if (!found.width)
  127. physics.removeObject(found, found.x, found.y);
  128. else
  129. physics.removeRegion(found);
  130. }
  131. found.destroy();
  132. if (callback)
  133. callback(found);
  134. },
  135. addObject: function (o, callback) {
  136. const newO = this.build();
  137. const components = o.components;
  138. delete o.components;
  139. for (let p in o)
  140. newO[p] = o[p];
  141. const len = components.length;
  142. for (let i = 0; i < len; i++) {
  143. const c = components[i];
  144. const newC = newO.addComponent(c.type, c);
  145. extend(newC, c);
  146. }
  147. this.pushObjectToList(newO);
  148. if (!newO.dead)
  149. this.physics.addObject(newO, newO.x, newO.y);
  150. callback(newO);
  151. return newO;
  152. },
  153. sendEvent: function (msg, { name: sourceZone }) {
  154. const { id, data } = msg;
  155. const player = this.objects.find(p => p.id === id);
  156. if (!player || player.zoneName !== sourceZone)
  157. return;
  158. player.socket.emit('event', {
  159. event: data.event,
  160. data: data.data
  161. });
  162. },
  163. sendEvents: function ({ data }, { name: sourceZone }) {
  164. const { objects } = this;
  165. //Store will contain all events to be sent to players
  166. const store = {};
  167. for (let e in data) {
  168. const event = data[e];
  169. const eLen = event.length;
  170. for (let j = 0; j < eLen; j++) {
  171. const eventEntry = event[j];
  172. const { obj: eventObj, to } = eventEntry;
  173. if (e === 'serverModule') {
  174. const { method, msg } = eventObj;
  175. if (Array.isArray(msg))
  176. global[eventObj.module][method](...msg);
  177. else
  178. global[eventObj.module][method](msg);
  179. continue;
  180. }
  181. const toLen = to.length;
  182. for (let i = 0; i < toLen; i++) {
  183. const toId = to[i];
  184. let storeEntry = store[toId];
  185. if (!storeEntry) {
  186. const playerObj = objects.find(o => o.id === toId);
  187. if (!playerObj || playerObj.zoneName !== sourceZone) {
  188. io.setAsync({
  189. key: new Date(),
  190. table: 'error',
  191. value: `ignoring ${e}`
  192. });
  193. continue;
  194. }
  195. store[toId] = {
  196. obj: playerObj,
  197. events: { [e]: [eventObj] }
  198. };
  199. continue;
  200. }
  201. if (!storeEntry.events[e])
  202. storeEntry.events[e] = [];
  203. storeEntry.events[e].push(eventObj);
  204. }
  205. }
  206. }
  207. for (let p in store) {
  208. const { obj: { socket }, events } = store[p];
  209. socket.emit('events', events);
  210. }
  211. },
  212. updateObject: async function (msg) {
  213. let player = this.objects.find(p => p.id === msg.serverId);
  214. if (!player)
  215. return;
  216. let obj = msg.obj;
  217. for (let p in obj)
  218. player[p] = obj[p];
  219. if (obj.permadead)
  220. await leaderboard.killCharacter(player.name);
  221. if (obj.level) {
  222. await leaderboard.setLevel(player.name, obj.level);
  223. cons.emit('events', {
  224. onGetMessages: [{
  225. messages: [{
  226. class: 'color-blueB',
  227. message: player.name + ' has reached level ' + obj.level
  228. }]
  229. }]
  230. });
  231. eventEmitter.emit('playerObjChanged', {
  232. obj: player
  233. });
  234. }
  235. },
  236. notifyCollisionChange: function (x, y, collides) {
  237. this.objects
  238. .filter(o => o.player)
  239. .forEach(function (o) {
  240. o.syncer.setArray(true, 'player', 'collisionChanges', {
  241. x,
  242. y,
  243. collides
  244. });
  245. });
  246. },
  247. notifyMapChange: function (x, y, mapCellString) {
  248. this.objects
  249. .filter(o => o.player)
  250. .forEach(function (o) {
  251. o.syncer.setArray(true, 'player', 'mapChanges', {
  252. x,
  253. y,
  254. mapCellString
  255. });
  256. });
  257. },
  258. update: function () {
  259. let objects = this.objects;
  260. let len = objects.length;
  261. for (let i = 0; i < len; i++) {
  262. let o = objects[i];
  263. //If object A causes object B (layer in the list) to rezone, we won't find it here
  264. if (!o) {
  265. len--;
  266. continue;
  267. }
  268. //Don't remove it from the list if it's destroyed, but don't update it either
  269. //That's syncer's job
  270. if ((o.update) && (!o.destroyed))
  271. o.update();
  272. //When objects are sent to other zones, we destroy them immediately (thhrough sendObjToZone)
  273. if (o.forceDestroy) {
  274. i--;
  275. len--;
  276. continue;
  277. }
  278. if (o.ttl) {
  279. o.ttl--;
  280. if (!o.ttl)
  281. o.destroyed = true;
  282. }
  283. o.fireEvent('afterTick');
  284. }
  285. }
  286. };