@@ -1,5 +1,9 @@ | |||||
//Imports | |||||
const { messageAllThreads } = require('../../world/threadManager'); | |||||
//Exports | |||||
module.exports = async (cpnSocial, eventName) => { | module.exports = async (cpnSocial, eventName) => { | ||||
atlas.messageAllThreads({ | |||||
messageAllThreads({ | |||||
threadModule: 'eventManager', | threadModule: 'eventManager', | ||||
method: 'startEventByCode', | method: 'startEventByCode', | ||||
data: eventName | data: eventName | ||||
@@ -1,5 +1,9 @@ | |||||
//Imports | |||||
const { messageAllThreads } = require('../../world/threadManager'); | |||||
//Exports | |||||
module.exports = async (cpnSocial, eventName) => { | module.exports = async (cpnSocial, eventName) => { | ||||
atlas.messageAllThreads({ | |||||
messageAllThreads({ | |||||
threadModule: 'eventManager', | threadModule: 'eventManager', | ||||
method: 'stopEventByCode', | method: 'stopEventByCode', | ||||
data: eventName | data: eventName | ||||
@@ -1,19 +0,0 @@ | |||||
let events = require('../../misc/events'); | |||||
let config = [ | |||||
{ | |||||
name: 'cave', | |||||
path: 'config/maps' | |||||
}, | |||||
{ | |||||
name: 'fjolarok', | |||||
path: 'config/maps' | |||||
} | |||||
]; | |||||
module.exports = { | |||||
init: function () { | |||||
events.emit('onBeforeGetMapList', config); | |||||
this.mapList = config; | |||||
} | |||||
}; |
@@ -1,7 +1,9 @@ | |||||
let questTemplate = require('./templates/questTemplate'); | |||||
let globalQuests = require('../questsBase'); | |||||
let mapList = require('../maps/mapList'); | |||||
//Imports | |||||
const questTemplate = require('./templates/questTemplate'); | |||||
const globalQuests = require('../questsBase'); | |||||
const { mapList } = require('../../world/mapManager'); | |||||
//Exports | |||||
module.exports = { | module.exports = { | ||||
instance: null, | instance: null, | ||||
@@ -11,7 +13,7 @@ module.exports = { | |||||
obtain: function (obj, template) { | obtain: function (obj, template) { | ||||
let zoneName = template?.zoneName ?? obj.zoneName; | let zoneName = template?.zoneName ?? obj.zoneName; | ||||
let zone = mapList.mapList.find(m => m.name === zoneName); | |||||
let zone = mapList.find(m => m.name === zoneName); | |||||
//Zone doesn't exist any more. Probably been renamed | //Zone doesn't exist any more. Probably been renamed | ||||
if (!zone) | if (!zone) | ||||
@@ -10,7 +10,7 @@ module.exports = { | |||||
//Options: | //Options: | ||||
// sqlite | // sqlite | ||||
// rethink | // rethink | ||||
db: process.env.IWD_DB || 'sqlite', | |||||
db: process.env.IWD_DB || 'rethink', | |||||
dbHost: process.env.IWD_DB_HOST || 'localhost', | dbHost: process.env.IWD_DB_HOST || 'localhost', | ||||
dbPort: process.env.IWD_DB_PORT || 28015, | dbPort: process.env.IWD_DB_PORT || 28015, | ||||
dbName: process.env.IWD_DB_NAME || 'live', | dbName: process.env.IWD_DB_NAME || 'live', | ||||
@@ -1,7 +1,11 @@ | |||||
let phaseTemplate = require('./phases/phaseTemplate'); | |||||
let fs = require('fs'); | |||||
let mapList = require('../config/maps/mapList'); | |||||
//System Imports | |||||
const fs = require('fs'); | |||||
//Imports | |||||
const phaseTemplate = require('./phases/phaseTemplate'); | |||||
const { mapList } = require('../world/mapManager'); | |||||
//Helpers | |||||
const applyVariablesToDescription = (desc, variables) => { | const applyVariablesToDescription = (desc, variables) => { | ||||
if (!variables) | if (!variables) | ||||
return desc; | return desc; | ||||
@@ -14,6 +18,7 @@ const applyVariablesToDescription = (desc, variables) => { | |||||
return desc; | return desc; | ||||
}; | }; | ||||
//Exports | |||||
module.exports = { | module.exports = { | ||||
configs: [], | configs: [], | ||||
nextId: 0, | nextId: 0, | ||||
@@ -22,7 +27,7 @@ module.exports = { | |||||
this.instance = instance; | this.instance = instance; | ||||
const zoneName = this.instance.map.name; | const zoneName = this.instance.map.name; | ||||
const zonePath = mapList.mapList.find(z => z.name === zoneName).path; | |||||
const zonePath = mapList.find(z => z.name === zoneName).path; | |||||
const zoneEventPath = zonePath + '/' + zoneName + '/events'; | const zoneEventPath = zonePath + '/' + zoneName + '/events'; | ||||
const paths = ['config/globalEvents', zoneEventPath]; | const paths = ['config/globalEvents', zoneEventPath]; | ||||
@@ -1,20 +1,21 @@ | |||||
require('./globals'); | require('./globals'); | ||||
let server = require('./server/index'); | |||||
let components = require('./components/components'); | |||||
let mods = require('./misc/mods'); | |||||
let animations = require('./config/animations'); | |||||
let skins = require('./config/skins'); | |||||
let factions = require('./config/factions'); | |||||
let classes = require('./config/spirits'); | |||||
let spellsConfig = require('./config/spellsConfig'); | |||||
let spells = require('./config/spells'); | |||||
let itemTypes = require('./items/config/types'); | |||||
let recipes = require('./config/recipes/recipes'); | |||||
let mapList = require('./config/maps/mapList'); | |||||
let fixes = require('./fixes/fixes'); | |||||
let profanities = require('./misc/profanities'); | |||||
const server = require('./server/index'); | |||||
const components = require('./components/components'); | |||||
const mods = require('./misc/mods'); | |||||
const animations = require('./config/animations'); | |||||
const skins = require('./config/skins'); | |||||
const factions = require('./config/factions'); | |||||
const classes = require('./config/spirits'); | |||||
const spellsConfig = require('./config/spellsConfig'); | |||||
const spells = require('./config/spells'); | |||||
const itemTypes = require('./items/config/types'); | |||||
const recipes = require('./config/recipes/recipes'); | |||||
const mapManager = require('./world/mapManager'); | |||||
const fixes = require('./fixes/fixes'); | |||||
const profanities = require('./misc/profanities'); | |||||
const routerConfig = require('./security/routerConfig'); | const routerConfig = require('./security/routerConfig'); | ||||
const { spawnMapThreads } = require('./world/threadManager'); | |||||
let startup = { | let startup = { | ||||
init: function () { | init: function () { | ||||
@@ -41,7 +42,7 @@ let startup = { | |||||
recipes.init(); | recipes.init(); | ||||
itemTypes.init(); | itemTypes.init(); | ||||
profanities.init(); | profanities.init(); | ||||
mapList.init(); | |||||
mapManager.init(); | |||||
components.init(this.onComponentsReady.bind(this)); | components.init(this.onComponentsReady.bind(this)); | ||||
}, | }, | ||||
@@ -55,7 +56,7 @@ let startup = { | |||||
await leaderboard.init(); | await leaderboard.init(); | ||||
atlas.init(); | |||||
await spawnMapThreads(); | |||||
}, | }, | ||||
onError: async function (e) { | onError: async function (e) { | ||||
@@ -1,3 +1,7 @@ | |||||
//Imports | |||||
const { sendMessageToThread } = require('../../world/threadManager'); | |||||
//Helpers | |||||
const route = function (socket, msg) { | const route = function (socket, msg) { | ||||
const source = this.players.find(p => p.socket.id === socket.id); | const source = this.players.find(p => p.socket.id === socket.id); | ||||
if (!source) | if (!source) | ||||
@@ -27,7 +31,10 @@ const route = function (socket, msg) { | |||||
if (msg.callback) | if (msg.callback) | ||||
msg.data.callbackId = atlas.registerCallback(msg.callback); | msg.data.callbackId = atlas.registerCallback(msg.callback); | ||||
atlas.send(source.zoneId, msg); | |||||
sendMessageToThread({ | |||||
threadId: source.zoneId, | |||||
msg | |||||
}); | |||||
return; | return; | ||||
} | } | ||||
@@ -52,6 +59,7 @@ const routeGlobal = function (msg) { | |||||
global[msg.module][msg.method](msg); | global[msg.module][msg.method](msg); | ||||
}; | }; | ||||
//Exports | |||||
module.exports = { | module.exports = { | ||||
route, | route, | ||||
routeGlobal | routeGlobal | ||||
@@ -1,21 +1,16 @@ | |||||
let childProcess = require('child_process'); | |||||
let objects = require('../objects/objects'); | |||||
let mapList = require('../config/maps/mapList'); | |||||
let connections = require('../security/connections'); | |||||
let events = require('../misc/events'); | |||||
const listenersOnZoneIdle = []; | |||||
//Imports | |||||
const objects = require('../objects/objects'); | |||||
const events = require('../misc/events'); | |||||
const { | |||||
getThread, killThread, sendMessageToThread, getThreadFromId, returnWhenThreadsIdle | |||||
} = require('./threadManager'); | |||||
//Exports | |||||
module.exports = { | module.exports = { | ||||
nextId: 0, | nextId: 0, | ||||
lastCallbackId: 0, | lastCallbackId: 0, | ||||
threads: [], | |||||
callbacks: [], | callbacks: [], | ||||
init: function () { | |||||
this.getMapFiles(); | |||||
}, | |||||
addObject: async function (obj, keepPos, transfer) { | addObject: async function (obj, keepPos, transfer) { | ||||
const serverObj = objects.objects.find(o => o.id === obj.id); | const serverObj = objects.objects.find(o => o.id === obj.id); | ||||
if (!serverObj) | if (!serverObj) | ||||
@@ -23,23 +18,16 @@ module.exports = { | |||||
events.emit('onBeforePlayerEnterWorld', obj); | events.emit('onBeforePlayerEnterWorld', obj); | ||||
let thread; | |||||
let map = mapList.mapList.find(m => m.name === obj.zoneName); | |||||
const { zoneName, zoneId } = obj; | |||||
if (!map) | |||||
map = mapList.mapList.find(m => m.name === clientConfig.config.defaultZone); | |||||
thread = this.threads.find(t => t.id === obj.zoneId && t.name === obj.zoneName); | |||||
if (!thread) { | |||||
if (map.instanced) { | |||||
delete obj.x; | |||||
delete obj.y; | |||||
thread = await this.spawnMap(map); | |||||
} else | |||||
thread = this.getThreadFromName(map.name); | |||||
const { thread, resetObjPosition } = await getThread({ | |||||
zoneName, | |||||
zoneId | |||||
}); | |||||
if (resetObjPosition) { | |||||
delete obj.x; | |||||
delete obj.y; | |||||
} | } | ||||
obj.zoneName = thread.name; | obj.zoneName = thread.name; | ||||
@@ -52,12 +40,15 @@ module.exports = { | |||||
const simpleObj = obj.getSimple ? obj.getSimple(true, true) : obj; | const simpleObj = obj.getSimple ? obj.getSimple(true, true) : obj; | ||||
this.send(obj.zoneId, { | |||||
method: 'addObject', | |||||
args: { | |||||
keepPos: keepPos, | |||||
obj: simpleObj, | |||||
transfer: transfer | |||||
sendMessageToThread({ | |||||
threadId: obj.zoneId, | |||||
msg: { | |||||
method: 'addObject', | |||||
args: { | |||||
keepPos: keepPos, | |||||
obj: simpleObj, | |||||
transfer: transfer | |||||
} | |||||
} | } | ||||
}); | }); | ||||
}, | }, | ||||
@@ -75,8 +66,7 @@ module.exports = { | |||||
}); | }); | ||||
}); | }); | ||||
thread.worker.kill(); | |||||
this.threads.spliceWhere(t => t === thread); | |||||
killThread(thread); | |||||
if (callback) | if (callback) | ||||
callback(); | callback(); | ||||
@@ -86,8 +76,8 @@ module.exports = { | |||||
if (!skipLocal) | if (!skipLocal) | ||||
objects.removeObject(obj); | objects.removeObject(obj); | ||||
let thread = this.findObjectThread(obj); | |||||
if (!thread) | |||||
const thread = getThreadFromId(obj.zoneId); | |||||
if (!thread) | |||||
return; | return; | ||||
if (thread.instanced) { | if (thread.instanced) { | ||||
@@ -100,38 +90,50 @@ module.exports = { | |||||
if (callback) | if (callback) | ||||
callbackId = this.registerCallback(callback); | callbackId = this.registerCallback(callback); | ||||
this.send(obj.zoneId, { | |||||
method: 'removeObject', | |||||
args: { | |||||
obj: obj.getSimple(true), | |||||
callbackId: callbackId | |||||
sendMessageToThread({ | |||||
threadId: obj.zoneId, | |||||
msg: { | |||||
method: 'removeObject', | |||||
args: { | |||||
obj: obj.getSimple(true), | |||||
callbackId: callbackId | |||||
} | |||||
} | } | ||||
}); | }); | ||||
}, | }, | ||||
updateObject: function (obj, msgObj) { | updateObject: function (obj, msgObj) { | ||||
this.send(obj.zoneId, { | |||||
method: 'updateObject', | |||||
args: { | |||||
id: obj.id, | |||||
obj: msgObj | |||||
sendMessageToThread({ | |||||
threadId: obj.zoneId, | |||||
msg: { | |||||
method: 'updateObject', | |||||
args: { | |||||
id: obj.id, | |||||
obj: msgObj | |||||
} | |||||
} | } | ||||
}); | }); | ||||
}, | }, | ||||
queueAction: function (obj, action) { | queueAction: function (obj, action) { | ||||
this.send(obj.zoneId, { | |||||
method: 'queueAction', | |||||
args: { | |||||
id: obj.id, | |||||
action: action | |||||
sendMessageToThread({ | |||||
threadId: obj.zoneId, | |||||
msg: { | |||||
method: 'queueAction', | |||||
args: { | |||||
id: obj.id, | |||||
action: action | |||||
} | |||||
} | } | ||||
}); | }); | ||||
}, | }, | ||||
performAction: function (obj, action) { | performAction: function (obj, action) { | ||||
this.send(obj.zoneId, { | |||||
method: 'performAction', | |||||
args: { | |||||
id: obj.id, | |||||
action: action | |||||
sendMessageToThread({ | |||||
threadId: obj.zoneId, | |||||
msg: { | |||||
method: 'performAction', | |||||
args: { | |||||
id: obj.id, | |||||
action: action | |||||
} | |||||
} | } | ||||
}); | }); | ||||
}, | }, | ||||
@@ -152,185 +154,12 @@ module.exports = { | |||||
callback.callback(msg.msg.result); | callback.callback(msg.msg.result); | ||||
}, | }, | ||||
send: function (threadId, msg) { | |||||
const thread = this.threads.find(t => t.id === threadId); | |||||
if (thread) | |||||
thread.worker.send(msg); | |||||
}, | |||||
findObjectThread: function ({ zoneId }) { | |||||
return this.threads.find(t => t.id === zoneId); | |||||
}, | |||||
getThreadFromName: function (name) { | |||||
return this.threads.find(t => t.name === name); | |||||
}, | |||||
getMapFiles: function () { | |||||
mapList.mapList | |||||
.filter(m => !m.disabled && !m.instanced) | |||||
.forEach(m => this.spawnMap(m)); | |||||
}, | |||||
spawnMap: async function ({ name, path, instanced }) { | |||||
return new Promise(resolveOnReady => { | |||||
const worker = childProcess.fork('./world/worker', [name]); | |||||
const id = instanced ? _.getGuid() : name; | |||||
const thread = { | |||||
id, | |||||
name, | |||||
instanced, | |||||
path, | |||||
worker, | |||||
cbOnInitialized: resolveOnReady | |||||
}; | |||||
const onMessage = this.onMessage.bind(this, thread); | |||||
worker.on('message', function (m) { | |||||
onMessage(m); | |||||
}); | |||||
this.threads.push(thread); | |||||
}); | |||||
}, | |||||
onMessage: function (thread, message) { | |||||
if (message.module) { | |||||
try { | |||||
global[message.module][message.method](message); | |||||
} catch (e) { | |||||
/* eslint-disable-next-line no-console */ | |||||
console.log('No global method found', message.module, message.method); | |||||
process.exit(); | |||||
} | |||||
} else if (message.event === 'onCrashed') { | |||||
thread.worker.kill(); | |||||
process.exit(); | |||||
} else | |||||
this.thread[message.method].call(this, thread, message); | |||||
}, | |||||
messageAllThreads: function (message) { | |||||
this.threads.forEach(t => t.worker.send(message)); | |||||
}, | |||||
fireEventOnAllThreads: function ({ msg: { event, data } }) { | |||||
this.threads.forEach(t => t.worker.send({ event, data })); | |||||
}, | |||||
thread: { | |||||
onReady: function (thread) { | |||||
thread.worker.send({ | |||||
method: 'init', | |||||
args: { | |||||
zoneName: thread.name, | |||||
zoneId: thread.id, | |||||
path: thread.path | |||||
} | |||||
}); | |||||
}, | |||||
onInitialized: function (thread) { | |||||
thread.cbOnInitialized(thread); | |||||
}, | |||||
event: function (thread, message) { | |||||
objects.sendEvent(message, thread); | |||||
}, | |||||
events: function (thread, message) { | |||||
objects.sendEvents(message, thread); | |||||
}, | |||||
object: function (thread, message) { | |||||
objects.updateObject(message); | |||||
}, | |||||
track: function (thread, message) { | |||||
let player = objects.objects.find(o => o.id === message.serverId); | |||||
if (!player) | |||||
return; | |||||
player.auth.gaTracker.track(message.obj); | |||||
}, | |||||
callDifferentThread: function (thread, message) { | |||||
let obj = connections.players.find(p => (p.name === message.playerName)); | |||||
if (!obj) | |||||
return; | |||||
let newThread = this.getThreadFromName(obj.zoneName); | |||||
if (!newThread) | |||||
return; | |||||
newThread.worker.send({ | |||||
module: message.data.module, | |||||
method: message.data.method, | |||||
args: message.data.args | |||||
}); | |||||
}, | |||||
rezone: async function (thread, message) { | |||||
const { args: { obj, newZone, keepPos = true } } = message; | |||||
if (thread.instanced) { | |||||
thread.worker.kill(); | |||||
this.threads.spliceWhere(t => t === thread); | |||||
} | |||||
//When messages are sent from map threads, they have an id (id of the object in the map thread) | |||||
// as well as a serverId (id of the object in the main thread) | |||||
const serverId = obj.serverId; | |||||
obj.id = serverId; | |||||
obj.destroyed = false; | |||||
const serverObj = objects.objects.find(o => o.id === obj.id); | |||||
const mapExists = mapList.mapList.some(m => m.name === newZone); | |||||
if (mapExists) { | |||||
serverObj.zoneName = newZone; | |||||
obj.zoneName = newZone; | |||||
} else { | |||||
obj.zoneName = clientConfig.config.defaultZone; | |||||
serverObj.zoneName = clientConfig.config.defaultZone; | |||||
} | |||||
delete serverObj.zoneId; | |||||
delete obj.zoneId; | |||||
const isRezone = true; | |||||
await this.addObject(obj, keepPos, isRezone); | |||||
}, | |||||
onZoneIdle: function (thread) { | |||||
listenersOnZoneIdle.forEach(l => l(thread)); | |||||
} | |||||
}, | |||||
returnWhenZonesIdle: async function () { | returnWhenZonesIdle: async function () { | ||||
return new Promise(res => { | |||||
const waiting = [...this.threads]; | |||||
const onZoneIdle = thread => { | |||||
waiting.spliceWhere(w => w === thread); | |||||
if (waiting.length) | |||||
return; | |||||
listenersOnZoneIdle.spliceWhere(l => l === onZoneIdle); | |||||
res(); | |||||
}; | |||||
listenersOnZoneIdle.push(onZoneIdle); | |||||
this.threads.forEach(t => { | |||||
t.worker.send({ | |||||
method: 'notifyOnceIdle' | |||||
}); | |||||
}); | |||||
}); | |||||
await returnWhenThreadsIdle(); | |||||
}, | }, | ||||
forceSavePlayer: async function (playerName, zoneId) { | forceSavePlayer: async function (playerName, zoneId) { | ||||
const thread = this.threads.find(t => t.id === zoneId); | |||||
const thread = getThreadFromId(zoneId); | |||||
if (!thread) | if (!thread) | ||||
return; | return; | ||||
@@ -0,0 +1,25 @@ | |||||
//Imports | |||||
const events = require('../misc/events'); | |||||
//Internals | |||||
const mapList = [ | |||||
{ | |||||
name: 'cave', | |||||
path: 'config/maps' | |||||
}, | |||||
{ | |||||
name: 'fjolarok', | |||||
path: 'config/maps' | |||||
} | |||||
]; | |||||
//Helpers | |||||
const init = () => { | |||||
events.emit('onBeforeGetMapList', mapList); | |||||
}; | |||||
//Exports | |||||
module.exports = { | |||||
init, | |||||
mapList | |||||
}; |
@@ -0,0 +1,250 @@ | |||||
//System Imports | |||||
const childProcess = require('child_process'); | |||||
//Imports | |||||
const objects = require('../objects/objects'); | |||||
const connections = require('../security/connections'); | |||||
const { mapList } = require('./mapManager'); | |||||
//Internals | |||||
const threads = []; | |||||
const listenersOnZoneIdle = []; | |||||
//Helpers | |||||
const getThreadFromName = name => { | |||||
return threads.find(t => t.name === name); | |||||
}; | |||||
const getThreadFromId = threadId => { | |||||
return threads.find(t => t.id === threadId); | |||||
}; | |||||
const messageHandlers = { | |||||
onReady: function (thread) { | |||||
thread.worker.send({ | |||||
method: 'init', | |||||
args: { | |||||
zoneName: thread.name, | |||||
zoneId: thread.id, | |||||
path: thread.path | |||||
} | |||||
}); | |||||
}, | |||||
onInitialized: function (thread) { | |||||
thread.isReady = true; | |||||
thread.cbOnInitialized(thread); | |||||
delete thread.cbOnInitialized; | |||||
delete thread.promise; | |||||
}, | |||||
event: function (thread, message) { | |||||
objects.sendEvent(message, thread); | |||||
}, | |||||
events: function (thread, message) { | |||||
objects.sendEvents(message, thread); | |||||
}, | |||||
object: function (thread, message) { | |||||
objects.updateObject(message); | |||||
}, | |||||
track: function (thread, message) { | |||||
let player = objects.objects.find(o => o.id === message.serverId); | |||||
if (!player) | |||||
return; | |||||
player.auth.gaTracker.track(message.obj); | |||||
}, | |||||
callDifferentThread: function (thread, message) { | |||||
let obj = connections.players.find(p => (p.name === message.playerName)); | |||||
if (!obj) | |||||
return; | |||||
let newThread = getThreadFromName(obj.zoneName); | |||||
if (!newThread) | |||||
return; | |||||
newThread.worker.send({ | |||||
module: message.data.module, | |||||
method: message.data.method, | |||||
args: message.data.args | |||||
}); | |||||
}, | |||||
rezone: async function (thread, message) { | |||||
const { args: { obj, newZone, keepPos = true } } = message; | |||||
if (thread.instanced) { | |||||
thread.worker.kill(); | |||||
threads.spliceWhere(t => t === thread); | |||||
} | |||||
//When messages are sent from map threads, they have an id (id of the object in the map thread) | |||||
// as well as a serverId (id of the object in the main thread) | |||||
const serverId = obj.serverId; | |||||
obj.id = serverId; | |||||
obj.destroyed = false; | |||||
const serverObj = objects.objects.find(o => o.id === obj.id); | |||||
const mapExists = mapList.some(m => m.name === newZone); | |||||
if (mapExists) { | |||||
serverObj.zoneName = newZone; | |||||
obj.zoneName = newZone; | |||||
} else { | |||||
obj.zoneName = clientConfig.config.defaultZone; | |||||
serverObj.zoneName = clientConfig.config.defaultZone; | |||||
} | |||||
delete serverObj.zoneId; | |||||
delete obj.zoneId; | |||||
const isRezone = true; | |||||
await atlas.addObject(obj, keepPos, isRezone); | |||||
}, | |||||
onZoneIdle: function (thread) { | |||||
listenersOnZoneIdle.forEach(l => l(thread)); | |||||
} | |||||
}; | |||||
const onMessage = (thread, message) => { | |||||
if (message.module) { | |||||
try { | |||||
global[message.module][message.method](message); | |||||
} catch (e) { | |||||
/* eslint-disable-next-line no-console */ | |||||
console.log('No global method found', message.module, message.method); | |||||
process.exit(); | |||||
} | |||||
} else if (message.event === 'onCrashed') { | |||||
thread.worker.kill(); | |||||
process.exit(); | |||||
} else | |||||
messageHandlers[message.method](thread, message); | |||||
}; | |||||
const spawnThread = async ({ name, path, instanced }) => { | |||||
let cbOnInitialized; | |||||
const promise = new Promise(resolveOnReady => { | |||||
cbOnInitialized = resolveOnReady; | |||||
}); | |||||
const worker = childProcess.fork('./world/worker', [name]); | |||||
const id = instanced ? _.getGuid() : name; | |||||
const thread = { | |||||
id, | |||||
name, | |||||
instanced, | |||||
path, | |||||
worker, | |||||
isReady: false, | |||||
promise, | |||||
cbOnInitialized | |||||
}; | |||||
worker.on('message', onMessage.bind(null, thread)); | |||||
threads.push(thread); | |||||
return promise; | |||||
}; | |||||
const getThread = async ({ zoneName, zoneId }) => { | |||||
const result = { | |||||
resetObjPosition: false, | |||||
thread: null | |||||
}; | |||||
let map = mapList.find(m => m.name === zoneName); | |||||
if (!map) | |||||
map = mapList.find(m => m.name === clientConfig.config.defaultZone); | |||||
let thread = threads.find(t => t.id === zoneId && t.name === zoneName); | |||||
if (!thread) { | |||||
if (map.instanced) { | |||||
result.resetObjPosition = true; | |||||
thread = await spawnThread(map); | |||||
} else | |||||
thread = getThreadFromName(map.name); | |||||
} | |||||
if (!thread.isReady) | |||||
await thread.promise; | |||||
result.thread = thread; | |||||
return result; | |||||
}; | |||||
const killThread = thread => { | |||||
thread.worker.kill(); | |||||
threads.spliceWhere(t => t === thread); | |||||
}; | |||||
const spawnMapThreads = async () => { | |||||
const promises = mapList | |||||
.filter(m => !m.disabled && !m.instanced) | |||||
.map(m => { | |||||
return new Promise(async res => { | |||||
await spawnThread(m); | |||||
}); | |||||
}); | |||||
await Promise.all(promises); | |||||
}; | |||||
const sendMessageToThread = ({ threadId, msg }) => { | |||||
const thread = threads.find(t => t.id === threadId); | |||||
if (thread) | |||||
thread.worker.send(msg); | |||||
}; | |||||
const messageAllThreads = message => { | |||||
threads.forEach(t => t.worker.send(message)); | |||||
}; | |||||
const returnWhenThreadsIdle = async () => { | |||||
return new Promise(res => { | |||||
let doneCount = 0; | |||||
const onZoneIdle = thread => { | |||||
doneCount++; | |||||
if (doneCount.length < threads.length) | |||||
return; | |||||
listenersOnZoneIdle.spliceWhere(l => l === onZoneIdle); | |||||
res(); | |||||
}; | |||||
listenersOnZoneIdle.push(onZoneIdle); | |||||
threads.forEach(t => { | |||||
t.worker.send({ | |||||
method: 'notifyOnceIdle' | |||||
}); | |||||
}); | |||||
}); | |||||
}; | |||||
//Exports | |||||
module.exports = { | |||||
getThread, | |||||
killThread, | |||||
getThreadFromId, | |||||
spawnMapThreads, | |||||
messageAllThreads, | |||||
sendMessageToThread, | |||||
returnWhenThreadsIdle | |||||
}; |
@@ -1,3 +1,4 @@ | |||||
//Globals | |||||
global.extend = require('../misc/clone'); | global.extend = require('../misc/clone'); | ||||
global.io = require('../db/io'); | global.io = require('../db/io'); | ||||
global._ = require('../misc/helpers'); | global._ = require('../misc/helpers'); | ||||
@@ -7,6 +8,7 @@ global.eventManager = require('../events/events'); | |||||
global.clientConfig = require('../config/clientConfig'); | global.clientConfig = require('../config/clientConfig'); | ||||
global.rezoneManager = require('./rezoneManager'); | global.rezoneManager = require('./rezoneManager'); | ||||
//Imports | |||||
const components = require('../components/components'); | const components = require('../components/components'); | ||||
const mods = require('../misc/mods'); | const mods = require('../misc/mods'); | ||||
const animations = require('../config/animations'); | const animations = require('../config/animations'); | ||||
@@ -17,14 +19,15 @@ const spellsConfig = require('../config/spellsConfig'); | |||||
const spells = require('../config/spells'); | const spells = require('../config/spells'); | ||||
const recipes = require('../config/recipes/recipes'); | const recipes = require('../config/recipes/recipes'); | ||||
const itemTypes = require('../items/config/types'); | const itemTypes = require('../items/config/types'); | ||||
const mapList = require('../config/maps/mapList'); | |||||
const mapManager = require('../world/mapManager'); | |||||
const itemEffects = require('../items/itemEffects'); | const itemEffects = require('../items/itemEffects'); | ||||
const profanities = require('../misc/profanities'); | const profanities = require('../misc/profanities'); | ||||
const eventEmitter = require('../misc/events'); | const eventEmitter = require('../misc/events'); | ||||
//Worker | |||||
instancer.mapName = process.argv[2]; | instancer.mapName = process.argv[2]; | ||||
let onCpnsReady = async function () { | |||||
const onCpnsReady = async function () { | |||||
factions.init(); | factions.init(); | ||||
skins.init(); | skins.init(); | ||||
animations.init(); | animations.init(); | ||||
@@ -32,7 +35,7 @@ let onCpnsReady = async function () { | |||||
spellsConfig.init(); | spellsConfig.init(); | ||||
spells.init(); | spells.init(); | ||||
itemTypes.init(); | itemTypes.init(); | ||||
mapList.init(); | |||||
mapManager.init(); | |||||
recipes.init(); | recipes.init(); | ||||
itemEffects.init(); | itemEffects.init(); | ||||
profanities.init(); | profanities.init(); | ||||
@@ -45,7 +48,7 @@ let onCpnsReady = async function () { | |||||
}); | }); | ||||
}; | }; | ||||
let onModsReady = function () { | |||||
const onModsReady = function () { | |||||
components.init(onCpnsReady); | components.init(onCpnsReady); | ||||
}; | }; | ||||
@@ -67,7 +70,7 @@ const onCrash = async e => { | |||||
}); | }); | ||||
}; | }; | ||||
let onDbReady = async function () { | |||||
const onDbReady = async function () { | |||||
require('../misc/random'); | require('../misc/random'); | ||||
process.on('uncaughtException', onCrash); | process.on('uncaughtException', onCrash); | ||||
@@ -82,17 +85,17 @@ io.init(onDbReady); | |||||
process.on('message', m => { | process.on('message', m => { | ||||
if (m.module) { | if (m.module) { | ||||
let instances = instancer.instances; | |||||
let iLen = instances.length; | |||||
const instances = instancer.instances; | |||||
const iLen = instances.length; | |||||
for (let i = 0; i < iLen; i++) { | for (let i = 0; i < iLen; i++) { | ||||
let objects = instances[i].objects.objects; | |||||
let oLen = objects.length; | |||||
const objects = instances[i].objects.objects; | |||||
const oLen = objects.length; | |||||
let found = false; | let found = false; | ||||
for (let j = 0; j < oLen; j++) { | for (let j = 0; j < oLen; j++) { | ||||
let object = objects[j]; | |||||
const object = objects[j]; | |||||
if (object.name === m.args[0]) { | if (object.name === m.args[0]) { | ||||
let mod = object.instance[m.module]; | |||||
const mod = object.instance[m.module]; | |||||
mod[m.method].apply(mod, m.args); | mod[m.method].apply(mod, m.args); | ||||
found = true; | found = true; | ||||