@@ -1,7 +1,9 @@ | |||
define([ | |||
'js/misc/distanceToPolygon' | |||
'js/misc/distanceToPolygon', | |||
'js/system/events' | |||
], function ( | |||
distanceToPolygon | |||
distanceToPolygon, | |||
events | |||
) { | |||
return { | |||
grid: null, | |||
@@ -10,6 +12,8 @@ define([ | |||
height: 0, | |||
init: function (collisionMap) { | |||
events.on('resetPhysics', this.reset.bind(this)); | |||
this.width = collisionMap.length; | |||
this.height = collisionMap[0].length; | |||
@@ -22,6 +26,13 @@ define([ | |||
} | |||
}, | |||
reset: function () { | |||
this.width = 0; | |||
this.height = 0; | |||
this.grid = []; | |||
}, | |||
isTileBlocking: function (x, y, mob, obj) { | |||
if ((x < 0) || (y < 0) || (x >= this.width) | (y >= this.height)) | |||
return true; | |||
@@ -174,7 +174,7 @@ define([ | |||
offEvents: function () { | |||
if (this.pather) | |||
this.pather.onDeath(); | |||
this.pather.clearPath(); | |||
for (let e in this.eventCallbacks) | |||
this.eventCallbacks[e].forEach(c => events.off(e, c)); | |||
@@ -15,11 +15,15 @@ define([ | |||
objects: [], | |||
init: function () { | |||
events.on('onGetObject', this.onGetObject.bind(this)); | |||
events.on('onRezone', this.onRezone.bind(this)); | |||
events.on('onChangeHoverTile', this.getLocation.bind(this)); | |||
events.on('onTilesVisible', this.onTilesVisible.bind(this)); | |||
events.on('onToggleNameplates', this.onToggleNameplates.bind(this)); | |||
[ | |||
'onGetObject', | |||
'onTilesVisible', | |||
'onToggleNameplates', | |||
'destroyAllObjects' | |||
] | |||
.forEach(e => events.on(e, this[e].bind(this))); | |||
}, | |||
getLocation: function (x, y) { | |||
@@ -87,20 +91,14 @@ define([ | |||
return list[fromIndex]; | |||
}, | |||
onRezone: function (oldZone) { | |||
let objects = this.objects; | |||
let oLen = objects.length; | |||
for (let i = 0; i < oLen; i++) { | |||
let o = objects[i]; | |||
destroyAllObjects: function () { | |||
this.objects.forEach(o => { | |||
o.destroy(); | |||
}); | |||
if (oldZone === null) | |||
o.destroy(); | |||
else if (o.zoneId === oldZone) | |||
o.destroy(); | |||
} | |||
this.objects.length = 0; | |||
if (window.player) | |||
window.player.offEvents(); | |||
window?.player?.offEvents(); | |||
}, | |||
onGetObject: function (obj) { | |||
@@ -0,0 +1,45 @@ | |||
define([ | |||
'js/rendering/spritePool' | |||
], function ( | |||
spritePool | |||
) { | |||
return function () { | |||
let map = this.map; | |||
let w = this.w = map.length; | |||
let h = this.h = map[0].length; | |||
this.stage.removeChild(this.layers.hiders); | |||
this.layers.hiders = new PIXI.Container(); | |||
this.layers.hiders.layer = 'hiders'; | |||
this.stage.addChild(this.layers.hiders); | |||
let container = this.layers.tileSprites; | |||
this.stage.removeChild(container); | |||
this.layers.tileSprites = container = new PIXI.Container(); | |||
container.layer = 'tiles'; | |||
this.stage.addChild(container); | |||
this.stage.children.sort((a, b) => { | |||
if (a.layer === 'hiders') | |||
return 1; | |||
else if (b.layer === 'hiders') | |||
return -1; | |||
else if (a.layer === 'tiles') | |||
return -1; | |||
else if (b.layer === 'tiles') | |||
return 1; | |||
return 0; | |||
}); | |||
spritePool.clean(); | |||
this.sprites = _.get2dArray(w, h, 'array'); | |||
this.map = []; | |||
this.w = 0; | |||
this.h = 0; | |||
delete this.moveTo; | |||
}; | |||
}); |
@@ -8,7 +8,8 @@ define([ | |||
'js/rendering/shaders/outline', | |||
'js/rendering/spritePool', | |||
'js/system/globals', | |||
'js/rendering/renderLoginBackground' | |||
'js/rendering/renderLoginBackground', | |||
'js/rendering/helpers/resetRenderer' | |||
], function ( | |||
resources, | |||
events, | |||
@@ -19,7 +20,8 @@ define([ | |||
shaderOutline, | |||
spritePool, | |||
globals, | |||
renderLoginBackground | |||
renderLoginBackground, | |||
resetRenderer | |||
) { | |||
const mRandom = Math.random.bind(Math); | |||
@@ -84,6 +86,7 @@ define([ | |||
events.on('onGetMap', this.onGetMap.bind(this)); | |||
events.on('onToggleFullscreen', this.toggleScreen.bind(this)); | |||
events.on('onMoveSpeedChange', this.adaptCameraMoveSpeed.bind(this)); | |||
events.on('resetRenderer', resetRenderer.bind(this)); | |||
this.width = $('body').width(); | |||
this.height = $('body').height(); | |||
@@ -18,7 +18,38 @@ define([ | |||
this.socket.on('event', this.onEvent.bind(this)); | |||
this.socket.on('events', this.onEvents.bind(this)); | |||
this.socket.on('dc', this.onDisconnect.bind(this)); | |||
Object.entries(this.processAction).forEach(([k, v]) => { | |||
this.processAction[k] = v.bind(this); | |||
}); | |||
}, | |||
onRezoneStart: function () { | |||
//Fired for mods to listen to | |||
events.emit('rezoneStart'); | |||
events.emit('destroyAllObjects'); | |||
events.emit('resetRenderer'); | |||
events.emit('resetPhysics'); | |||
events.emit('clearUis'); | |||
client.request({ | |||
threadModule: 'rezoneManager', | |||
method: 'clientAck', | |||
data: {} | |||
}); | |||
}, | |||
onGetMap: function ([msg]) { | |||
events.emit('onGetMap', msg); | |||
client.request({ | |||
threadModule: 'instancer', | |||
method: 'clientAck', | |||
data: {} | |||
}); | |||
}, | |||
onConnected: function (onReady) { | |||
if (this.doneConnect) | |||
this.onDisconnect(); | |||
@@ -28,45 +59,72 @@ define([ | |||
if (onReady) | |||
onReady(); | |||
}, | |||
onDisconnect: function () { | |||
window.location = window.location; | |||
}, | |||
onHandshake: function () { | |||
events.emit('onHandshake'); | |||
this.socket.emit('handshake'); | |||
}, | |||
request: function (msg) { | |||
this.socket.emit('request', msg, msg.callback); | |||
}, | |||
onEvent: function (response) { | |||
events.emit(response.event, response.data); | |||
}, | |||
onEvents: function (response) { | |||
//If we get objects, self needs to be first | |||
// otherwise we might create the object (setting his position or attack animation) | |||
// before instantiating it | |||
let oList = response.onGetObject; | |||
if (oList) { | |||
let prepend = oList.filter(o => o.self); | |||
oList.spliceWhere(o => prepend.some(p => p === o)); | |||
oList.unshift.apply(oList, prepend); | |||
} | |||
for (let e in response) { | |||
let r = response[e]; | |||
processAction: { | |||
default: function (eventName, msgs) { | |||
msgs.forEach(m => events.emit(eventName, m)); | |||
}, | |||
rezoneStart: function (eventName, msgs) { | |||
events.emit('rezoneStart'); | |||
events.emit('destroyAllObjects'); | |||
events.emit('resetRenderer'); | |||
events.emit('resetPhysics'); | |||
events.emit('clearUis'); | |||
//Certain messages expect to be performed last (because the object they act on hasn't been created when they get queued) | |||
r.sort(function (a, b) { | |||
if (a.performLast) | |||
return 1; | |||
else if (b.performLast) | |||
return -1; | |||
return 0; | |||
client.request({ | |||
threadModule: 'rezoneManager', | |||
method: 'clientAck', | |||
data: {} | |||
}); | |||
}, | |||
r.forEach(function (o) { | |||
events.emit(e, o); | |||
getMap: function (eventName, msgs) { | |||
events.emit('onGetMap', msgs[0]); | |||
client.request({ | |||
threadModule: 'instancer', | |||
method: 'clientAck', | |||
data: {} | |||
}); | |||
}, | |||
onGetObject: function (eventName, msgs) { | |||
const prepend = msgs.filter(o => o.self); | |||
msgs.spliceWhere(o => prepend.some(p => p === o)); | |||
msgs.unshift.apply(msgs, prepend); | |||
this.processAction.default(eventName, msgs); | |||
} | |||
}, | |||
onEvent: function ({ event: eventName, data: eventData }) { | |||
const handler = this.processAction[eventName] || this.processAction.default; | |||
handler(eventName, [eventData]); | |||
}, | |||
onEvents: function (response) { | |||
for (let eventName in response) { | |||
const eventMsgs = response[eventName]; | |||
const handler = this.processAction[eventName] || this.processAction.default; | |||
handler(eventName, eventMsgs); | |||
} | |||
} | |||
}; | |||
@@ -20,14 +20,14 @@ define([ | |||
this.onEvent('onPermadeath', this.onPermadeath.bind(this)); | |||
this.find('.btn-logout').on('click', this.onLogout.bind(this)); | |||
this.find('.btn-respawn').on('click', this.onRespawn.bind(this)); | |||
this.find('.btn-respawn').on('click', this.performRespawn.bind(this)); | |||
}, | |||
onLogout: function () { | |||
$('.uiMainMenu').data('ui').charSelect(); | |||
}, | |||
onRespawn: function () { | |||
performRespawn: function () { | |||
events.emit('onHideOverlay', this.el); | |||
this.hide(true); | |||
@@ -26,7 +26,7 @@ define([ | |||
this.find('.btnCollapse').on('click', this.toggleButtons.bind(this)); | |||
} | |||
this.onEvent('onRezone', this.onRezone.bind(this)); | |||
this.onEvent('clearUis', this.clear.bind(this)); | |||
this.onEvent('onObtainEvent', this.onObtainEvent.bind(this)); | |||
this.onEvent('onRemoveEvent', this.onRemoveEvent.bind(this)); | |||
@@ -37,7 +37,7 @@ define([ | |||
this.onToggleEventsVisibility(config.showEvents); | |||
}, | |||
onRezone: function () { | |||
clear: function () { | |||
this.list = []; | |||
this.el.find('.list').empty(); | |||
}, | |||
@@ -58,8 +58,10 @@ define([ | |||
}, | |||
onCharSelect: function () { | |||
renderer.clean(); | |||
objects.onRezone(); | |||
events.emit('destroyAllObjects'); | |||
events.emit('resetRenderer'); | |||
events.emit('resetPhysics'); | |||
renderer.buildTitleScreen(); | |||
sound.unload(); | |||
@@ -25,7 +25,7 @@ define([ | |||
this.find('.btnCollapse').on('click', this.toggleButtons.bind(this)); | |||
} | |||
this.onEvent('onRezone', this.onRezone.bind(this)); | |||
this.onEvent('clearUis', this.clear.bind(this)); | |||
this.onEvent('onObtainQuest', this.onObtainQuest.bind(this)); | |||
this.onEvent('onUpdateQuest', this.onUpdateQuest.bind(this)); | |||
@@ -35,7 +35,7 @@ define([ | |||
this.onToggleQuestsVisibility(config.showQuests); | |||
}, | |||
onRezone: function () { | |||
clear: function () { | |||
this.quests = []; | |||
this.el.find('.list').empty(); | |||
}, | |||
@@ -18,11 +18,7 @@ define([ | |||
postRender: function () { | |||
this.onEvent('onGetTalk', this.onGetTalk.bind(this)); | |||
this.onEvent('onRezone', this.onRezone.bind(this)); | |||
}, | |||
onRezone: function () { | |||
this.hide(); | |||
this.onEvent('clearUis', this.hide.bind(this)); | |||
}, | |||
onGetTalk: function (dialogue) { | |||
@@ -1,48 +1,3 @@ | |||
/* | |||
atlas.onMessage.event / events -> only send if source zone = obj zoneName | |||
SERVER SIDE | |||
1. Change zone and position | |||
2. Save | |||
3. Syncer: Destroy, Flush and Notify other objects of destroyed obj | |||
4. Log IN CASE (if new events are queued) | |||
5. Stage rezone | |||
6. Tell client rezone is happening | |||
CLIENT SIDE | |||
events.emit('rezoneStart'); | |||
events.emit('destroyAllObjects'); | |||
events.emit('resetRenderer'); | |||
events.emit('resetPhysics'); | |||
events.emit('clearUis'); | |||
client.request({ | |||
threadModule: 'rezoneManager', | |||
method: 'clientAck', | |||
data: {} | |||
}); | |||
SERVER SIDE | |||
7. Server receives ack | |||
8. Map thread tells main thread about rezone | |||
9. Main thread does rezone | |||
10. New map thread registers handshake for map send | |||
11. New map thread sends new map | |||
CLIENT SIDE | |||
events.emit('onGetMap', msg); | |||
client.request({ | |||
threadModule: 'instancer', | |||
method: 'clientAck', | |||
data: {} | |||
}); | |||
SERVER SIDE | |||
12. Add object to zone | |||
*/ | |||
const sendObjToZone = async ({ obj, invokingObj, zoneName, toPos, toRelativePos }) => { | |||
const { serverId, instance: { syncer: globalSyncer, physics } } = obj; | |||
@@ -3,6 +3,9 @@ const sendObjToZone = require('../portal/sendObjToZone'); | |||
module.exports = (cpnSocial, targetZone) => { | |||
const { obj } = cpnSocial; | |||
if (obj.zoneName === targetZone) | |||
return; | |||
sendObjToZone({ | |||
obj, | |||
zoneName: targetZone | |||
@@ -8,7 +8,7 @@ module.exports = { | |||
// sqlite | |||
// rethink | |||
//eslint-disable-next-line no-process-env | |||
db: process.env.IWD_DB || 'sqlite', | |||
db: process.env.IWD_DB || 'rethink', | |||
//eslint-disable-next-line no-process-env | |||
dbHost: process.env.IWD_DB_HOST || 'localhost', | |||
//eslint-disable-next-line no-process-env | |||
@@ -203,73 +203,80 @@ module.exports = { | |||
return newO; | |||
}, | |||
sendEvent: function (msg, sourceThread) { | |||
let player = this.objects.find(p => p.id === msg.id); | |||
if (!player) | |||
sendEvent: function (msg, { name: sourceZone }) { | |||
const { id, data } = msg; | |||
const player = this.objects.find(p => p.id === id); | |||
if (!player || player.zoneName !== sourceZone) | |||
return; | |||
player.socket.emit('event', { | |||
event: msg.data.event, | |||
data: msg.data.data | |||
event: data.event, | |||
data: data.data | |||
}); | |||
}, | |||
sendEvents: function (msg, sourceThread) { | |||
let players = {}; | |||
let objects = this.objects; | |||
let data = msg.data; | |||
sendEvents: function ({ data }, { name: sourceZone }) { | |||
const { objects } = this; | |||
//Store will contain all events to be sent to players | |||
const store = {}; | |||
for (let e in data) { | |||
let event = data[e]; | |||
let eLen = event.length; | |||
const event = data[e]; | |||
const eLen = event.length; | |||
for (let j = 0; j < eLen; j++) { | |||
let eventEntry = event[j]; | |||
let obj = eventEntry.obj; | |||
if (e !== 'serverModule') { | |||
let to = eventEntry.to; | |||
let toLen = to.length; | |||
for (let i = 0; i < toLen; i++) { | |||
let toId = to[i]; | |||
let player = players[toId]; | |||
if (!player) { | |||
let findPlayer = objects.find(o => o.id === toId); | |||
if (!findPlayer) | |||
continue; | |||
else { | |||
//If the message came from a map the player is no longer in, ignore | |||
if (findPlayer.zoneName !== sourceThread.name) | |||
continue; | |||
player = (players[toId] = { | |||
socket: findPlayer.socket, | |||
events: {}, | |||
obj: findPlayer | |||
}); | |||
} | |||
} | |||
//If the message came from a map the player is no longer in, ignore | |||
if (player.obj.zoneName !== sourceThread.name) | |||
const eventEntry = event[j]; | |||
const { obj: eventObj, to } = eventEntry; | |||
if (e === 'serverModule') { | |||
const { method, msg } = eventObj; | |||
if (Array.isArray(msg)) | |||
global[eventObj.module][method](...msg); | |||
else | |||
global[eventObj.module][method](msg); | |||
continue; | |||
} | |||
const toLen = to.length; | |||
for (let i = 0; i < toLen; i++) { | |||
const toId = to[i]; | |||
let storeEntry = store[toId]; | |||
if (!storeEntry) { | |||
const playerObj = objects.find(o => o.id === toId); | |||
if (!playerObj || playerObj.zoneName !== sourceZone) | |||
continue; | |||
let eventList = player.events[e] || (player.events[e] = []); | |||
eventList.push(obj); | |||
store[toId] = { | |||
obj: playerObj, | |||
events: { [e]: [eventObj] } | |||
}; | |||
continue; | |||
} | |||
} else if (obj.msg instanceof Array) | |||
global[obj.module][obj.method](...obj.msg); | |||
else | |||
global[obj.module][obj.method](obj.msg); | |||
if (!storeEntry.events[e]) | |||
storeEntry.events[e] = []; | |||
storeEntry.events[e].push(eventObj); | |||
} | |||
} | |||
} | |||
for (let p in players) { | |||
let player = players[p]; | |||
player.socket.emit('events', player.events); | |||
for (let p in store) { | |||
const { obj: { socket }, events } = store[p]; | |||
socket.emit('events', events); | |||
} | |||
}, | |||
updateObject: async function (msg) { | |||
let player = this.objects.find(p => p.id === msg.serverId); | |||
if (!player) | |||
@@ -60,7 +60,6 @@ module.exports = { | |||
this.syncer.queue('onGetObject', { | |||
id: obj.id, | |||
performLast: true, | |||
components: [spawnAnimation] | |||
}, -1); | |||
} | |||
@@ -210,8 +210,6 @@ module.exports = { | |||
this.dirty = false; | |||
console.log(Object.keys(this.buffer)); | |||
process.send({ | |||
method: 'events', | |||
data: this.buffer | |||