diff --git a/interval_tasks.py b/interval_tasks.py new file mode 100644 index 0000000..f689619 --- /dev/null +++ b/interval_tasks.py @@ -0,0 +1,79 @@ +from queue import Queue + + +class IntervalTaskMaster (): + def __init__(self, socketio): + self.socketio = socketio + self.tasks_by_id = {} + self.tasks_id = 0 + self.queue = Queue() + + def start (self): + self.socketio.start_background_task(self.background_task) + + def background_task(self): + st = 0 + while True: + print (f"IntervalTaskMaster is running with {len(self.tasks_by_id)} pending tasks") + # Add any items in the queue + while not self.queue.empty(): + task_id, callback, time, interval = self.queue.get() + print (f"CREATING TASK {task_id} interval:{interval}") + self.tasks_by_id[task_id] = Task(task_id, callback, time, interval) + + remove_intervals = [] + for task_id, task in self.tasks_by_id.items(): + print (f"servicing task {task_id}") + ran_task = task.service(st) + if not task.interval and ran_task: + remove_intervals.append(task_id) + for task_id in remove_intervals: + print (f"deleting task {task_id}") + del self.tasks_by_id[task_id] + st = self.calc_current_sleep_time_ms() + print (f"taskmaster sleeping {st}") + self.socketio.sleep(st/1000) + + def calc_current_sleep_time_ms(self): + min_time = None + for task in self.tasks_by_id.values(): + if min_time == None or task.time < min_time: + min_time = task.time + if min_time is None: + return 1000 + else: + return min(10000, min_time / 2) + + def setTimeout (self, callback, time, interval=False): + task_id = self.tasks_id + self.tasks_id += 1 + self.queue.put((task_id, callback, time, interval)) + return task_id + + def clearTimeout (self, task_id): + try: + del self.tasks_by_id[task_id] + return True + except KeyError: + pass + + def setInterval(self, callback, time): + return self.setTimeout(callback, time, True) + + def clearInterval(self, task_id): + return self.clearTimeout(task_id) + +class Task (): + def __init__(self, task_id, callback, time, interval=False): + self.task_id = task_id + self.callback = callback + self.time = time + self.interval = interval + self.current_timer = time + + def service (self, elapsed_time): + self.current_timer -= elapsed_time + if self.current_timer <= 0: + self.current_timer = 0 + self.callback() + return True diff --git a/npc.py b/npc.py new file mode 100644 index 0000000..f3d3d3e --- /dev/null +++ b/npc.py @@ -0,0 +1,81 @@ +""" +NPC +exists in a room +broadcasts the the same join, leave, move, talk, intro events +is rendered like and avatar by the client +is controlled by the server +""" +from flask_socketio import emit, send + + +class NPC (): + + def __init__(self, io, o, gameState): + print(f"Create NPC {o['id']} in room {o['room']} nickNamed {o['nickName']}") + self.io = io + self.gameState = gameState + self.id = o['id'] + self.nickName = o['nickName'] + self.room = o['room'] + self.avatar = o['avatar'] + self.colors = o['colors'] + self.x = o['x'] * 2; + self.y = o['y'] * 2; + self.destinationX = o['x'] + self.destinationY = o['y'] + + if o['labelColor']: + self.labelColor = o['labelColor'] + else: + self.labelColor = "#FFFFFF" # oops server doesn't know about colors + + # add to NPC list + self.gameState['NPCs'][self.id] = self + + def sendIntroTo (self, pId): + """ mimicks the emission from players """ + print(f"HELLO I'm {self.nickName} in {self.room}, pId: {pId}") + # If I'm not the new player send an introduction to the new player + # slight issue, server doesn't compute movements so if moving it appears at the destination + # a way to solve this would be to save the time of the movement and lerp it + self.io.emit("onIntro", { + 'id': self.id, + 'nickName': self.nickName, + 'colors': self.colors, + 'avatar': self.avatar, + 'room': self.room, + 'x': self.destinationX, + 'y': self.destinationY, + 'destinationX': self.destinationX, + 'destinationY': self.destinationY + }, room=pId) + + def move (self, dx, dy): + print(f"HELLO I'm {self.nickName} and I move to {dx} {dy} in room: {self.room}") + # broadcast the movement to everybody in the room + # it doesn't check if the position is valid + + self.io.emit("playerMoved", { + 'id': self.id, + 'x': self.x, + 'y': self.y, + 'destinationX': dx, + 'destinationY': dy + }, room=self.room) + # update for future intros + self.destinationX = self.x = dx + self.destinationY = self.y = dy + + def talk (self, message): + self.io.emit("playerTalked", { + 'id': self.id, + 'color': self.labelColor, + 'message': message, + 'x': self.x, + 'y': self.y + }, room=self.room) + + def delete (self): + self.io.emit("playerLeft", { 'id': self.id, 'room': self.room, 'disconnect': true }, room=self.room) + del self.gameState['NPCs'][self.id] + diff --git a/public/client.js b/public/client.js index f8b81aa..d44967e 100644 --- a/public/client.js +++ b/public/client.js @@ -874,13 +874,15 @@ function newGame() { socket.on("playerMoved", function (p) { try { - //console.log(p.id + " moves to: " + p.destinationX + " " + p.destinationY); + console.log(p.id + " moves to: " + p.destinationX + " " + p.destinationY); //make sure the player exists if (players.hasOwnProperty(p.id)) { - + console.log("YES"); players[p.id].destinationX = p.destinationX; players[p.id].destinationY = p.destinationY; + } else { + console.log("NO"); } } catch (e) { console.log("Error on playerMoved"); diff --git a/server.py b/server.py index d8fd97f..8b24a58 100644 --- a/server.py +++ b/server.py @@ -62,12 +62,20 @@ app.add_url_rule("/", view_func=lambda **kw: app.send_static_file("index.html", socketio = SocketIO(app) connections = 0 +from interval_tasks import IntervalTaskMaster + +# def background_task(): +# while True: +# print ("I'm running in the background") +# socketio.sleep(5) + + @socketio.on('connect') def connect(sid=None, environ=None, auth=None): global connections connections += 1 print (f"A user connected ({connections} connections)") - emit('serverWelcome', (VERSION, DATA, START_TIME.isoformat())) + emit('serverWelcome', (VERSION, DATA, START_TIME)) @socketio.on('disconnect') def disconnect(auth=None): @@ -84,9 +92,9 @@ def disconnect(auth=None): # check if there is a custom function in the MOD to call at this point if playerObject is not None: if playerObject['room']: - if (playerObject['room']+"Leave" in MOD): - # call it! - MOD[playerObject.room+"Leave"](playerObject, playerObject['room']) + if hasattr(MOD, playerObject['room']+"Leave"): + mod_fn = getattr(MOD, playerObject['room']+"Leave") + mod_fn(playerObject, playerObject['room']) # send the disconnect # delete the player object @@ -207,12 +215,13 @@ def join (playerInfo): # check if there are NPCs in this room and make them send info to the player for NPCId in gameState['NPCs']: npc = gameState['NPCs'][NPCId] - if npc['room'] == playerInfo['room']: + if npc.room == playerInfo['room']: npc.sendIntroTo(flask.request.sid) #check if there is a custom function in the MOD to call at this point - if playerInfo['room']+"Join" in MOD: + if hasattr(MOD, playerInfo['room']+"Join"): # call it! - MOD[playerInfo['room']+"Join"](newPlayer, playerInfo['room']) + mod_fn = getattr(MOD, playerInfo['room']+"Join") + mod_fn(newPlayer, playerInfo['room']) print(f"There are now {len(gameState['players'])} players on this server. Total visits {visits}") except Exception as e: @@ -227,8 +236,9 @@ def intro (newComer, obj): if (obj is not None): if obj['id'] == flask.request.sid: emit("onIntro", obj, room=newComer) - if (obj['room'] + "Intro" in MOD): - MOD[obj.room + "Intro"](newComer, obj) + if hasattr(MOD, obj['room'] + "Intro"): + mod_fn = getattr(MOD, obj['room'] + "Intro") + mod_fn(newComer, obj) else: print(f"ATTENTION: Illegitimate intro from {flask.request.sid}") @@ -277,10 +287,9 @@ def talk (obj): else: # check if there is a custom function in the MOD to call at this point - if obj['room']+"TalkFilter" in MOD: - - # call it! - obj.message = MOD[obj.room + "TalkFilter"](gameState['players'][flask.request.sid], obj['message']) + if hasattr(MOD, obj['room']+"TalkFilter"): + mod_fn = getattr(MOD, obj['room']+"TalkFilter") + obj.message = mod_fn(gameState['players'][flask.request.sid], obj['message']) if obj['message'] is not None: print("MOD: Warning - TalkFilter should return a message ") @@ -335,16 +344,16 @@ def changeRoom (obj): playerObject['new'] = False # check if there is a custom function in the MOD to call at this point - if obj['from']+"Leave" in MOD: - # call it! - MOD[obj['from'] + "Leave"](playerObject, obj['from']) + if hasattr(MOD, obj['from']+"Leave"): + mod_fn = getattr(MOD, obj['from']+"Leave") + mod_fn(playerObject, obj['from']) emit("playerJoined", playerObject, room=obj['to']) # check if there is a custom function in the MOD to call at this point - if obj['to']+"Join" in MOD: - # call it! - MOD[obj['to']+"Join"](playerObject, obj['to']) + if hasattr(MOD, obj['to']+"Join"): + mod_fn = getattr(MOD, obj['to']+"Join") + mod_fn(playerObject, obj['to']) # check if there are NPCs in this room and make them send info to the player for NPCId in gameState['NPCs']: @@ -413,10 +422,10 @@ def blur(obj): @socketio.on('action') def action(aId): """ generic action listener, looks for a function with that id in the mod """ - if "on"+aId in MOD: - # call it! + if hasattr(MOD, "on"+aId): + mod_fn = getattr(MOD, "on"+aId) # print(f"on {aId} exists in the mod, call it") - MOD["on"+aId](flask.request.sid); + mod_fn(flask.request.sid); def validateName(nn): admin = False @@ -570,22 +579,25 @@ def IPByName(nick): class BadWordsFilter (object): def __init__(self, initial_data=None): - pass + self.words=[] def clean (self, text): return text def isProfane(self, text): return False - -filter = BadWordsFilter() + def addWords(self, *words): + self.words.extend(words) +filter = BadWordsFilter() +taskmaster = IntervalTaskMaster(socketio) # modding MOD = {} -# try: -# import serverMod as MOD -# MOD.initMod(gameState, DATA) -# except ImportError: -# pass +try: + import serverMod as MOD + MOD.initMod(socketio, gameState, DATA, taskmaster) +except ImportError as e: + print (f"Error importing serverMod: {e}") if __name__ == '__main__': + taskmaster.start() socketio.run(app) \ No newline at end of file diff --git a/serverMod.py b/serverMod.py new file mode 100644 index 0000000..88b0c4a --- /dev/null +++ b/serverMod.py @@ -0,0 +1,572 @@ +from npc import NPC +import random, re, json +from flask_socketio import emit + +""" +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. +""" + +# family room roles +# values are id's of player +familyRoles = { + 'wife': "", + 'husband': "", + 'child1': "", + 'child2': "", + 'child3': "", + 'uncle': "", + 'milkman': "", + 'boyfriend': "" +} + +lastRhymes = [] +rhymingPlayers = {} +beatPlaying = False + +paranoidTalk = [ + "Hey you", + "There are bots in here", + "Are you a bot?", + "Russia is controlling the bots", + "Are you real?", + "Yes", + "I don't trust you", + "This is weird", + "Prove you are human", + "No", + "Have you seen that?", + "That person is a bot", + "Listen", + "Bots everywhere", + "Hello", + "Another bot" +]; + +with open("dictionary.json") as fin: + dictionary = json.load(fin) + +# cycle through contraints in the consonant room +consonant = 0 + + +def random_between (min, max): + return random.random() * (max-min) + min + +VIPList = [] + +def initMod (io, gameState, DATA, taskmaster): + """ called at the beginning """ + print("MOD: Initialized"); + + # EVERYTHING GLOBALLLLL + # global.rita = require('rita'); + # global.gameState = gameState; + # global.io = io; + # global.DATA = DATA; + + # //global function ffs + # global.random = function (min, max) { + # return Math.random() * (max - min) + min; + # } + + + # Example of NPC creation and behavior + + npc = NPC(io, { + 'id': "paranoid", + 'nickName': "Anonymous", + 'room': "secondFloor", + 'x': 23, + 'y': 78, + 'avatar': 1, + 'colors': [2, 2, 1, 5], + 'labelColor': "#1e839d" + }, gameState) + + def ramble(): + print ("ramble") + dice = random_between(0, 100) + + if (dice < 40): + npc.talk(random.choice(paranoidTalk)) + npc.behavior = taskmaster.setTimeout(ramble, random_between(7000, 9000)) + elif (dice < 60): + npc.move(random_between(17, 113) * 2, random_between(76, 98) * 2) + npc.behavior = taskmaster.setTimeout(ramble, random_between(4000, 8000)) + else: + # just wait + npc.behavior = taskmaster.setTimeout(ramble, random_between(1000, 3000)); + # to kill the bot + # clearTimeout(npc.behavior) + # npc.delete() + + npc.behavior = taskmaster.setTimeout(ramble, random_between(1000, 2000)) + + def consonant_interval(): + global consonant + print (f"consonant_interval: {consonant}") + # aeiou- + consonant+=1 + if (consonant > 5): + consonant = 0 + + msg = "" + + if (consonant == 0): # a + msg = "All art appalls a fan" + elif (consonant == 1): # e + msg = "Greet her when she enters" + elif (consonant == 2): # i + msg = "I sit ildly till twilight" + elif (consonant == 3): # o + msg = "No stools, no books: work protocol" + elif (consonant == 4): # u + msg = "But truth: dull suburbs turn fun" + elif (consonant == 5): # none + msg = "Tsk, tsk... try my rhythms" + + # sends a message to the room + io.emit('nonPlayerTalked', { 'id': "", 'labelColor': "#3e7eb0", 'room': "cnsnntrm", 'message': msg, 'x': 36, 'y': 56 }, room="cnsnntrm") + + + taskmaster.setInterval(consonant_interval, 60*1000) + + +# # 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 +# def experimentsJoin(player, roomId): +# # print("MOD: " + player.nickName + " entered room " + roomId) +# pass + +# def experimentsLeave(player, roomId): +# # print("MOD: " + player.nickName + " exited room " + roomId) +# pass + +# def experimentsTalkFilter(player, message): +# """ wouldn't it be funny if cetain rooms modified your messages? """ + +# # print("MOD: " + player.nickName + " said " + message); +# # message = re.sub('[aeiou]', '', message, flags=re.I) +# # make sure it returns a message +# return message + + + +# # wouldn't it be funny if cetain rooms modified your messages? +# def VIPRoomTalkFilter(player, message): +# # print("MOD: " + player.nickName + " said " + message); +# message = rita.getPhonemes(message) +# message = message.replace(/-/g, "") +# # make sure it returns a message +# return message + +# # wouldn't it be funny if cetain rooms modified your messages? +# def cnsnntrmTalkFilter(player, message): + +# # print("MOD: " + player.nickName + " said " + message) + +# if (global.consonant == 0) # a +# message = message.replace(/[eiou]/ig, 'a'); +# if (global.consonant == 1) # e +# message = message.replace(/[aiou]/ig, 'e'); +# if (global.consonant == 2) # i +# message = message.replace(/[aeou]/ig, 'i'); +# if (global.consonant == 3) # o +# message = message.replace(/[aeiu]/ig, 'o'); +# if (global.consonant == 4) # u +# message = message.replace(/[aeio]/ig, 'u'); +# if (global.consonant == 5) # none +# message = message.replace(/[aeiou]/ig, ''); + + +# //make sure it returns a message +# return message; +# } + +# //words can only be used once +# module.exports.censorshipRoomTalkFilter = function (player, message) { + +# //create a list of censored words +# if (global.forbiddenWords == null) { +# global.forbiddenWords = []; +# } + +# //strip special characters +# message = message.replace(/[`~!@#$%^&*()_|+\-=?;:",.<>\{\}\[\]\\\/]/gi, ''); + +# //break down the message into words +# var words = message.split(" "); +# var censoredMessage = ""; + +# //check each single word +# for (var j = 0; j < words.length; j++) { + +# /* +# //remove repeated character if they occur more than twice like hellooooo > hello +# var word = words[j]; +# var pChar = ""; +# var ppChar = ""; +# var newWord = ""; + +# for (var k = 0; k < word.length; k++) { +# var newChar = word[k]; + +# if (pChar == "" || ppChar == "" || !(newChar == ppChar && newChar == pChar)) { +# newWord += newChar; +# } +# ppChar = pChar; +# pChar = newChar; +# } +# */ + +# var newWord = words[j]; + +# //found, censor +# if (forbiddenWords.indexOf(newWord.toLowerCase()) > -1) { +# var l = newWord.length; +# var bleep = ""; +# for (var i = 0; i < l; i++) { +# bleep += "*"; +# } + +# censoredMessage += bleep; + +# } +# else { +# censoredMessage += newWord; +# //not found add +# forbiddenWords.push(newWord.toLowerCase()); +# } + +# if (j < words.length - 1) +# censoredMessage += " "; +# } + + +# return censoredMessage; + +# } + + +# module.exports.rhymeRoomTalkFilter = function (player, message) { +# // +# if (global.beat == null) +# global.beat = 1; + +# var arr = message.split(" "); +# var lastWord = ""; + +# if (arr.length > 0) +# lastWord = arr[arr.length - 1].toLowerCase(); + +# //extended dictionary +# var exists = global.dictionary.indexOf(lastWord) != -1; + +# var first = false; +# var lastRhyme = ""; +# var used = false; + + +# if (global.lastRhymes.length == 0) +# first = true; +# else { +# used = global.lastRhymes.indexOf(lastWord) != -1; + +# lastRhyme = global.lastRhymes[global.lastRhymes.length - 1].toLowerCase(); + +# } + +# if (exists && !used) { + +# var rhymes = false; + +# //not first check the rhym +# if (!first) +# rhymes = global.rita.isRhyme(lastWord, lastRhyme); + +# //start the battle +# if (first || rhymes) { + +# if (global.beatPlaying == false) { + +# io.to("rhymeRoom").emit('musicOn', global.beat); +# global.beatPlaying = true; +# } + +# global.lastRhymes.push(lastWord); + +# //create the rhyming player score +# if (global.rhymingPlayers[player.nickName] == null) +# global.rhymingPlayers[player.nickName] = 0; + +# //calculate the score by counting the real words +# //skip the first +# if (global.lastRhymes.length > 1) { +# for (var i = 0; i < arr.length; i++) { +# if (global.rita.containsWord(arr[i])) +# global.rhymingPlayers[player.nickName]++; +# } +# } + +# //console.log("YEAH " + player.nickName + " " + lastWord + "! Words uttered " + global.rhymingPlayers[player.nickName]); + +# clearTimeout(global.rhymeTime); + +# global.rhymeTime = setTimeout(function () { +# //console.log("Rhyme timeout"); + +# //send to everybody in the room +# io.to("rhymeRoom").emit('musicOff'); +# global.beatPlaying = false; +# //change record +# global.beat++; +# if (global.beat > 3) +# global.beat = 1; + +# var highscore = 0; +# var winner = ""; +# //find high score +# for (var nn in global.rhymingPlayers) { +# if (global.rhymingPlayers[nn] >= 4 && global.rhymingPlayers[nn] > highscore) { +# winner = nn; +# highscore = global.rhymingPlayers[nn]; +# } +# } +# global.lastRhymes = []; +# global.rhymingPlayers = {}; +# if (winner != "") { +# io.to("rhymeRoom").emit('godMessage', winner + " wins!" + highscore + " words uttered"); + +# } +# }, 8000); + +# return message; +# }//doesn't ryme +# else { +# return "..."; +# } +# }//doesn't exist +# else { +# return "..."; +# } +# } + +# //if enters when music is playing sent +# module.exports.rhymeRoomJoin = function (playerObject, roomId) { + +# if (io.sockets.sockets[playerObject.id] != null && global.beatPlaying) { +# io.sockets.sockets[playerObject.id].emit('musicEnter', global.beat); + +# } + +# } + +# //if enters when music is playing sent +# module.exports.rhymeRoomLeave = function (playerObject, roomId) { + +# if (io.sockets.sockets[playerObject.id] != null) { +# io.sockets.sockets[playerObject.id].emit('musicExit'); + +# } +# } + +# module.exports.darkRoomTalkFilter = function (player, message) { +# //I should declare them at the init but whatev +# var nouns = ["ass", "climax", "coitus", "boner", "booty", "threesome", "tush", "lust", "orgy", "libido", "dildo", "kink", +# "porno", "buttplug", "cunnilingus", "cybersex", "sex", "cum", "orgasm", "quickie", "intercourse", "cock", "penis", "dick", "pussy", "fanny", "vagina", "clit", "butt"]; +# var verbs = ["love", "shag", "mate", "seduce", "hook up", "hump", "arouse", "fornicate", "erect", "get some", "bone", "bang", "fuck", "lick", "suck", "cum", "penetrate", "screw", "sodomize", "arouse", "kiss", "pet", "masturbate", "come"]; + +# var arr = rita.tokenize(message); +# var replaced = false; + +# for (var i = 0; i < arr.length && !replaced; i++) { +# var word = arr[i]; +# //skip verbs 50% since they are more likely to come before nouns +# if (rita.isVerb(word) && Math.random() < 0.5) { +# arr[i] = rita.randomItem(verbs); +# replaced = true; +# } +# if (rita.isNoun(word)) { +# arr[i] = rita.randomItem(nouns); +# replaced = true; +# } + +# } + +# return arr.join(" "); +# } + +# //player enters family room roles are assigned by the server +# module.exports.familyRoomJoin = function (playerObject, roomId) { + +# var foundRole = false; +# for (var roleId in global.familyRoles) { +# //role not assigned +# if (global.familyRoles[roleId] == "" && !foundRole) { +# foundRole = true; +# global.familyRoles[roleId] = playerObject.id; +# console.log(playerObject.id + " becomes " + roleId); +# } +# } + +# if (!foundRole) +# console.log(playerObject.id + " becomes a fly"); + +# //assign a new role and send all the roles to the room + +# io.to("familyRoom").emit('updateRoles', playerObject.id, global.familyRoles); + +# //io.to("familyRoom").emit('assignRole', { id: playerObject.id, roleId: "wife", roleLabel: "Wife", rolePrompt: "You are feeling frustrated" }); +# //send the existing roles +# } + +# //exit > free up the role +# //player enters family room roles are assigned by the server +# module.exports.familyRoomLeave = function (playerObject, roomId) { + +# for (var roleId in global.familyRoles) { +# //role not assigned +# if (global.familyRoles[roleId] == playerObject.id) { + +# global.familyRoles[roleId] = ""; +# console.log(roleId + " is now free"); +# } +# } +# //I don't need to send updated roles +# //io.to("familyRoom").emit('updateRoles', playerObject.id, global.familyRoles); + +# } + +# //mute spectators on the server-side +# module.exports.familyRoomTalkFilter = function (player, message) { +# var spectator = true; + +# for (var roleId in global.familyRoles) { +# //role assigned +# if (global.familyRoles[roleId] == player.id) { +# spectator = false; +# } +# } + +# if (spectator) +# return "zzzz"; +# else +# return message; + +# } + +# module.exports.VIPRoomJoin = function (playerObject, roomId) { +# //console.log(playerObject.nickName + " enters the VIP room"); +# //... +# global.VIPList.push(playerObject.id); +# if (global.VIPList.length > 3) { +# var expelled = global.VIPList.shift(); + +# //force leave +# if (io.sockets.sockets[expelled] != null) { + +# this.transferPlayer(expelled, "VIPRoom", "likelikeOutside", 121 * 2, 89 * 2); +# io.to(expelled).emit('godMessage', "Sorry, we had to expel you to make room for " + playerObject.nickName); +# } + +# } + +# } + +# module.exports.VIPRoomIntro = function (newComerId, introObj) { +# //the problem with the auto expulsion in VIPRoom is that the intro is sent before it's the other person is expelled +# //so the intros arrive too late creating ghosts. +# //since the server has the real list I can override the intro after the fact and expel the ghost. Ugly but necessary. + +# //console.log("Obsolete intro? " + gameState.players[introObj.id].room); + +# if (gameState.players[introObj.id].room != "VIPRoom") +# io.to("VIPRoom").emit("playerLeft", { id: introObj.id, room: "VIPRoom", disconnect: false }); + +# } + +# //force change room +# module.exports.transferPlayer = function (playerId, from, to, x, y) { +# //console.log(playerId + " is transfered to " + to); + +# var s = io.sockets.sockets[playerId]; +# var p = gameState.players[playerId]; + +# if (s != null) +# if (p.room != null) { + +# //var from = p.room; +# s.leave(from); +# s.join(to); + +# //broadcast the change to everybody in the current room +# //from the client perspective leaving the room is the same as disconnecting +# io.to(from).emit("playerLeft", { id: playerId, room: from, disconnect: false }); + +# //same for joining, sending everybody in the room the player state + +# p.room = to; +# p.x = p.destinationX = x; +# p.y = p.destinationY = y; +# p.new = false; + + +# //check if there is a custom function in the MOD to call at this point +# if (this[from + "Leave"] != null) { +# //call it! +# this[from + "Leave"](p, from); +# } + +# io.to(to).emit("playerJoined", p); + + +# //check if there is a custom function in the MOD to call at this point +# if (this[to + "Join"] != null) { +# //call it! +# this[to + "Join"](p, to); +# } + +# //check if there are NPCs in this room and make them send info to the player +# for (var NPCId in gameState.NPCs) { +# var npc = gameState.NPCs[NPCId]; + +# if (npc.room == to) { +# npc.sendIntroTo(playerId); +# } +# } + +# } +# } + +# //if a player leaves the room on their own accord make sure they are removed from the list as well +# module.exports.VIPRoomLeave = function (playerObject, roomId) { +# //console.log(playerObject.nickName + " exits the VIP room"); + +# var index = global.VIPList.indexOf(playerObject.id); +# if (index !== -1) { +# global.VIPList.splice(index, 1); +# } + +# } + + +# //a client can send generic action request to the server +# //the action logic is defined in functions named "on"+ActionId like this one +# //I don't want a hacked client to be able to call whatever function exists on the server mod hence the naming +# //and I want send only an id without arguments to force all my logic here on the server side +# module.exports.onTVInteract = function (pId) { +# //console.log("Action onTVInteract called by " + pId); + +# //a persistent change to the game state: change the DATA sent to the new players +# //*persistent until server restarts + +# var TVState = !DATA.ROOMS.familyRoom.things.TV.visible; +# //change the visibility +# DATA.ROOMS.familyRoom.things.TV.visible = TVState; +# //send a thing update too ALL clients, changing the client data and telling them to delete and recreate the sprite if they are in the room +# io.sockets.emit("thingChanged", { thingId: "TV", room: "familyRoom", property: "visible", value: TVState }); +# } \ No newline at end of file