From 6bc17ead3cf6cdebeb0810a5fc0bd2d68da85ab4 Mon Sep 17 00:00:00 2001 From: molleindustria Date: Tue, 7 Apr 2020 11:08:48 -0400 Subject: [PATCH] added Mod support fixed a rollover bug on change room that got players stuck Starting to add client and server side mods. added a secret room for mods ?room=experiments --- data.js | 13 ++++- public/assets/experiments-areas.png | Bin 0 -> 604 bytes public/assets/experiments-bg.png | Bin 0 -> 790 bytes public/client.js | 62 ++++++++++++++++++-- public/index.html | 1 + public/mod.js | 84 ++++++++++++++++++++++++++++ server.js | 49 +++++++++++++++- serverMod.js | 33 +++++++++++ 8 files changed, 233 insertions(+), 9 deletions(-) create mode 100755 public/assets/experiments-areas.png create mode 100755 public/assets/experiments-bg.png create mode 100644 public/mod.js create mode 100644 serverMod.js diff --git a/data.js b/data.js index 3b12cb1..13fa0e4 100644 --- a/data.js +++ b/data.js @@ -98,7 +98,18 @@ module.exports.ROOMS = { { file: "likelike-backyard-chairs.png", position: [33, 44] }, ] + }, + //just an empty room for testing mods + experiments: { - }, + bg: "experiments-bg.png", + avatarScale: 2, + pageBg: "#bfaeae", + area: "experiments-areas.png", + tint: "#FFFFFF", + bubblesY: 50, + spawn: [15, 77, 113, 96] + + } }; \ No newline at end of file diff --git a/public/assets/experiments-areas.png b/public/assets/experiments-areas.png new file mode 100755 index 0000000000000000000000000000000000000000..6683429a2c6e3a01b4dbe8a35ea09f947b535418 GIT binary patch literal 604 zcmeAS@N?(olHy`uVBq!ia0vp^4M3d2!3HG#UR%U7Ffb{5x;TbZ#J#<8yQs-Qgf;Nz z|9-PnEzhS(A_5{Wj{fG^{QJwz!zZV!87#TXU9aR2!^9+@;HMxL&pcA71gpl+KWpaI zo$B1m$#dACa-q8XjuwRjw-(Q-{~yAs#+~rvbNlC>$t)FYPka9-cd<;CI`A#O=9Bz+ zc#seCWJ8G`1hCh|EDCTH^q6~`+m)1DVIL* zP2Z}2dAwW0a^?H?`13srHUqVNYqNar$}+?GZ9@9L$q(+cZTNfKsDa`5tmkV?uB+_0 z#jvej?EYDKr3260xBO$S_x`XPsOOh+#Z!5X4_?2de||6LtTSnNd;dgBSRET<7~7uq z*Y>JEvKVgfZ{Mi<-Hl1-c+qzASe1%=pvY}WyDtSyHZAWZ+SzZ{_c)&Ob!^!AgsEfOLDv~j#ao?JV=n~c!-KAG|*Z(@)&9sB5 zcE-l9m41xB9_*Q+By>PD;r2$>`p@ebSOXfWnN`&`u736YrT5IWb!-(^f_^3ay?Vko zL&NHlI;I4Z+dus(_R{V_cXnFsb&+pbpF|a0ZdtVQl z1CvI>f4vJUn5*yo-7WTDBUA4;gD=T%f6k8yz0dkXH*t4eZ4KkM8`tt`|ELEu*d5kr zWODiXv0t>|yn)vOhQQiC$*d2IdxSI`LgfEPF#h0K%)%vb^|*c5$WZ#Bka5xSuRnBo z-~6=n+g+b^BU7+da}{W*U5sz<<91}=jQ z42RMWtdDJc1e9-N6|m#3JIf`a+rY%5)9_*D2k-ENVn&gK1jd&0ZSk9!R&y_4VCGi% zWA`9`?SV&38V3$AaqQRsk*#g88)DRZ;eVI7{zNmdN<=U`{LWjS$NEnPV%G77|GSv> zL-lWbV88xAE!g0F=bqo5@zK}Tv>>Emqw5dG_s7$>@Ro^-0nmdKI;Vst0JzRk AZU6uP literal 0 HcmV?d00001 diff --git a/public/client.js b/public/client.js index 0d4be97..929e176 100644 --- a/public/client.js +++ b/public/client.js @@ -136,6 +136,7 @@ var allSheets; //current room bg and areas var bg; var areas; +var room; //the id //command quequed for when the destination is reached var nextCommand; @@ -620,6 +621,7 @@ function newGame() { //if it's me/////////// if (socket.id == p.id) { + rolledSprite = null; //the location appears in the url if (ROOM_LINK && ROOMS[p.room] != null) @@ -642,6 +644,7 @@ function newGame() { me.sprite.onMousePressed = function () { socket.emit('emote', { room: me.room, em: true }); }; me.sprite.onMouseReleased = function () { socket.emit('emote', { room: me.room, em: false }); }; + room = p.room; //if a page background is specified change it if (ROOMS[p.room].pageBg != null) @@ -724,8 +727,12 @@ function newGame() { } + //initialize the mod if any + if (window.initMod != null) { + window.initMod(p.id, p.room); + } - } + }//it me else { // players[p.id] = new Player(p); @@ -765,6 +772,11 @@ function newGame() { console.log("There are now " + Object.keys(players).length + " players in this room"); + //calling a custom function roomnameEnter if it exists + if (window[p.room + "Enter"] != null) { + window[p.room + "Enter"](p.id, p.room); + } + } catch (e) { console.log("Error on playerJoined"); @@ -814,6 +826,12 @@ function newGame() { console.log("Player " + p.id + " left"); if (players[p.id] != null) { + + //calling a custom function roomnameEnter if it exists + if (window[p.room + "Exit"] != null) { + window[p.room + "Exit"](p.id); + } + if (p.disconnect && players[p.id].nickName != "") { var spark = createSprite(players[p.id].x, players[p.id].y - AVATAR_H + 1); spark.addAnimation("spark", disappearEffect); @@ -861,12 +879,18 @@ function newGame() { var offY = ROOMS[me.room].bubblesY * ASSET_SCALE; var newBubble = new Bubble(p.id, p.message, p.color, p.x, p.y, offY); + //calling a custom function + if (window[me.room + "Talk"] != null) { + window[me.room + "Talk"](p.id, newBubble); + } + pushBubbles(newBubble); bubbles.push(newBubble); if (SOUND) { blips[floor(random(0, blips.length))].play(); } + } } } catch (e) { @@ -1017,6 +1041,12 @@ function update() { text(errorMessage, floor(WIDTH / 8), floor(HEIGHT / 8), WIDTH - floor(WIDTH / 4), HEIGHT - floor(HEIGHT / 4) + 1); } else if (screen == "game") { + + //calling a custom function + if (window[room + "Update"] != null) { + window[room + "Update"](); + } + //draw a background background(UI_BG); imageMode(CORNER); @@ -1501,6 +1531,7 @@ function Player(p) { this.sprite.id = this.id; this.sprite.label = p.nickName; this.sprite.transparent = false; + this.sprite.roomId = p.room; //sure anything goes //save the dominant color for bubbles and rollover label var c = color(AVATAR_PALETTES[p.color][2]); @@ -1563,7 +1594,12 @@ function Player(p) { if (this.transparent) tint(255, 100); - this.originalDraw(); + if (window[this.roomId + "DrawSprite"] != null) { + window[this.roomId + "DrawSprite"](this.id, this, this.originalDraw); + } + else { + this.originalDraw(); + } if (this.transparent) noTint(); @@ -1671,7 +1707,12 @@ function isObstacle(x, y, room, a) { if (room != null && a != null) { - var c1 = a.get(x, y); + //you know, at this point I'm not sure if you are using assets scaled by 2 for the areas + //so I'm just gonna stretch the coordinates ok + var px = floor(map(x, 0, WIDTH, 0, a.width)); + var py = floor(map(y, 0, HEIGHT, 0, a.height)); + + var c1 = a.get(px, py); //if not white check if color is obstacle if (c1[0] != 255 || c1[1] != 255 || c1[2] != 255) { @@ -1717,7 +1758,13 @@ function mouseMoved() { walkIcon.visible = false; if (areas != null && me != null) { - var c = areas.get(mouseX, mouseY); + + //you know, at this point I'm not sure if you are using assets scaled by 2 for the areas + //so I'm just gonna stretch the coordinates ok + var mx = floor(map(mouseX, 0, WIDTH, 0, areas.width)); + var my = floor(map(mouseY, 0, HEIGHT, 0, areas.height)); + + var c = areas.get(mx, my); areaLabel = ""; if (alpha(c) != 0 && me.room != null) { @@ -1797,7 +1844,12 @@ function canvasReleased() { //check the area info else if (areas != null && me.room != null) { - var c = areas.get(mouseX, mouseY); + //you know, at this point I'm not sure if you are using assets scaled by 2 for the areas + //so I'm just gonna stretch the coordinates ok + var mx = floor(map(mouseX, 0, WIDTH, 0, areas.width)); + var my = floor(map(mouseY, 0, HEIGHT, 0, areas.height)); + + var c = areas.get(mx, my); //if transparent or semitransparent do nothing if (alpha(c) != 255) { diff --git a/public/index.html b/public/index.html index 3c94f43..e9f09f9 100644 --- a/public/index.html +++ b/public/index.html @@ -34,6 +34,7 @@ + diff --git a/public/mod.js b/public/mod.js new file mode 100644 index 0000000..3a85ae5 --- /dev/null +++ b/public/mod.js @@ -0,0 +1,84 @@ +/* +WARNING: THIS IS STILL EXPERIMENTAL STUFF +I want to have the ability to assign specific behaviors to each room without messing with the main engine +So this is a file for client-side modifications (mods). There is one for the server side as well. +Their naming convention is roomIdFunction. +The functions are called by the engine at crucial points, only if they exist. +*/ + +//when my players joins the game for the first time, after everything in the room is initialized +//called also for lurk mode (nickName == "") +function initMod(playerId, roomId) { + print("Mod: " + players[playerId].nickName + " joined the game at " + roomId) +} + +//roomnameEnter: called when a player enters a room, after all the normal operations +//called also for lurk mode (nickName == "") +function experimentsEnter(playerId, roomId) { + print("MOD: " + players[playerId].nickName + " entered room " + roomId); + + //a full screen welcome text appears + longText = "Welcome " + players[playerId].nickName; + longTextLines = -1; + longTextAlign = "center"; +} + +//roomnameExit: called right before a player exits or disconnects +function experimentsExit(playerId) { + print("MOD: " + players[playerId].nickName + " exited room " + roomId); +} + +//called every frame in a specific room - beware: this is client side, everything non deterministic and non server-driven +//may misalign the players clients +function experimentsUpdate() { + //print("MOD: updating experiments"); +} + +//roomnameTalk: called when somebody in the room talks, passes player object and the new bubble (before it's added to the stack and before the sound is made) +function experimentsTalk(playerId, bubble) { + print("MOD: " + players[playerId].nickName + " said " + bubble.message); + + //overwrites the color + bubble.color = color("#FFFFFF"); + //all bubbles show up in the center and lines are not drawn + /* + bubble.x = WIDTH / 2 - bubble.w / 2; + bubble.y = HEIGHT / 2; + bubble.px = 0; + bubble.py = 0; + */ +} + +//this can override or modify the normal player drawing function +function experimentsDrawSprite(playerId, sprite, drawingFunction) { + //print("MOD: " + players[playerId].nickName + " being drawn experimentally " + sprite.width); //let's not call this at every frame + + //the normal drawing function comment this out to see the examples below + drawingFunction(); + + /* + //don't try this + tint(random(0, 255), random(0, 255), random(0, 255)); + drawingFunction(); + noTint(); + */ + + //draw a square + /* + fill(0); + rect(0, 0, 10, 10); + */ + + /* + //sprites drawn horizontally and 20 pixel above the grund + push(); + translate(0, -20); + angleMode(DEGREES); + rotate(90); + //the original drawing function + drawingFunction(); + pop(); + */ + +} + diff --git a/server.js b/server.js index 1f908a2..5df4195 100644 --- a/server.js +++ b/server.js @@ -10,6 +10,14 @@ ADMINS=username1|pass1,username2|pass2 PORT = 3000 */ +var MOD = {}; +//load server side mod file +try { + MOD = require('./serverMod'); +} +catch (e) { +} + var port = process.env.PORT || 3000; //number of emits per second allowed for each player, after that ban the IP. @@ -219,6 +227,12 @@ io.on('connection', function (socket) { if (playerInfo.nickName != "") visits++; + //check if there is a custom function in the MOD to call at this point + if (MOD["joinGame"] != null) { + //call it! + MOD["joinGame"](newPlayer, playerInfo.room); + } + //send all players information about the new player //upon creation destination and position are the same io.to(playerInfo.room).emit('playerJoined', newPlayer); @@ -307,7 +321,22 @@ io.on('connection', function (socket) { console.log(socket.id + " is problematic"); } else { - io.to(obj.room).emit('playerTalked', { id: socket.id, color: obj.color, message: obj.message, x: obj.x, y: obj.y }); + + //check if there is a custom function in the MOD to call at this point + if (MOD[obj.room + "TalkFilter"] != null) { + + //call it! + obj.message = MOD[obj.room + "TalkFilter"](gameState.players[socket.id], obj.message); + + if (obj.message == null) { + console.log("MOD: Warning - TalkFilter should return a message "); + obj.message = ""; + } + + } + + if (obj.message != "") + io.to(obj.room).emit('playerTalked', { id: socket.id, color: obj.color, message: obj.message, x: obj.x, y: obj.y }); } } @@ -343,10 +372,10 @@ io.on('connection', function (socket) { else { //console.log("Player " + socket.id + " moved from " + obj.from + " to " + obj.to); - socket.leave(obj.from); socket.join(obj.to); + //broadcast the change to everybody in the current room //from the client perspective leaving the room is the same as disconnecting io.to(obj.from).emit('playerLeft', { id: socket.id, disconnect: false }); @@ -357,6 +386,19 @@ io.on('connection', function (socket) { playerObject.x = playerObject.destinationX = obj.x; playerObject.y = playerObject.destinationY = obj.y; playerObject.new = false; + + //check if there is a custom function in the MOD to call at this point + if (MOD[obj.from + "Exit"] != null) { + //call it! + MOD[obj.from + "Exit"](playerObject, obj.from); + } + + //check if there is a custom function in the MOD to call at this point + if (MOD[obj.to + "Enter"] != null) { + //call it! + MOD[obj.to + "Enter"](playerObject, obj.to); + } + io.to(obj.to).emit('playerJoined', playerObject); } } catch (e) { @@ -667,5 +709,6 @@ let myBadWords = ['chink', 'cunt', 'cunts', "fag", "fagging", "faggitt", "faggot var filter = new Filter({ emptyList: true }); filter.addWords(...myBadWords); - +//p5 style alias +function print(s) { console.log(s); } diff --git a/serverMod.js b/serverMod.js new file mode 100644 index 0000000..445b587 --- /dev/null +++ b/serverMod.js @@ -0,0 +1,33 @@ +/* +WARNING: THIS IS STILL EXPERIMENTAL STUFF +I want to have the ability to assign specific behaviors to each room without messing with the main engine +So I'm creating a module for server-side modifications (mods). There is one also for the client. +Their naming convention is roomIdFunction. +The functions are called by the engine at crucial points, only if they exist. +*/ + +module.exports.joinGame = function (player, roomId) { + //console.log("MOD: Player " + player.nickName + " joined the game at room " + roomId); + + //objects are passed by reference so this actually changes the nickname on the server (but not on the client) + //player.nickName = "Dude"; +} + +//custom function called on the server side when a player successfully enters or exits the room +//executed before it's broadcast to the other players +module.exports.experimentsEnter = function (player, roomId) { + console.log("MOD: " + player.nickName + " entered room " + roomId); +} + +module.exports.experimentsExit = function (player, roomId) { + console.log("MOD: " + player.nickName + " exited room " + roomId); +} + +//wouldn't it be funny if cetain rooms modified your messages? +module.exports.experimentsTalkFilter = function (player, message) { + + console.log("MOD: " + player.nickName + " said " + message); + message = message.replace(/[aeiou]/ig, ''); + //make sure it returns a message + return message; +} \ No newline at end of file