您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
 
 
 

293 行
6.2 KiB

  1. let childProcess = require('child_process');
  2. let objects = require('../objects/objects');
  3. let mapList = require('../config/maps/mapList');
  4. let connections = require('../security/connections');
  5. let serverConfig = require('../config/serverConfig');
  6. let events = require('../misc/events');
  7. const listenersOnZoneIdle = [];
  8. module.exports = {
  9. nextId: 0,
  10. lastCallbackId: 0,
  11. threads: [],
  12. callbacks: [],
  13. init: function () {
  14. this.getMapFiles();
  15. },
  16. addObject: function (obj, keepPos, transfer) {
  17. events.emit('onBeforePlayerEnterWorld', obj);
  18. let thread = this.getThreadFromName(obj.zoneName);
  19. let instanceId = obj.instanceId;
  20. if ((!thread) || (obj.zoneName !== thread.name))
  21. instanceId = -1;
  22. if (!thread) {
  23. thread = this.getThreadFromName(serverConfig.defaultZone);
  24. obj.zoneName = thread.name;
  25. }
  26. obj.zone = thread.id;
  27. this.send(obj.zone, {
  28. method: 'addObject',
  29. args: {
  30. keepPos: keepPos,
  31. obj: obj.getSimple ? obj.getSimple(true, true) : obj,
  32. instanceId: instanceId,
  33. transfer: transfer
  34. }
  35. });
  36. },
  37. removeObject: function (obj, skipLocal, callback) {
  38. if (!skipLocal)
  39. objects.removeObject(obj);
  40. let thread = this.getThreadFromName(obj.zoneName);
  41. if (!thread)
  42. return;
  43. let callbackId = null;
  44. if (callback)
  45. callbackId = this.registerCallback(callback);
  46. obj.zone = thread.id;
  47. this.send(obj.zone, {
  48. method: 'removeObject',
  49. args: {
  50. obj: obj.getSimple(true),
  51. instanceId: obj.instanceId,
  52. callbackId: callbackId
  53. }
  54. });
  55. },
  56. updateObject: function (obj, msgObj) {
  57. this.send(obj.zone, {
  58. method: 'updateObject',
  59. args: {
  60. id: obj.id,
  61. instanceId: obj.instanceId,
  62. obj: msgObj
  63. }
  64. });
  65. },
  66. queueAction: function (obj, action) {
  67. this.send(obj.zone, {
  68. method: 'queueAction',
  69. args: {
  70. id: obj.id,
  71. instanceId: obj.instanceId,
  72. action: action
  73. }
  74. });
  75. },
  76. performAction: function (obj, action) {
  77. this.send(obj.zone, {
  78. method: 'performAction',
  79. args: {
  80. id: obj.id,
  81. instanceId: obj.instanceId,
  82. action: action
  83. }
  84. });
  85. },
  86. registerCallback: function (callback) {
  87. this.callbacks.push({
  88. id: ++this.lastCallbackId,
  89. callback: callback
  90. });
  91. return this.lastCallbackId;
  92. },
  93. resolveCallback: function (msg) {
  94. let callback = this.callbacks.spliceFirstWhere(c => c.id === msg.msg.id);
  95. if (!callback)
  96. return;
  97. callback.callback(msg.msg.result);
  98. },
  99. send: function (zone, msg) {
  100. let thread = this.getThreadFromId(zone);
  101. if (thread)
  102. thread.worker.send(msg);
  103. },
  104. getThreadFromId: function (id) {
  105. return this.threads.find(t => t.id === id);
  106. },
  107. getThreadFromName: function (name) {
  108. return this.threads.find(t => t.name === name);
  109. },
  110. getMapFiles: function () {
  111. mapList.mapList.filter(m => !m.disabled).forEach(m => this.spawnMap(m));
  112. },
  113. spawnMap: function (map) {
  114. const worker = childProcess.fork('./world/worker', [map.name]);
  115. const thread = {
  116. id: this.nextId++,
  117. name: map.name,
  118. path: map.path,
  119. worker
  120. };
  121. const onMessage = this.onMessage.bind(this, thread);
  122. worker.on('message', function (m) {
  123. onMessage(m);
  124. });
  125. this.threads.push(thread);
  126. },
  127. onMessage: function (thread, message) {
  128. if (message.module) {
  129. try {
  130. global[message.module][message.method](message);
  131. } catch (e) {
  132. console.log('No global method found', message.module, message.method);
  133. process.exit();
  134. }
  135. } else if (message.event === 'onCrashed') {
  136. thread.worker.kill();
  137. process.exit();
  138. } else
  139. this.thread[message.method].call(this, thread, message);
  140. },
  141. messageAllThreads: function (message) {
  142. this.threads.forEach(t => t.worker.send(message));
  143. },
  144. fireEventOnAllThreads: function ({ msg: { event, data } }) {
  145. this.threads.forEach(t => t.worker.send({ event, data }));
  146. },
  147. thread: {
  148. onReady: function (thread) {
  149. thread.worker.send({
  150. method: 'init',
  151. args: {
  152. name: thread.name,
  153. path: thread.path,
  154. zoneId: thread.id
  155. }
  156. });
  157. },
  158. event: function (thread, message) {
  159. objects.sendEvent(message, thread);
  160. },
  161. events: function (thread, message) {
  162. objects.sendEvents(message, thread);
  163. },
  164. object: function (thread, message) {
  165. objects.updateObject(message);
  166. },
  167. track: function (thread, message) {
  168. let player = objects.objects.find(o => o.id === message.serverId);
  169. if (!player)
  170. return;
  171. player.auth.gaTracker.track(message.obj);
  172. },
  173. callDifferentThread: function (thread, message) {
  174. let obj = connections.players.find(p => (p.name === message.playerName));
  175. if (!obj)
  176. return;
  177. let newThread = this.getThreadFromName(obj.zoneName);
  178. if (!newThread)
  179. return;
  180. newThread.worker.send({
  181. module: message.data.module,
  182. method: message.data.method,
  183. args: message.data.args
  184. });
  185. },
  186. rezone: function (thread, message) {
  187. const { args: { obj, newZone, keepPos = true } } = message;
  188. obj.destroyed = false;
  189. obj.zoneName = newZone;
  190. obj.id = obj.serverId;
  191. let serverObj = objects.objects.find(o => o.id === obj.id);
  192. serverObj.zoneName = obj.zoneName;
  193. let newThread = this.getThreadFromName(obj.zoneName);
  194. if (!newThread) {
  195. newThread = this.getThreadFromName(serverConfig.defaultZone);
  196. obj.zoneName = newThread.name;
  197. serverObj.zoneName = newThread.name;
  198. }
  199. serverObj.zone = newThread.id;
  200. obj.zone = newThread.id;
  201. serverObj.player.broadcastSelf();
  202. const isRezone = true;
  203. this.addObject(obj, keepPos, isRezone);
  204. },
  205. onZoneIdle: function (thread) {
  206. listenersOnZoneIdle.forEach(l => l(thread));
  207. }
  208. },
  209. returnWhenZonesIdle: async function () {
  210. return new Promise(res => {
  211. const waiting = [...this.threads];
  212. const onZoneIdle = thread => {
  213. waiting.spliceWhere(w => w === thread);
  214. if (waiting.length)
  215. return;
  216. listenersOnZoneIdle.spliceWhere(l => l === onZoneIdle);
  217. res();
  218. };
  219. listenersOnZoneIdle.push(onZoneIdle);
  220. this.threads.forEach(t => {
  221. t.worker.send({
  222. method: 'notifyOnceIdle'
  223. });
  224. });
  225. });
  226. },
  227. forceSavePlayer: async function (playerName, zoneName) {
  228. const thread = this.getThreadFromName(zoneName);
  229. if (!thread)
  230. return;
  231. return new Promise(res => {
  232. const callbackId = this.registerCallback(res);
  233. thread.worker.send({
  234. method: 'forceSavePlayer',
  235. args: {
  236. playerName,
  237. callbackId
  238. }
  239. });
  240. });
  241. }
  242. };