Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.
 
 
 

554 рядки
13 KiB

  1. let map = require('./map');
  2. let syncer = require('./syncer');
  3. let objects = require('../objects/objects');
  4. let spawners = require('./spawners');
  5. let physics = require('./physics');
  6. let resourceSpawner = require('./resourceSpawner');
  7. let spellCallbacks = require('../config/spells/spellCallbacks');
  8. let questBuilder = require('../config/quests/questBuilder');
  9. let randomMap = require('./randomMap');
  10. let customMap = require('./customMap');
  11. let events = require('../events/events');
  12. let scheduler = require('../misc/scheduler');
  13. let mail = require('../misc/mail');
  14. let herbs = require('../config/herbs');
  15. let eventEmitter = require('../misc/events');
  16. module.exports = {
  17. instances: [],
  18. zoneId: -1,
  19. speed: 350,
  20. lastTime: 0,
  21. init: function (args) {
  22. this.zoneId = args.zoneId;
  23. spellCallbacks.init();
  24. herbs.init();
  25. map.init(args);
  26. if (!map.instanced) {
  27. let fakeInstance = {
  28. objects: objects,
  29. syncer: syncer,
  30. physics: physics,
  31. zoneId: this.zoneId,
  32. spawners: spawners,
  33. questBuilder: questBuilder,
  34. events: events,
  35. zone: map.zone,
  36. mail: mail,
  37. map: map,
  38. scheduler: scheduler,
  39. eventEmitter: eventEmitter,
  40. zone: map.zone
  41. };
  42. this.instances.push(fakeInstance);
  43. spawners.init(fakeInstance);
  44. scheduler.init();
  45. map.create();
  46. map.clientMap.zoneId = this.zoneId;
  47. [resourceSpawner, syncer, objects, questBuilder, events, mail].forEach(i => i.init(fakeInstance));
  48. this.addObject = this.nonInstanced.addObject.bind(this);
  49. this.onAddObject = this.nonInstanced.onAddObject.bind(this);
  50. this.updateObject = this.nonInstanced.updateObject.bind(this);
  51. this.queueAction = this.nonInstanced.queueAction.bind(this);
  52. this.performAction = this.nonInstanced.performAction.bind(this);
  53. this.removeObject = this.nonInstanced.removeObject.bind(this);
  54. this.onRemoveObject = this.nonInstanced.onRemoveObject.bind(this);
  55. this.tick = this.nonInstanced.tick.bind(this);
  56. this.tick();
  57. } else {
  58. spawners.init({
  59. zone: map.zone
  60. });
  61. map.create();
  62. map.clientMap.zoneId = this.zoneId;
  63. this.addObject = this.instanced.addObject.bind(this);
  64. this.onAddObject = this.instanced.onAddObject.bind(this);
  65. this.updateObject = this.instanced.updateObject.bind(this);
  66. this.queueAction = this.instanced.queueAction.bind(this);
  67. this.performAction = this.instanced.performAction.bind(this);
  68. this.removeObject = this.instanced.removeObject.bind(this);
  69. this.onRemoveObject = this.instanced.onRemoveObject.bind(this);
  70. if (map.mapFile.properties.isRandom)
  71. this.ttlGen = 0;
  72. this.tick = this.instanced.tick.bind(this);
  73. this.tick();
  74. }
  75. },
  76. nonInstanced: {
  77. tick: function () {
  78. events.update();
  79. objects.update();
  80. resourceSpawner.update();
  81. spawners.update();
  82. syncer.update();
  83. scheduler.update();
  84. setTimeout(this.tick.bind(this), this.speed);
  85. },
  86. addObject: function (msg) {
  87. let obj = msg.obj;
  88. obj.serverId = obj.id;
  89. delete obj.id;
  90. if ((msg.keepPos) && (!physics.isValid(obj.x, obj.y)))
  91. msg.keepPos = false;
  92. let spawnPos = map.getSpawnPos(obj);
  93. if ((!msg.keepPos) || (obj.x == null)) {
  94. obj.x = spawnPos.x;
  95. obj.y = spawnPos.y;
  96. }
  97. obj.spawn = map.spawn;
  98. syncer.queue('onGetMap', map.clientMap, [obj.serverId]);
  99. if (!msg.transfer)
  100. objects.addObject(obj, this.onAddObject.bind(this));
  101. else {
  102. let o = objects.transferObject(obj);
  103. questBuilder.obtain(o);
  104. }
  105. },
  106. onAddObject: function (obj) {
  107. if (obj.player)
  108. obj.stats.onLogin();
  109. questBuilder.obtain(obj);
  110. obj.fireEvent('afterMove');
  111. if (obj.dead) {
  112. obj.instance.syncer.queue('onDeath', {
  113. x: obj.x,
  114. y: obj.y
  115. }, [obj.serverId]);
  116. }
  117. },
  118. updateObject: function (msg) {
  119. let obj = objects.find(o => o.serverId == msg.id);
  120. if (!obj)
  121. return;
  122. let msgObj = msg.obj;
  123. let components = msgObj.components || [];
  124. delete msgObj.components;
  125. for (let p in msgObj)
  126. obj[p] = msgObj[p];
  127. let cLen = components.length;
  128. for (let i = 0; i < cLen; i++) {
  129. let c = components[i];
  130. let component = obj[c.type];
  131. for (let p in c)
  132. component[p] = c[p];
  133. }
  134. },
  135. queueAction: function (msg) {
  136. let obj = objects.find(o => o.serverId == msg.id);
  137. if (!obj)
  138. return;
  139. else if (msg.action.action == 'move') {
  140. let moveEntries = obj.actionQueue.filter(q => (q.action == 'move')).length;
  141. if (moveEntries >= 50)
  142. return;
  143. }
  144. obj.queue(msg.action);
  145. },
  146. performAction: function (msg) {
  147. let obj = null;
  148. let targetId = msg.action.targetId;
  149. if (!targetId)
  150. obj = objects.find(o => o.serverId == msg.id);
  151. else {
  152. obj = objects.find(o => o.id == targetId);
  153. if (obj) {
  154. let action = msg.action;
  155. if (!action.data)
  156. action.data = {};
  157. action.data.sourceId = msg.id;
  158. }
  159. }
  160. if (!obj)
  161. return;
  162. obj.performAction(msg.action);
  163. },
  164. removeObject: function (msg) {
  165. let obj = msg.obj;
  166. obj = objects.find(o => o.serverId == obj.id);
  167. if (!obj) {
  168. //We should probably never reach this
  169. return;
  170. }
  171. if (obj.auth)
  172. obj.auth.doSave();
  173. if (obj.player)
  174. obj.fireEvent('beforeRezone');
  175. obj.destroyed = true;
  176. },
  177. onRemoveObject: function (obj) {
  178. }
  179. },
  180. instanced: {
  181. tick: function () {
  182. if (map.mapFile.properties.isRandom) {
  183. if (this.ttlGen <= 0) {
  184. if (!map.oldMap)
  185. map.oldMap = map.clientMap.map;
  186. if (!map.oldCollisionMap)
  187. map.oldCollisionMap = map.collisionMap;
  188. spawners.reset();
  189. randomMap.generate({
  190. map: map,
  191. physics: physics,
  192. spawners: spawners
  193. });
  194. this.ttlGen = 2000;
  195. } else
  196. this.ttlGen--;
  197. }
  198. let instances = this.instances;
  199. let iLen = instances.length;
  200. for (let i = 0; i < iLen; i++) {
  201. let instance = instances[i];
  202. instance.objects.update();
  203. instance.spawners.update();
  204. instance.resourceSpawner.update();
  205. instance.scheduler.update();
  206. instance.syncer.update();
  207. if (instance.closeTtl != null) {
  208. let hasPlayers = instance.objects.objects.some(o => o.player);
  209. if (hasPlayers) {
  210. delete instance.closeTtl;
  211. continue;
  212. }
  213. instance.closeTtl--;
  214. if (instance.closeTtl <= 0) {
  215. instances.splice(i, 1);
  216. i--;
  217. iLen--;
  218. }
  219. } else {
  220. let isEmpty = !instance.objects.objects.some(o => o.player);
  221. if (isEmpty) {
  222. //Zones reset after being empty for 10 minutes
  223. instance.closeTtl = 2;
  224. }
  225. }
  226. }
  227. setTimeout(this.tick.bind(this), this.speed);
  228. },
  229. addObject: function (msg) {
  230. let obj = msg.obj;
  231. let instanceId = msg.instanceId;
  232. //Maybe a party member is in here already?
  233. let social = obj.components.find(c => c.type == 'social');
  234. if ((social) && (social.party)) {
  235. let party = social.party;
  236. let instances = this.instances;
  237. let iLen = instances.length;
  238. for (let i = 0; i < iLen; i++) {
  239. let instance = instances[i];
  240. let partyInside = instance.objects.objects.some(o => party.indexOf(o.serverId) > -1);
  241. if (partyInside) {
  242. if (instance.id != obj.instanceId)
  243. msg.keepPos = false;
  244. obj.instanceId = instance.id;
  245. obj.instance = instance;
  246. instanceId = instance.id;
  247. break;
  248. }
  249. }
  250. }
  251. if (msg.transfer)
  252. msg.keepPos = false;
  253. let exists = this.instances.find(i => i.id == instanceId);
  254. if (exists) {
  255. if ((msg.keepPos) && (!exists.physics.isValid(obj.x, obj.y)))
  256. msg.keepPos = false;
  257. }
  258. let spawnPos = map.getSpawnPos(obj);
  259. if (exists)
  260. spawnPos = exists.map.getSpawnPos(obj);
  261. if ((!msg.keepPos) || (obj.x == null)) {
  262. obj.x = spawnPos.x;
  263. obj.y = spawnPos.y;
  264. }
  265. obj.spawn = map.spawn;
  266. if (exists) {
  267. //Keep track of what the connection id is (sent from the server)
  268. obj.serverId = obj.id;
  269. delete obj.id;
  270. let spawnPos = exists.map.getSpawnPos(obj);
  271. obj.spawn = exists.map.spawn;
  272. exists.syncer.queue('onGetMap', exists.map.clientMap, [obj.serverId]);
  273. if (!msg.transfer)
  274. exists.objects.addObject(obj, this.onAddObject.bind(this, msg.keepPos));
  275. else {
  276. let newObj = exists.objects.transferObject(obj);
  277. this.onAddObject(false, newObj);
  278. }
  279. process.send({
  280. method: 'object',
  281. serverId: obj.serverId,
  282. obj: {
  283. instanceId: exists.id
  284. }
  285. });
  286. } else
  287. obj = this.instanced.createInstance.call(this, obj, msg.transfer);
  288. },
  289. onAddObject: function (keepPos, obj) {
  290. if (!keepPos) {
  291. let spawnPos = obj.instance.map.getSpawnPos(obj);
  292. obj.x = spawnPos.x;
  293. obj.y = spawnPos.y;
  294. }
  295. obj.instance.questBuilder.obtain(obj);
  296. if (obj.player)
  297. obj.stats.onLogin();
  298. obj.fireEvent('afterMove');
  299. if (obj.dead) {
  300. obj.instance.syncer.queue('onDeath', {
  301. x: obj.x,
  302. y: obj.y
  303. }, [obj.serverId]);
  304. }
  305. },
  306. updateObject: function (msg) {
  307. let id = msg.id;
  308. let instanceId = msg.instanceId;
  309. let exists = this.instances.find(i => i.id == instanceId);
  310. if (!exists)
  311. return;
  312. let obj = exists.objects.find(o => o.serverId == id);
  313. if (!obj)
  314. return;
  315. let msgObj = msg.obj;
  316. let components = msgObj.components || [];
  317. delete msgObj.components;
  318. for (let p in msgObj)
  319. obj[p] = msgObj[p];
  320. let cLen = components.length;
  321. for (let i = 0; i < cLen; i++) {
  322. let c = components[i];
  323. let component = obj[c.type];
  324. for (let p in c)
  325. component[p] = c[p];
  326. }
  327. },
  328. performAction: function (msg) {
  329. let id = msg.id;
  330. let instanceId = msg.instanceId;
  331. let exists = this.instances.find(i => i.id == instanceId);
  332. if (!exists)
  333. return;
  334. let obj = exists.objects.find(o => o.serverId == id);
  335. if (!obj)
  336. return;
  337. obj.performAction(msg.action);
  338. },
  339. queueAction: function (msg) {
  340. let id = msg.id;
  341. let instanceId = msg.instanceId;
  342. let exists = this.instances.find(i => i.id == instanceId);
  343. if (!exists)
  344. return;
  345. let obj = exists.objects.find(o => o.serverId == id);
  346. if (obj) {
  347. if (msg.action.action == 'move') {
  348. let moveEntries = obj.actionQueue.filter(q => (q.action == 'move')).length;
  349. if (moveEntries >= 50)
  350. return;
  351. }
  352. obj.queue(msg.action);
  353. }
  354. },
  355. removeObject: function (msg) {
  356. let obj = msg.obj;
  357. let instanceId = msg.instanceId;
  358. let exists = this.instances.find(i => i.id == instanceId);
  359. if (!exists)
  360. return;
  361. let obj = msg.obj;
  362. obj = exists.objects.find(o => o.serverId == obj.id);
  363. if (!obj)
  364. return;
  365. if (obj.auth)
  366. obj.auth.doSave();
  367. obj.destroyed = true;
  368. },
  369. onRemoveObject: function (obj) {
  370. },
  371. createInstance: function (objToAdd, transfer) {
  372. let newMap = {
  373. name: map.name,
  374. spawn: extend(true, [], map.spawn),
  375. clientMap: extend(true, {}, map.clientMap)
  376. };
  377. newMap.getSpawnPos = map.getSpawnPos.bind(newMap);
  378. //Hack: We need to actually just always use the instanced eventEmitter
  379. let eventQueue = eventEmitter.queue;
  380. delete eventEmitter.queue;
  381. let newEventEmitter = extend(true, {
  382. queue: []
  383. }, eventEmitter);
  384. eventEmitter.queue = eventQueue;
  385. let instance = {
  386. id: objToAdd.name + '_' + (+new Date()),
  387. objects: extend(true, {}, objects),
  388. spawners: extend(true, {}, spawners),
  389. syncer: extend(true, {}, syncer),
  390. physics: extend(true, {}, physics),
  391. resourceSpawner: extend(true, {}, resourceSpawner),
  392. zoneId: this.zoneId,
  393. zone: map.zone,
  394. closeTtl: null,
  395. questBuilder: extend(true, {}, questBuilder),
  396. events: extend(true, {}, events),
  397. scheduler: extend(true, {}, scheduler),
  398. mail: extend(true, {}, mail),
  399. map: newMap,
  400. eventEmitter: newEventEmitter,
  401. instanced: true
  402. };
  403. ['objects', 'spawners', 'syncer', 'resourceSpawner', 'questBuilder', 'events', 'scheduler', 'mail'].forEach(i => instance[i].init(instance));
  404. this.instances.push(instance);
  405. let onDone = this.instanced.onCreateInstance.bind(this, instance, objToAdd, transfer);
  406. if (map.custom) {
  407. instance.customMap = extend(true, {}, customMap);
  408. instance.customMap.load(instance, objToAdd, onDone);
  409. } else
  410. onDone();
  411. },
  412. onCreateInstance: function (instance, objToAdd, transfer) {
  413. objToAdd.instance = instance;
  414. objToAdd.instanceId = instance.id;
  415. //Keep track of what the connection id is (sent from the server)
  416. objToAdd.serverId = objToAdd.id;
  417. delete objToAdd.id;
  418. let obj = null;
  419. instance.syncer.queue('onGetMap', instance.map.clientMap, [objToAdd.serverId]);
  420. if (!transfer)
  421. obj = instance.objects.addObject(objToAdd, this.onAddObject.bind(this, false));
  422. else {
  423. obj = instance.objects.transferObject(objToAdd);
  424. let spawnPos = instance.map.getSpawnPos(obj);
  425. obj.x = spawnPos.x;
  426. obj.y = spawnPos.y;
  427. instance.questBuilder.obtain(obj);
  428. }
  429. process.send({
  430. method: 'object',
  431. serverId: obj.serverId,
  432. obj: {
  433. instanceId: instance.id
  434. }
  435. });
  436. if (obj.dead) {
  437. obj.instance.syncer.queue('onDeath', {
  438. x: obj.x,
  439. y: obj.y
  440. }, [obj.serverId]);
  441. }
  442. return obj;
  443. }
  444. }
  445. };