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.
 
 
 

210 lines
4.3 KiB

  1. //External Modules
  2. const objects = require('../objects/objects');
  3. //Helpers
  4. const { route, routeGlobal } = require('./connections/route');
  5. //Module
  6. module.exports = {
  7. players: [],
  8. sockets: null,
  9. playing: 0,
  10. onHandshake: function (socket) {
  11. if (this.players.some(f => f.socket.id === socket.id))
  12. return;
  13. const p = objects.build();
  14. p.socket = socket;
  15. p.addComponent('auth');
  16. p.addComponent('player');
  17. objects.pushObjectToList(p);
  18. this.players.push(p);
  19. },
  20. onDisconnect: async function (socket) {
  21. let player = this.players.find(p => p.socket.id === socket.id);
  22. if (!player)
  23. return;
  24. let sessionDuration = 0;
  25. if (player.has('id')) {
  26. if (player.social)
  27. player.social.dc();
  28. sessionDuration = ~~(((+new Date()) - player.player.sessionStart) / 1000);
  29. atlas.updateObject(player, {
  30. components: [{
  31. type: 'stats',
  32. sessionDuration: sessionDuration
  33. }]
  34. });
  35. //If the player doesn't have a 'social' component, they are no longer in a threat
  36. // Likely due to unzoning (character select screen)
  37. // Also, rezoning is set to true while rezoning so we don't try to remove objects
  38. // from zones if they are currently rezoning
  39. if (player.components.some(c => c.type === 'social') && player.rezoning !== true) {
  40. await new Promise(res => {
  41. atlas.removeObject(player, false, res);
  42. });
  43. }
  44. }
  45. if (player.name) {
  46. this.emit('events', {
  47. onGetMessages: [{
  48. messages: [{
  49. class: 'color-blueB',
  50. message: player.name + ' has gone offline'
  51. }]
  52. }],
  53. onGetDisconnectedPlayer: [player.name]
  54. });
  55. if (player.has('id'))
  56. this.modifyPlayerCount(-1);
  57. }
  58. this.players.spliceWhere(p => p.socket.id === socket.id);
  59. },
  60. route: function (socket, msg) {
  61. route.call(this, socket, msg);
  62. },
  63. routeGlobal: function (msg) {
  64. routeGlobal.call(this, msg);
  65. },
  66. unzone: async function (msg) {
  67. let socket = msg.socket;
  68. let player = this.players.find(p => p.socket.id === socket.id);
  69. if (!player)
  70. return;
  71. if (player.social)
  72. player.social.dc();
  73. await new Promise(res => {
  74. atlas.removeObject(player, true, res);
  75. });
  76. let keys = Object.keys(player);
  77. keys.forEach(function (k) {
  78. let val = player[k];
  79. if (val && val.type) {
  80. if (['player', 'auth', 'syncer'].indexOf(val.type) === -1) {
  81. delete player[k];
  82. player.components.spliceWhere(c => c.type === val.type);
  83. }
  84. }
  85. });
  86. this.emit('events', {
  87. onGetMessages: [{
  88. messages: [{
  89. class: 'color-blueB',
  90. message: player.name + ' has gone offline'
  91. }]
  92. }],
  93. onGetDisconnectedPlayer: [player.name]
  94. });
  95. //If we don't do this, the atlas will try to remove it from the thread
  96. delete player.zoneName;
  97. delete player.name;
  98. //A hack to allow us to actually call methods again (like retrieve the player list)
  99. player.dead = false;
  100. player.permadead = false;
  101. delete player.auth.charname;
  102. this.modifyPlayerCount(-1);
  103. msg.callback();
  104. },
  105. logOut: async function (exclude) {
  106. const { players } = this;
  107. let pLen = players.length;
  108. for (let i = 0; i < pLen; i++) {
  109. const p = players[i];
  110. if (!p || p === exclude || !p.auth)
  111. continue;
  112. else if (p.auth.username === exclude.auth.username) {
  113. if (p.name && p.zoneId)
  114. await atlas.forceSavePlayer(p.id, p.zoneId);
  115. if (p.socket?.connected)
  116. p.socket.emit('dc', {});
  117. else {
  118. players.splice(i, 1);
  119. i--;
  120. pLen--;
  121. }
  122. }
  123. }
  124. },
  125. emit: function (event, msg) {
  126. this.sockets.emit(event, msg);
  127. },
  128. getCharacterList: function () {
  129. let result = [];
  130. let players = this.players;
  131. let pLen = players.length;
  132. for (let i = 0; i < pLen; i++) {
  133. let p = players[i];
  134. if (!p.name)
  135. continue;
  136. result.push({
  137. zoneName: p.zoneName,
  138. zoneId: p.zoneId,
  139. name: p.name,
  140. level: p.level,
  141. class: p.class,
  142. id: p.id
  143. });
  144. }
  145. return result;
  146. },
  147. forceSaveAll: async function () {
  148. const promises = this.players
  149. .filter(p => p.zoneName !== undefined)
  150. .map(p => {
  151. const promise = new Promise(res => {
  152. const msg = {
  153. cpn: 'auth',
  154. method: 'doSaveManual',
  155. data: {
  156. callbackId: atlas.registerCallback(res)
  157. }
  158. };
  159. atlas.performAction(p, msg);
  160. });
  161. return promise;
  162. });
  163. await Promise.all(promises);
  164. },
  165. modifyPlayerCount: function (delta) {
  166. this.playing += delta;
  167. }
  168. };