diff --git a/DataCollection/gamedata.json b/DataCollection/gamedata.json index 4c48386..1cd3777 100644 --- a/DataCollection/gamedata.json +++ b/DataCollection/gamedata.json @@ -1,17 +1,28 @@ {"messages":{ - "login_format":"Welcome to the land of Horse Isle, %USERNAME%!!", + "welcome_format":"Welcome to the land of Horse Isle, %USERNAME%!!", "motd_format":"Today's Note: %MOTD%", "mail_received":"A message has been sent to you from another player. It is in your inventory now.", - "login_message":"Player %USERNAME% has logged in", - "logout_message":"Player %USERNAME% has disconnected", + "login_format":"Player %USERNAME% has logged in", + "logout_format":"Player %USERNAME% has disconnected", "profile_save":"Your profile changes were saved.", "buddy_request":"Attempting to Add Buddy. The other player must click ADD BUDDY as well. (Many players reserve this for just a couple players so don't feel insulted if they do not).", + "drawing_notice":"Drawing not sent to other players when you are not a subscriber.", + "tag":{ + "for_sender":"TAG!! %USERNAME% is now it! (tagged by %TAGGER%) [%AMOUNT% buds]", + "for_others":"TAG!! %USERNAME% is now it! (tagged by %TAGGER%)" + }, "commands":{ "mute_help":"PLAYER COMMAND [%COMMAND%] COMPLETED Mute Channel Not Recognized. (ALL/ADS/GLOBAL/ISLAND/NEAR/HERE/BUDDY/PM/BR/SOCIALS/LOGINS)", "command_completed":"PLAYER COMMAND [%COMMAND%] COMPLETED" }, "disconnect":{ - "banned":"Your account has been BANNED. You will no longer be able to login" + "banned":"Your account has been BANNED. You will no longer be able to login", + "client_timeout":{ + "warn_after":10, + "kick_after":25, + "warn_message":"You have been idle for %WARN% minutes. You will be disconnected at %KICK% minutes idle", + "kick_message":"%KICK% Minute Player Idle Timeout Reached" + } }, "login":{ "banned":"Your account has been banned. This occurs when too many rules have been broken", @@ -29,6 +40,112 @@ "bridge_text":"A bridge crosses over the water to another isle. That'll save you some travel costs!" } }, + "socials":{ + "for_sender":{ + "friendly":{ + "smile":"* You smile at %USERNAME%. *", + "wave":"* You wave enthusiastically at %USERNAME%! *", + "wink":"* You sneak a wink off to %USERNAME%. *", + "laugh":"* You laugh at %USERNAME%'s humor. *", + "high5":"* You give a big high-five to %USERNAME%! *", + "clap":"* You clap at what %USERNAME% has done! *", + "hug":"* You give %USERNAME% a welcome hug. *", + "bearhug":"* You nearly crush %USERNAME% with your massive bearhug! *", + "dance":"* You do a little dance with %USERNAME%! *", + "nod":"* You nod at %USERNAME%. *", + "tickle":"* You tickle %USERNAME%'s sides. *", + "thumbsup":"* You give %USERNAME% an enthusiastic thumbs up. *", + "shoulderpat":"* You pat %USERNAME% comfortingly on the shoulder. *", + "circle":"* You run circles around %USERNAME% making them dizzy. *", + "glomp":"* You surprise %USERNAME% by tackling and hugging them very tightly! %USERNAME% squeaks in surprise! *", + "beam":"* You produce one of the biggest, happiest faces possible towards %USERNAME%! *", + "handshake":"* You shake hands with %USERNAME% enthusiastically. *", + "rofl":"* %USERNAME% is so funny you end up rolling on the floor from laughing so hard!! *", + "spin":"* You playfully spin %USERNAME% in circles making them dizzy. *", + "sing":"* You sing a silly song to %USERNAME% hoping they laugh. *", + "flail":"* You flail wildly at %USERNAME%! *" + }, + "unfriendly":{ + "frown":"* You frown upon %USERNAME%'s behavior. *", + "poke":"* You poke %USERNAME% right in the ribs! *", + "ignore":"* You stick your nose in the air and ignore %USERNAME%s childish behavior! *", + "growl":"* In a deep growling voice, you attempt to frighten %USERNAME%! *", + "point":"* You point jokingly at %USERNAME%! *", + "burp":"* BuuuuuuuurrrrP! *", + "cry":"* %USERNAME% has made you cry like a little baby! *", + "yell":"* You start yelling angrily at %USERNAME%. *", + "nudge":"* You nudge %USERNAME% carefully out of your way. *", + "yawn":"* YYYYAAAAWWWWNNNNN... Boy %USERNAME% is boring... *", + "tease":"* You laughingly tease %USERNAME% about their silly shoes. *", + "quack":"* You make weird animal noises at %USERNAME% trying to sound like a ferocious... duck. *", + "snore":"* ZZzzzzz.... %USERNAME% has bored you to the point of SNORING!! Wow.. now, that is boring.. *", + "scream":"* AAAAAAAAAAAAAHHH!!!! You scream loudly at %USERNAME%.. . maybe overreacting? *", + "hide":"* You quickly hide in the shadows, hoping %USERNAME% does not see you. . . *", + "trip":"* Poor %USERNAME% tripped over your giant hobbitty feet!! *", + "roar":"* From the bottom of your being you release the loudest roar possible!. . Only. . on its way out, your voice squeaks a little, and that takes away from the intimidation. . . *", + "boo":"* BOOOOO! You frighten %USERNAME% really bad! They did not see that coming! *" + }, + "horse":{ + "wink":"* Your horse winks at %USERNAME%. *", + "neigh":"* Your horse neighs loudly at %USERNAME%. *", + "whinny":"* Your horse whinnies softly and happily towards %USERNAME%. *", + "snort":"* Your horse rudely snorts towards %USERNAME%! *", + "buck":"* Your horse bucks you lightly. Must have been excited to see %USERNAME%. *" + } + }, + "for_others":{ + "friendly":{ + "smile":"* %USERNAME% smiles at you. *", + "wave":"* %USERNAME% is waving at you very enthusiastically! *", + "wink":"* %USERNAME% winks at you secretively. *", + "laugh":"* %USERNAME% laughs at your humor. *", + "high5":"* %USERNAME% comes at you with a high-five! You manage to meet the clap in time! *", + "clap":"* %USERNAME% is clapping at what you have accomplished! *", + "hug":"* %USERNAME% gives you a hug. *", + "bearhug":"* %USERNAME% nearly crushes you with a massive bearhug! *", + "dance":"* %USERNAME% and you do a little dance! *", + "nod":"* %USERNAME% nods at you. *", + "tickle":"* %USERNAME% tickles your sides until you fall over laughing. *", + "thumbsup":"* %USERNAME% gives you an enthusiastic thumbs up. *", + "shoulderpat":"* %USERNAME% comfortingly pats you on the shoulder. *", + "circle":"* %USERNAME% excitedly runs circles around you causing your head to spin. *", + "glomp":"* All of a sudden %USERNAME% tackles you and starts to hug you very tightly! You squeak in surprise! *", + "beam":"* %USERNAME% produces one of the biggest, happiest faces you've ever seen towards you!!! Wow, you must have made them happy. *", + "handshake":"* %USERNAME% shakes hands with you enthusiastically. *", + "rofl":"* You were so funny that %USERNAME% is rolling on the floor from laughing so hard!! *", + "spin":"* %USERNAME% playfully spins you in circles. You are getting quite dizzy. *", + "sing":"* %USERNAME% sings you a silly song. You burst out laughing. *", + "flail":"* You must have done something exciting, because %USERNAME% is flailing at you wildly! *" + }, + "unfriendly":{ + "frown":"* Upon your behavior, %USERNAME% frowns deeply. *", + "poke":"* %USERNAME% has poked you right in the ribs! *", + "ignore":"* %USERNAME% sticks their nose in the air ignoring your childish behavior! *", + "growl":"* You are frightened by a deep growl! It's directed at you from %USERNAME%! *", + "point":"* %USERNAME% points jokingly at you! *", + "burp":"* Buuurrrp! You can't believe %USERNAME% just did that towards you! *", + "cry":"* %USERNAME% is crying like a little baby because of you now! *", + "yell":"* %USERNAME% is yelling at you! You must have done something wrong. *", + "nudge":"* %USERNAME% gives you a careful nudge out of the way. *", + "yawn":"* YYYAAAWWWNN... you are boring %USERNAME%! *", + "tease":"* %USERNAME% laughingly teases you about your silly shoes. *", + "quack":"* %USERNAME% makes weird animal noises at you. Was that a duck? *", + "snore":"* ZZzzzzz.... You have bored %USERNAME% to the point of SNORING!! Ooops! *", + "scream":"* AAAAAAAAAAAAAHHH!!!! %USERNAME% screams loudly at you.. . overreacting a bit!? *", + "hide":"* %USERNAME% quickly hides in the shadows, hoping you do not see them. . . *", + "trip":"* You tripped over %USERNAME%'s giant hobbitty feet!! Poor you! *", + "roar":"* From the bottom of %USERNAME%'s being they release the loudest roar possible towards you!. . Only. . on its way out, their voice squeaks a little, and that takes away from the intimidation. . . *", + "boo":"* BOOOOOOOO! %USERNAME% frightens you really bad! You did not see that coming! *" + }, + "horse":{ + "wink":"* %USERNAME%'s horse winks at you! *", + "neigh":"* %USERNAME%'s horse neighs loudly at you. *", + "whinny":"* %USERNAME%'s horse whinnies softly and happily towards you. *", + "snort":" * %USERNAME%'s horse rudely snorts towards you! *", + "buck":"* %USERNAME%'s horse bucks lightly. Must have been excited to see you. *" + } + } + }, "chat":{ "for_others":{ "global_format":"%USERNAME%: %MESSAGE%", @@ -37,8 +154,11 @@ "admin_format":"%USERNAME%: %MESSAGE%", "ads_format":"%USERNAME%: %MESSAGE%", "friend_format":"%USERNAME%: %MESSAGE%", + "here_format":"%USERNAME%: %MESSAGE%", + "near_format":"%USERNAME%: %MESSAGE%", + "isle_format":"%USERNAME%: %MESSAGE%", "dm_format":"%USERNAME%: %MESSAGE%", - "dm_format)moderator":"%USERNAME%[mod: %MESSAGE%" + "dm_format_moderator":"%USERNAME%[mod: %MESSAGE%" }, "for_sender":{ @@ -88,13 +208,16 @@ {"word":"my phone","reason_type":"personal_info","match_all":true}, {"word":"phone number","reason_type":"personal_info","match_all":true}, {"word":"home address","reason_type":"personal_info","match_all":true}, + {"word":"http","reason_type":"personal_info","match_all":true}, {"word":"40lb","reason_type":"personal_info","match_all":true} ], "correct":[ {"word":"lol","new_word":"*laughing out loud!*"}, {"word":"lmao","new_word":"*laughing my horse's rump off*"}, {"word":"lmfao","new_word":"*laughing my horse's rump off*"}, + {"word":"rofl","new_word":"*rolling on floor laughing*"}, {"word":"ppp","new_word":"*petting a pretty pony*"}, + {"word":"wtf","new_word":"what the horse poo!"}, {"word":"asl","new_word":"how are you"}, {"word":"omg","new_word":"oh my gosh"}, {"word":"god","new_word":"unicorns"}, @@ -112,11 +235,13 @@ {"name":"personal_info","message":"No giving out personal info/websites."} ], "violation_points_required":10, - "violation_format":"Your last chat was flagged as a possible violation of chat rules to be reviewed by an admin. If it is severe or you have many violations your account may be suspended. We require at least %AMOUNT% violation points before examining an account, so if it was a simple misspelling do not worry. Remember this is a family friendly game! Thanks for keeping it as such! (REASON: %REASON%)" + "violation_format":"Your last chat was flagged as a possible violation of chat rules to be reviewed by an admin. If it is severe or you have many violations your account may be suspended. We require at least %AMOUNT% violation points before examining an account, so if it was a simple misspelling do not worry. Remember this is a family friendly game! Thanks for keeping it as such! (REASON: %REASON%)", + "password_included":"Your Password was included in the chat you attempted to send! DO NOT Give ANYONE your password! If someone was asking for your password, please report them immediately!", + "caps_notice":"Please do not use all CAPS, it looks as if you are yelling." } }, "mod_splatterball_game":{ - "hit_message":"SMACK!! %USERNAME% hit you with a Mod Splatterball, slimy goop exploded and dripped on you.", + "hit_message":"SMACK!! %USERNAME% hit you with a Mod Splatterball, slimy goop exploded and dripped on you." }, "water_balloon_game":{ "money_prize":20000, diff --git a/DataCollection/notes.txt b/DataCollection/notes.txt index 0070e7c..ad74d81 100644 --- a/DataCollection/notes.txt +++ b/DataCollection/notes.txt @@ -25,4 +25,12 @@ Not implemented: "hit_message":"SMACK!! %USERNAME% hit you with a Water Balloon, soaking you.", "winner_message":"You are a Water Balloon winner! Prize: $%PRIZE%", "end_message_winner":"WATER BALLOON FIGHT OVER: Here were the winners:
%USERNAME% was hit %AMOUNT% times." - }, \ No newline at end of file + }, + + mod_format FOR SENDER is unconfirmed + mod_format is unconfirmed + admin_format is unconfirmed + admin_format FOR SENDER is unconfirmed. + + +Near radius is a square, 15x19 \ No newline at end of file diff --git a/Horse Isle Server/Horse Isle Server/Chat.cs b/Horse Isle Server/Horse Isle Server/Chat.cs index 5fe6f6d..2439a52 100644 --- a/Horse Isle Server/Horse Isle Server/Chat.cs +++ b/Horse Isle Server/Horse Isle Server/Chat.cs @@ -78,7 +78,7 @@ namespace Horse_Isle_Server } else { - if (message.ToLower().Contains(filter.FilteredWord.ToLower())) + if (message.ToLower().Contains(filter.FilteredWord)) return filter.Reason; } } @@ -106,7 +106,21 @@ namespace Horse_Isle_Server } } - public static Client[] GetRecipiants(User user, ChatChannel channel) + + public static string GetDmRecipiant(string message) + { + if(message.Contains('|')) + { + string recipiantName = message.Split('|')[0]; + return recipiantName.Substring(2); + } + else + { + return null; + } + } + + public static Client[] GetRecipiants(User user, ChatChannel channel, string to=null) { if (channel == ChatChannel.All) { @@ -187,6 +201,27 @@ namespace Horse_Isle_Server return recipiants.ToArray(); } + if(channel == ChatChannel.Dm) + { + if (to != null) + { + List recipiants = new List(); + foreach (Client client in Server.ConnectedClients) + { + if (client.LoggedIn) + if (!client.LoggedinUser.MutePrivateMessage) + if (client.LoggedinUser.Username != to) + recipiants.Add(client); + } + return recipiants.ToArray(); + } + else + { + Logger.ErrorPrint("Channel is " + channel + " (DM) BUT no 'to' Paramater was specfied"); + return new Client[0]; + } + } + Logger.ErrorPrint(user.Username + " Sent message in unknown channel: " + (byte)channel); return new Client[0]; // No recipiants @@ -241,7 +276,6 @@ namespace Horse_Isle_Server return "not implemented yet :("; } } - public static string FormatChatForSender(User user, ChatChannel channel, string message) { switch (channel) @@ -264,6 +298,32 @@ namespace Horse_Isle_Server return "not implemented yet :("; } } + + public static string NonViolationChecks(User user, string message) + { + + // Check if contains password. + if (message.ToLower().Contains(user.Password.ToLower())) + { + return Messages.PasswordNotice; + } + + + // Check if ALL CAPS + if (message.Contains(' ')) // hi1 apparently doesnt care about caps if its all 1 word? + { + string[] wordsSaid = message.Split(' '); + foreach (string word in wordsSaid) + { + if (word.ToUpper() == word) + { + return Messages.CapsNotice; + } + } + } + + return null; + } public static Reason GetReason(string name) { foreach (Reason reason in Reasons) diff --git a/Horse Isle Server/Horse Isle Server/Client.cs b/Horse Isle Server/Horse Isle Server/Client.cs index 48eb4a1..ba1adb6 100644 --- a/Horse Isle Server/Horse Isle Server/Client.cs +++ b/Horse Isle Server/Horse Isle Server/Client.cs @@ -14,22 +14,52 @@ namespace Horse_Isle_Server public User LoggedinUser; private Thread recvPackets; + private Timer updateTimer; + private Timer inactivityTimer; + private Timer warnTimer; + private Timer kickTimer; + + + private int keepAliveInterval = 60 * 1000; private int updateInterval = 60 * 1000; + + private int warnInterval = Server.IdleWarning * 60 * 1000; + private int kickInterval = Server.IdleTimeout * 60 * 1000; + + + private void keepAliveTimerTick(object state) + { + Logger.DebugPrint("Sending keep-alive packet to "+ LoggedinUser.Username); + byte[] updatePacket = PacketBuilder.CreateKeepAlive(); + SendPacket(updatePacket); + } + + private void warnTimerTick(object state) + { + Logger.DebugPrint("Sending inactivity warning to: " + RemoteIp); + byte[] chatPacket = PacketBuilder.CreateChat(Messages.FormatIdleWarningMessage(), PacketBuilder.CHAT_BOTTOM_RIGHT); + SendPacket(chatPacket); + } + + private void kickTimerTick(object state) + { + Kick(Messages.FormatIdleKickMessage()); + } private void updateTimerTick(object state) { - Logger.DebugPrint("Sending update packet to "+ LoggedinUser.Username); - byte[] updatePacket = PacketBuilder.CreateUpdate(); - SendPacket(updatePacket); + Server.UpdateArea(this); + Server.UpdateWorld(this); + Server.UpdatePlayer(this); } public void Login(int id) { LoggedinUser = new User(id); LoggedIn = true; - updateTimer = new Timer(new TimerCallback(updateTimerTick), null, updateInterval, updateInterval); + inactivityTimer = new Timer(new TimerCallback(keepAliveTimerTick), null, keepAliveInterval, keepAliveInterval); } private void receivePackets() { @@ -54,6 +84,7 @@ namespace Horse_Isle_Server ms.Seek(0x00, SeekOrigin.Begin); byte[] fullPacket = ms.ToArray(); parsePackets(fullPacket); + ms.Close(); ms = new MemoryStream(); } @@ -63,7 +94,7 @@ namespace Horse_Isle_Server } catch(SocketException e) { - Logger.ErrorPrint("Socket exception occured: " + e.Message +" and so it was disconnected."); + Logger.ErrorPrint("Socket exception occured: " + e.Message); Disconnect(); break; } @@ -81,8 +112,16 @@ namespace Horse_Isle_Server } byte identifier = Packet[0]; - if (updateTimer != null) - updateTimer.Change(updateInterval, updateInterval); + // Reset timers + if (inactivityTimer != null && identifier != PacketBuilder.PACKET_KEEP_ALIVE) + inactivityTimer.Change(keepAliveInterval, keepAliveInterval); + + + if (kickTimer != null && identifier != PacketBuilder.PACKET_KEEP_ALIVE) + kickTimer.Change(kickInterval, kickInterval); + + if (warnTimer != null && identifier != PacketBuilder.PACKET_KEEP_ALIVE) + warnTimer.Change(warnInterval, warnInterval); if (!LoggedIn) // Must be either login or policy-file-request { @@ -113,8 +152,8 @@ namespace Horse_Isle_Server case PacketBuilder.PACKET_CHAT: Server.OnChatPacket(this, Packet); break; - case PacketBuilder.PACKET_UPDATE: - Server.OnUpdatePacket(this, Packet); + case PacketBuilder.PACKET_KEEP_ALIVE: + Server.OnKeepAlive(this, Packet); break; default: Logger.ErrorPrint("Unimplemented Packet: " + BitConverter.ToString(Packet).Replace('-', ' ')); @@ -127,14 +166,31 @@ namespace Horse_Isle_Server { Logger.DebugPrint(ClientSocket.RemoteEndPoint + " has Disconnected."); recvPackets.Abort(); - updateTimer.Dispose(); + if(updateTimer != null) + updateTimer.Dispose(); + if(inactivityTimer != null) + inactivityTimer.Dispose(); + if(warnTimer != null) + warnTimer.Dispose(); + if(kickTimer != null) + kickTimer.Dispose(); + + Server.OnDisconnect(this); LoggedIn = false; LoggedinUser = null; - Server.ConnectedClients.Remove(this); ClientSocket.Close(); ClientSocket.Dispose(); } + public void Kick(string Reason) + { + byte[] kickPacket = PacketBuilder.CreateKickMessage(Reason); + SendPacket(kickPacket); + Disconnect(); + + Logger.InfoPrint("CLIENT: "+RemoteIp+" KICKED for: "+Reason); + } + public void SendPacket(byte[] PacketData) { try @@ -143,7 +199,7 @@ namespace Horse_Isle_Server } catch (SocketException e) { - Logger.ErrorPrint("Socket exception occured: " + e.Message + " and so it was disconnected."); + Logger.ErrorPrint("Socket exception occured: " + e.Message); Disconnect(); } } @@ -155,6 +211,9 @@ namespace Horse_Isle_Server Logger.DebugPrint("Client connected @ " + RemoteIp); + kickTimer = new Timer(new TimerCallback(kickTimerTick), null, kickInterval, kickInterval); + warnTimer = new Timer(new TimerCallback(warnTimerTick), null, warnInterval, warnInterval); + recvPackets = new Thread(() => { receivePackets(); diff --git a/Horse Isle Server/Horse Isle Server/Database.cs b/Horse Isle Server/Horse Isle Server/Database.cs index cbe9db1..5362e94 100644 --- a/Horse Isle Server/Horse Isle Server/Database.cs +++ b/Horse Isle Server/Horse Isle Server/Database.cs @@ -17,7 +17,7 @@ namespace Horse_Isle_Server string ExtTable = "CREATE TABLE UserExt(Id INT, X INT, Y INT, Money INT, BankBalance BIGINT,ProfilePage Text(1028), CharId INT, ChatViolations INT)"; string MailTable = "CREATE TABLE Mailbox(IdTo INT, PlayerFrom TEXT(16),Subject TEXT(128), Message Text(1028), TimeSent INT)"; string BuddyTable = "CREATE TABLE BuddyList(Id INT, IdFriend INT, Pending BOOL)"; - string WorldTable = "CREATE TABLE World(TimeStarted INT, Weather TEXT(64))"; + string WorldTable = "CREATE TABLE World(Time INT,Day INT, Year INT, Weather TEXT(64))"; string DroppedTable = "CREATE TABLE DroppedItems(X INT, Y INT, ItemID INT)"; try @@ -87,11 +87,9 @@ namespace Horse_Isle_Server sqlCommand.ExecuteNonQuery(); - int epoch = (int)(DateTime.UtcNow - new DateTime(1970, 1, 1)).TotalSeconds; sqlCommand = db.CreateCommand(); - sqlCommand.CommandText = "INSERT INTO World VALUES(@unix,'SUNNY')"; - sqlCommand.Parameters.AddWithValue("@unix", epoch); + sqlCommand.CommandText = "INSERT INTO World VALUES(0,0,0,'SUNNY')"; sqlCommand.Prepare(); sqlCommand.ExecuteNonQuery(); @@ -103,14 +101,40 @@ namespace Horse_Isle_Server } - public static int GetServerCreationTime() + public static void SetServerTime(int time, int day, int year) { MySqlCommand sqlCommand = db.CreateCommand(); - sqlCommand.CommandText = "SELECT TimeStarted FROM World"; + sqlCommand.CommandText = "UPDATE World SET Time=@time,Day=@day,Year=@year"; + sqlCommand.Parameters.AddWithValue("@time", time); + sqlCommand.Parameters.AddWithValue("@day", day); + sqlCommand.Parameters.AddWithValue("@year", year); + sqlCommand.Prepare(); + sqlCommand.ExecuteNonQuery(); + } + + public static int GetServerTime() + { + MySqlCommand sqlCommand = db.CreateCommand(); + sqlCommand.CommandText = "SELECT Time FROM World"; + int serverTime = Convert.ToInt32(sqlCommand.ExecuteScalar()); + return serverTime; + } + + public static int GetServerDay() + { + MySqlCommand sqlCommand = db.CreateCommand(); + sqlCommand.CommandText = "SELECT Day FROM World"; + int serverTime = Convert.ToInt32(sqlCommand.ExecuteScalar()); + return serverTime; + } + + public static int GetServerYear() + { + MySqlCommand sqlCommand = db.CreateCommand(); + sqlCommand.CommandText = "SELECT Year FROM World"; int creationTime = Convert.ToInt32(sqlCommand.ExecuteScalar()); return creationTime; } - public static string GetWorldWeather() { MySqlCommand sqlCommand = db.CreateCommand(); diff --git a/Horse Isle Server/Horse Isle Server/Gamedata.cs b/Horse Isle Server/Horse Isle Server/Gamedata.cs index 32cd91f..6447dc7 100644 --- a/Horse Isle Server/Horse Isle Server/Gamedata.cs +++ b/Horse Isle Server/Horse Isle Server/Gamedata.cs @@ -117,9 +117,11 @@ namespace Horse_Isle_Server // Announcements - Messages.LoginFormat = gameData.messages.login_format; + Messages.WelcomeFormat = gameData.messages.welcome_format; Messages.MotdFormat = gameData.messages.motd_format; Messages.ProfileSavedMessage = gameData.messages.profile_save; + Messages.LoginMessageForamt = gameData.messages.login_format; + Messages.LogoutMessageFormat = gameData.messages.logout_format; // Chat @@ -144,6 +146,9 @@ namespace Horse_Isle_Server Messages.ModChatFormatForSender = gameData.messages.chat.for_sender.mod_format; Messages.AdminChatFormatForSender = gameData.messages.chat.for_sender.admin_format; + Messages.PasswordNotice = gameData.messages.chat.password_included; + Messages.CapsNotice = gameData.messages.chat.caps_notice; + // Meta Format Messages.LocationFormat = gameData.messages.meta.location_format; @@ -159,6 +164,17 @@ namespace Horse_Isle_Server Map.OverlayTileDepth = gameData.tile_paramaters.overlay_tiles.tile_depth.ToObject(); Map.OverlayTilesetPassibility = gameData.tile_paramaters.overlay_tiles.passibility.ToObject(); Map.TerrainTilePassibility = gameData.tile_paramaters.terrain_tiles.passibility.ToObject(); + + // Disconnect Reasons + + Messages.BanMessage = gameData.messages.disconnect.banned; + Messages.IdleKickMessageFormat = gameData.messages.disconnect.client_timeout.kick_message; + Messages.IdleWarningFormat = gameData.messages.disconnect.client_timeout.warn_message; + + + Server.IdleWarning = gameData.messages.disconnect.client_timeout.warn_after; + Server.IdleTimeout = gameData.messages.disconnect.client_timeout.kick_after; + } } diff --git a/Horse Isle Server/Horse Isle Server/Logger.cs b/Horse Isle Server/Horse Isle Server/Logger.cs index ef8f0f3..531b867 100644 --- a/Horse Isle Server/Horse Isle Server/Logger.cs +++ b/Horse Isle Server/Horse Isle Server/Logger.cs @@ -21,5 +21,9 @@ namespace Horse_Isle_Server { Console.WriteLine("[ERROR] " + text); } + public static void InfoPrint(string text) + { + Console.WriteLine("[INFO] " + text); + } } } diff --git a/Horse Isle Server/Horse Isle Server/Messages.cs b/Horse Isle Server/Horse Isle Server/Messages.cs index b1e49ad..b71fefa 100644 --- a/Horse Isle Server/Horse Isle Server/Messages.cs +++ b/Horse Isle Server/Horse Isle Server/Messages.cs @@ -10,9 +10,11 @@ namespace Horse_Isle_Server { // Announcements public static string NewUserMessage; - public static string LoginFormat; + public static string WelcomeFormat; public static string MotdFormat; - + public static string IdleWarningFormat; + public static string LoginMessageForamt; + public static string LogoutMessageFormat; // Records public static string ProfileSavedMessage; @@ -38,6 +40,8 @@ namespace Horse_Isle_Server public static string ChatViolationMessageFormat; public static int RequiredChatViolations; + public static string PasswordNotice; + public static string CapsNotice; // Meta public static string IsleFormat; @@ -49,6 +53,10 @@ namespace Horse_Isle_Server public static string NothingMessage; public static string Seperator; + // Disconnect Messages + public static string BanMessage; + public static string IdleKickMessageFormat; + public static string FormatGlobalChatViolationMessage(Chat.Reason violationReason) { return ChatViolationMessageFormat.Replace("%AMOUNT%", RequiredChatViolations.ToString()).Replace("%REASON%", violationReason.Message); @@ -114,25 +122,36 @@ namespace Horse_Isle_Server { return DirectChatFormatForSender.Replace("%FROMUSER%", username).Replace("%TOUSER%", toUsername).Replace(" %MESSAGE%", message); } + public static string FormatIdleWarningMessage() + { + return IdleWarningFormat.Replace("%WARN%", Server.IdleWarning.ToString()).Replace("%KICK%", Server.IdleTimeout.ToString()); + } + public static string FormatLoginMessage(string username) + { + return LoginMessageForamt.Replace("%USERNAME%", username); + } - - - - - + public static string FormatLogoutMessage(string username) + { + return LogoutMessageFormat.Replace("%USERNAME%", username); + } public static string FormatMOTD() { return MotdFormat.Replace("%MOTD%", ConfigReader.Motd); } - public static string FormatLoginMessage(string username) + public static string FormatWelcomeMessage(string username) { - return LoginFormat.Replace("%USERNAME%", username); + return WelcomeFormat.Replace("%USERNAME%", username); } - - + // Disconnect + public static string FormatIdleKickMessage() + { + return IdleKickMessageFormat.Replace("%KICK%", Server.IdleTimeout.ToString()); + } + // Meta public static string FormatLocationData(int x, int y) { string locationString = ""; diff --git a/Horse Isle Server/Horse Isle Server/PacketBuilder.cs b/Horse Isle Server/Horse Isle Server/PacketBuilder.cs index 41d2fb8..bfea041 100644 --- a/Horse Isle Server/Horse Isle Server/PacketBuilder.cs +++ b/Horse Isle Server/Horse Isle Server/PacketBuilder.cs @@ -8,7 +8,7 @@ namespace Horse_Isle_Server { public const byte PACKET_TERMINATOR = 0x00; - public const byte PACKET_A_TERMINATOR = 0x0A; + public const byte PACKET_CLIENT_TERMINATOR = 0x0A; public const byte PACKET_LOGIN = 0x7F; @@ -21,8 +21,15 @@ namespace Horse_Isle_Server public const byte PACKET_AREA_DEFS = 0x79; public const byte PACKET_ANNOUNCEMENT = 0x7E; public const byte PACKET_TILE_FLAGS = 0x75; - public const byte PACKET_UPDATE = 0x7C; + public const byte PACKET_KEEP_ALIVE = 0x7C; public const byte PACKET_PROFILE = 0x18; + public const byte PACKET_KICK = 0x80; + public const byte PACKET_LEAVE = 0x7D; + + public const byte PACKET_PLAYERINFO = 0x16; + + public const byte PLAYERINFO_LEAVE = 0x16; + public const byte PLAYERINFO_UPDATE_OR_CREATE = 0x15; public const byte VIEW_PROFILE = 0x14; public const byte SAVE_PROFILE = 0x15; @@ -49,10 +56,58 @@ namespace Horse_Isle_Server public const byte DIRECTION_RIGHT = 1; public const byte DIRECTION_DOWN = 2; public const byte DIRECTION_LEFT = 3; - public const byte DIRECTION_LOGIN = 4; + public const byte DIRECTION_TELEPORT = 4; public const byte DIRECTION_NONE = 10; + public static byte[] CreatePlayerLeavePacket(string username) + { + MemoryStream ms = new MemoryStream(); + + ms.WriteByte(PACKET_PLAYERINFO); + ms.WriteByte(PLAYERINFO_LEAVE); + + byte[] strBytes = Encoding.UTF8.GetBytes(username); + ms.Write(strBytes, 0x00, strBytes.Length); + + ms.WriteByte(PACKET_TERMINATOR); + + ms.Seek(0x00, SeekOrigin.Begin); + byte[] Packet = ms.ToArray(); + ms.Dispose(); + + return Packet; + } + public static byte[] CreatePlayerInfoUpdateOrCreate(int x, int y, int facing, int charId, string username) + { + MemoryStream ms = new MemoryStream(); + + ms.WriteByte(PACKET_PLAYERINFO); + ms.WriteByte(PLAYERINFO_UPDATE_OR_CREATE); + + ms.WriteByte((byte)(((x - 4) / 64) + 20)); + ms.WriteByte((byte)(((x - 4) % 64) + 20)); + + ms.WriteByte((byte)(((y - 1) / 64) + 20)); + ms.WriteByte((byte)(((y - 1) % 64) + 20)); + + ms.WriteByte((byte)(facing + 20)); + + ms.WriteByte((byte)((charId / 64) + 20)); //6 + ms.WriteByte((byte)((charId % 64) + 20)); //7 + + + byte[] strBytes = Encoding.UTF8.GetBytes(username); + ms.Write(strBytes, 0x00, strBytes.Length); + + ms.WriteByte(PACKET_TERMINATOR); + + ms.Seek(0x00, SeekOrigin.Begin); + byte[] Packet = ms.ToArray(); + ms.Dispose(); + + return Packet; + } public static byte[] CreateLoginPacket(bool Success) { @@ -215,7 +270,7 @@ namespace Horse_Isle_Server ms.WriteByte((byte)otileId); } } - if (direction == DIRECTION_LOGIN) + if (direction == DIRECTION_TELEPORT) { for(int rely = 0; rely <= 9; rely++) { @@ -262,7 +317,7 @@ namespace Horse_Isle_Server ms.WriteByte(PACKET_PLACE_INFO); ms.Write(strBytes, 0x00, strBytes.Length); - + ms.WriteByte(PACKET_TERMINATOR); ms.Seek(0x00, SeekOrigin.Begin); @@ -317,11 +372,11 @@ namespace Horse_Isle_Server return Packet; } - public static byte[] CreateUpdate() + public static byte[] CreateKeepAlive() { MemoryStream ms = new MemoryStream(); - ms.WriteByte(PACKET_UPDATE); + ms.WriteByte(PACKET_KEEP_ALIVE); ms.WriteByte(PACKET_TERMINATOR); ms.Seek(0x00, SeekOrigin.Begin); @@ -419,7 +474,7 @@ namespace Horse_Isle_Server return Packet; } - public static byte[] CreateBaseStats(int money, int playerCount, int mail) + public static byte[] CreatePlayerData(int money, int playerCount, int mail) { byte[] moneyStrBytes = Encoding.UTF8.GetBytes(money.ToString()); byte[] playerStrBytes = Encoding.UTF8.GetBytes(playerCount.ToString()); @@ -460,6 +515,7 @@ namespace Horse_Isle_Server return Packet; } + public static byte[] CreateSecCode(byte[] SecCodeSeed, int SecCodeInc, bool Admin, bool Moderator) { MemoryStream ms = new MemoryStream(); @@ -500,6 +556,21 @@ namespace Horse_Isle_Server return Packet; } + public static byte[] CreateKickMessage(string reason) + { + MemoryStream ms = new MemoryStream(); + ms.WriteByte(PACKET_KICK); + byte[] strBytes = Encoding.UTF8.GetBytes(reason); + ms.Write(strBytes, 0x00, strBytes.Length); + ms.WriteByte(PACKET_TERMINATOR); + + ms.Seek(0x00, SeekOrigin.Begin); + byte[] Packet = ms.ToArray(); + ms.Dispose(); + + return Packet; + } + public static byte[] CreateAreaMessage(int x, int y) { string locationStr = Messages.FormatLocationData(x, y); @@ -510,7 +581,7 @@ namespace Horse_Isle_Server string formattedMotd = Messages.FormatMOTD(); return CreateAnnouncement(formattedMotd); } - public static byte[] CreateLoginMessage(string username) + public static byte[] CreateWelcomeMessage(string username) { string formattedStr = Messages.FormatLoginMessage(username); return CreateChat(formattedStr, CHAT_BOTTOM_RIGHT); diff --git a/Horse Isle Server/Horse Isle Server/Program.cs b/Horse Isle Server/Horse Isle Server/Program.cs index 304e12a..9cb0862 100644 --- a/Horse Isle Server/Horse Isle Server/Program.cs +++ b/Horse Isle Server/Horse Isle Server/Program.cs @@ -17,6 +17,7 @@ namespace Horse_Isle_Server Database.OpenDatabase(); Map.OpenMap(); Gamedata.ReadGamedata(); + World.ReadWorldData(); Server.StartServer(); } diff --git a/Horse Isle Server/Horse Isle Server/Server.cs b/Horse Isle Server/Horse Isle Server/Server.cs index b0ae606..661096d 100644 --- a/Horse Isle Server/Horse Isle Server/Server.cs +++ b/Horse Isle Server/Horse Isle Server/Server.cs @@ -5,6 +5,7 @@ using System.Linq; using System.Net; using System.Net.Sockets; using System.Text; +using System.Threading; using System.Threading.Tasks; namespace Horse_Isle_Server @@ -13,8 +14,25 @@ namespace Horse_Isle_Server { public static Socket ServerSocket; - public static List ConnectedClients = new List(); + + public static Client[] ConnectedClients // Done to prevent Enumerator Changed errors. + { + get { + return connectedClients.ToArray(); + } + } + + public static int IdleTimeout; + public static int IdleWarning; + + + + // used for world time, + private static int gameTickSpeed = 4320; // Changing this to ANYTHING else will cause desync with the client. + private static Timer serverTimer; + + private static List connectedClients = new List(); public static void OnCrossdomainPolicyRequest(Client sender) // When a cross-domain-policy request is received. { Logger.DebugPrint("Cross-Domain-Policy request received from: " + sender.RemoteIp); @@ -35,28 +53,36 @@ namespace Horse_Isle_Server User user = sender.LoggedinUser; - byte[] MovementPacket = PacketBuilder.CreateMovementPacket(user.X, user.Y, user.CharacterId, PacketBuilder.DIRECTION_DOWN, PacketBuilder.DIRECTION_LOGIN, true); + byte[] MovementPacket = PacketBuilder.CreateMovementPacket(user.X, user.Y, user.CharacterId, user.Facing, PacketBuilder.DIRECTION_TELEPORT, true); sender.SendPacket(MovementPacket); - byte[] LoginMessage = PacketBuilder.CreateLoginMessage(user.Username); - sender.SendPacket(LoginMessage); + byte[] WelcomeMessage = PacketBuilder.CreateWelcomeMessage(user.Username); + sender.SendPacket(WelcomeMessage); - World.Time time = World.GetGameTime(); - int timestamp = time.hours * 60; - timestamp += time.minutes; - - byte[] WorldData = PacketBuilder.CreateWorldData(timestamp, time.days, time.year, World.GetWeather()); + byte[] WorldData = PacketBuilder.CreateWorldData(World.ServerTime.Minutes, World.ServerTime.Days, World.ServerTime.Years, World.GetWeather()); sender.SendPacket(WorldData); byte[] SecCodePacket = PacketBuilder.CreateSecCode(user.SecCodeSeeds, user.SecCodeInc, user.Administrator, user.Moderator); sender.SendPacket(SecCodePacket); - byte[] BaseStatsPacketData = PacketBuilder.CreateBaseStats(user.Money, Server.GetNumberOfPlayers(), user.MailBox.MailCount); + byte[] BaseStatsPacketData = PacketBuilder.CreatePlayerData(user.Money, Server.GetNumberOfPlayers(), user.MailBox.MailCount); sender.SendPacket(BaseStatsPacketData); byte[] AreaMessage = PacketBuilder.CreateAreaMessage(user.X, user.Y); sender.SendPacket(AreaMessage); + foreach(Client client in ConnectedClients) + { + if (client.LoggedIn) + { + if(client.LoggedinUser.Id != user.Id) + { + byte[] PlayerInfo = PacketBuilder.CreatePlayerInfoUpdateOrCreate(client.LoggedinUser.X, client.LoggedinUser.Y, client.LoggedinUser.Facing, client.LoggedinUser.CharacterId, client.LoggedinUser.Username); + sender.SendPacket(PlayerInfo); + } + } + } + byte[] IsleData = PacketBuilder.CreatePlaceData(World.Isles.ToArray(), World.Towns.ToArray(), World.Areas.ToArray()); sender.SendPacket(IsleData); @@ -68,24 +94,24 @@ namespace Horse_Isle_Server } - public static void OnUpdatePacket(Client sender, byte[] packet) + + public static void OnKeepAlive(Client sender, byte[] packet) { if (!sender.LoggedIn) { - Logger.ErrorPrint(sender.RemoteIp + " Requested user information when not logged in."); + Logger.ErrorPrint(sender.RemoteIp + " Requested update when not logged in."); return; } if (packet.Length < 2) { - Logger.ErrorPrint(sender.LoggedinUser.Username + " Sent an invalid Update Packet"); + Logger.ErrorPrint(sender.LoggedinUser.Username + " Sent an invalid update Packet"); return; } - if(packet[1] == PacketBuilder.PACKET_A_TERMINATOR) + if(packet[1] == PacketBuilder.PACKET_CLIENT_TERMINATOR) { - Logger.DebugPrint(sender.LoggedinUser.Username + " Requested latest statistics (Money/Playercount/Mail)"); - byte[] packetResponse = PacketBuilder.CreateBaseStats(sender.LoggedinUser.Money, GetNumberOfPlayers(), sender.LoggedinUser.MailBox.MailCount); - sender.SendPacket(packetResponse); + Logger.DebugPrint("Sending "+ sender.LoggedinUser.Username +" updated info..."); + UpdatePlayer(sender); } } public static void OnProfilePacket(Client sender, byte[] packet) @@ -131,6 +157,7 @@ namespace Horse_Isle_Server sender.SendPacket(chatPacket); UpdateArea(sender); + UpdateUserInfo(sender.LoggedinUser); } } @@ -148,64 +175,70 @@ namespace Horse_Isle_Server if(movementDirection == PacketBuilder.MOVE_UP) { + loggedInUser.Facing = PacketBuilder.DIRECTION_UP; if (Map.CheckPassable(loggedInUser.X, loggedInUser.Y - 1)) { loggedInUser.Y -= 1; - byte[] moveUpResponse = PacketBuilder.CreateMovementPacket(loggedInUser.X, loggedInUser.Y, loggedInUser.CharacterId, PacketBuilder.DIRECTION_UP, PacketBuilder.DIRECTION_UP, true); + + byte[] moveUpResponse = PacketBuilder.CreateMovementPacket(loggedInUser.X, loggedInUser.Y, loggedInUser.CharacterId, sender.LoggedinUser.Facing, PacketBuilder.DIRECTION_UP, true); sender.SendPacket(moveUpResponse); } else { - byte[] moveUpResponse = PacketBuilder.CreateMovementPacket(loggedInUser.X, loggedInUser.Y, loggedInUser.CharacterId, PacketBuilder.DIRECTION_UP, PacketBuilder.DIRECTION_NONE, false); + byte[] moveUpResponse = PacketBuilder.CreateMovementPacket(loggedInUser.X, loggedInUser.Y, loggedInUser.CharacterId, sender.LoggedinUser.Facing, PacketBuilder.DIRECTION_NONE, false); sender.SendPacket(moveUpResponse); } } else if(movementDirection == PacketBuilder.MOVE_LEFT) { + loggedInUser.Facing = PacketBuilder.DIRECTION_LEFT; if (Map.CheckPassable(loggedInUser.X - 1, loggedInUser.Y)) { loggedInUser.X -= 1; - byte[] moveLeftResponse = PacketBuilder.CreateMovementPacket(loggedInUser.X, loggedInUser.Y, loggedInUser.CharacterId, PacketBuilder.DIRECTION_LEFT, PacketBuilder.DIRECTION_LEFT, true); + byte[] moveLeftResponse = PacketBuilder.CreateMovementPacket(loggedInUser.X, loggedInUser.Y, loggedInUser.CharacterId, loggedInUser.Facing, PacketBuilder.DIRECTION_LEFT, true); sender.SendPacket(moveLeftResponse); } else { - byte[] moveLeftResponse = PacketBuilder.CreateMovementPacket(loggedInUser.X, loggedInUser.Y, loggedInUser.CharacterId, PacketBuilder.DIRECTION_LEFT, PacketBuilder.DIRECTION_NONE, false); + byte[] moveLeftResponse = PacketBuilder.CreateMovementPacket(loggedInUser.X, loggedInUser.Y, loggedInUser.CharacterId, loggedInUser.Facing, PacketBuilder.DIRECTION_NONE, false); sender.SendPacket(moveLeftResponse); } } else if(movementDirection == PacketBuilder.MOVE_RIGHT) { + loggedInUser.Facing = PacketBuilder.DIRECTION_RIGHT; if (Map.CheckPassable(loggedInUser.X + 1, loggedInUser.Y)) { loggedInUser.X += 1; - byte[] moveLeftResponse = PacketBuilder.CreateMovementPacket(loggedInUser.X, loggedInUser.Y, loggedInUser.CharacterId, PacketBuilder.DIRECTION_RIGHT, PacketBuilder.DIRECTION_RIGHT, true); + byte[] moveLeftResponse = PacketBuilder.CreateMovementPacket(loggedInUser.X, loggedInUser.Y, loggedInUser.CharacterId, loggedInUser.Facing, PacketBuilder.DIRECTION_RIGHT, true); sender.SendPacket(moveLeftResponse); } else { - byte[] moveLeftResponse = PacketBuilder.CreateMovementPacket(loggedInUser.X, loggedInUser.Y, loggedInUser.CharacterId, PacketBuilder.DIRECTION_RIGHT, PacketBuilder.DIRECTION_NONE, false); + byte[] moveLeftResponse = PacketBuilder.CreateMovementPacket(loggedInUser.X, loggedInUser.Y, loggedInUser.CharacterId, loggedInUser.Facing, PacketBuilder.DIRECTION_NONE, false); sender.SendPacket(moveLeftResponse); } } else if(movementDirection == PacketBuilder.MOVE_DOWN) { + loggedInUser.Facing = PacketBuilder.DIRECTION_DOWN; if (Map.CheckPassable(loggedInUser.X, loggedInUser.Y + 1)) { loggedInUser.Y += 1; - byte[] moveDownResponse = PacketBuilder.CreateMovementPacket(loggedInUser.X, loggedInUser.Y, loggedInUser.CharacterId, PacketBuilder.DIRECTION_DOWN, PacketBuilder.DIRECTION_DOWN, true); + byte[] moveDownResponse = PacketBuilder.CreateMovementPacket(loggedInUser.X, loggedInUser.Y, loggedInUser.CharacterId, loggedInUser.Facing, PacketBuilder.DIRECTION_DOWN, true); sender.SendPacket(moveDownResponse); } else { - byte[] moveDownResponse = PacketBuilder.CreateMovementPacket(loggedInUser.X, loggedInUser.Y, loggedInUser.CharacterId, PacketBuilder.DIRECTION_DOWN, PacketBuilder.DIRECTION_NONE, false); + byte[] moveDownResponse = PacketBuilder.CreateMovementPacket(loggedInUser.X, loggedInUser.Y, loggedInUser.CharacterId, loggedInUser.Facing, PacketBuilder.DIRECTION_NONE, false); sender.SendPacket(moveDownResponse); } } - UpdateArea(sender); + UpdateUserInfo(sender.LoggedinUser); + UpdateArea(sender); } public static void OnChatPacket(Client sender, byte[] packet) @@ -228,11 +261,15 @@ namespace Horse_Isle_Server Chat.ChatChannel channel = (Chat.ChatChannel)packet[1]; string message = packetStr.Substring(2, packetStr.Length - 4); - Logger.DebugPrint(sender.LoggedinUser.Username + " Attempting to say '" + message + "' in channel: " + channel.ToString("X")); + Logger.DebugPrint(sender.LoggedinUser.Username + " Attempting to say '" + message + "' in channel: " + channel.ToString()); + + string nameTo = null; + if (channel == Chat.ChatChannel.Dm) + nameTo = Chat.GetDmRecipiant(message); Object violationReason = Chat.FilterMessage(message); - if (violationReason != null) // This is such a hack, but i really couldnt think of any better way to do it. + if (violationReason != null) { sender.LoggedinUser.ChatViolations += 1; string chatViolationMessage = Messages.FormatGlobalChatViolationMessage((Chat.Reason)violationReason); @@ -241,10 +278,22 @@ namespace Horse_Isle_Server return; } - Client[] recipiants = Chat.GetRecipiants(sender.LoggedinUser, channel); byte chatSide = Chat.GetSide(channel); message = Chat.DoCorrections(message); message = Chat.EscapeMessage(message); + + + string failedReason = Chat.NonViolationChecks(sender.LoggedinUser, message); + if (failedReason != null) + { + byte[] failedMessage = PacketBuilder.CreateChat(failedReason, PacketBuilder.CHAT_BOTTOM_RIGHT); + sender.SendPacket(failedMessage); + return; + } + + Client[] recipiants = Chat.GetRecipiants(sender.LoggedinUser, channel, nameTo); + + // Finally send chat message. string formattedMessage = Chat.FormatChatForOthers(sender.LoggedinUser,channel,message); string formattedMessageSender = Chat.FormatChatForSender(sender.LoggedinUser, channel, message); byte[] chatPacketOthers = PacketBuilder.CreateChat(formattedMessage, chatSide); @@ -258,6 +307,7 @@ namespace Horse_Isle_Server // Send to sender sender.SendPacket(chatPacketSender); } + public static void OnLoginRequest(Client sender, byte[] packet) { Logger.DebugPrint("Login request received from: " + sender.RemoteIp); @@ -270,7 +320,7 @@ namespace Horse_Isle_Server return; } - if(packet[1] != PacketBuilder.PACKET_A_TERMINATOR) + if(packet[1] != PacketBuilder.PACKET_CLIENT_TERMINATOR) { string[] loginParts = loginRequestString.Split('|'); if (loginParts.Length < 3) @@ -290,11 +340,23 @@ namespace Horse_Isle_Server // Obtain user information int userId = Database.GetUserid(username); sender.Login(userId); + sender.LoggedinUser.Password = password; byte[] ResponsePacket = PacketBuilder.CreateLoginPacket(true); sender.SendPacket(ResponsePacket); Logger.DebugPrint(sender.RemoteIp + " Logged into : " + sender.LoggedinUser.Username + " (ADMIN: " + sender.LoggedinUser.Administrator + " MOD: " + sender.LoggedinUser.Moderator+")"); + + // Send login message + byte[] loginMessageBytes = PacketBuilder.CreateChat(Messages.FormatLoginMessage(sender.LoggedinUser.Username), PacketBuilder.CHAT_BOTTOM_LEFT); + foreach (Client client in ConnectedClients) + if (client.LoggedIn) + if (!client.LoggedinUser.MuteLogins) + if(client.LoggedinUser.Id != userId) + client.SendPacket(loginMessageBytes); + + UpdateUserInfo(sender.LoggedinUser); + } else { @@ -306,21 +368,81 @@ namespace Horse_Isle_Server } + public static void OnDisconnect(Client sender) + { + if(sender.LoggedIn) + { + // Send disconnect message + byte[] logoutMessageBytes = PacketBuilder.CreateChat(Messages.FormatLogoutMessage(sender.LoggedinUser.Username), PacketBuilder.CHAT_BOTTOM_LEFT); + foreach (Client client in ConnectedClients) + if (client.LoggedIn) + if (!client.LoggedinUser.MuteLogins) + if (client.LoggedinUser.Id != sender.LoggedinUser.Id) + client.SendPacket(logoutMessageBytes); + // Tell clients of diconnect (remove from chat) + byte[] playerRemovePacket = PacketBuilder.CreatePlayerLeavePacket(sender.LoggedinUser.Username); + foreach (Client client in ConnectedClients) + if (client.LoggedIn) + if (client.LoggedinUser.Id != sender.LoggedinUser.Id) + client.SendPacket(playerRemovePacket); + } + + connectedClients.Remove(sender); + } + public static void UpdateArea(Client forClient) { + if (!forClient.LoggedIn) + { + Logger.ErrorPrint(forClient.RemoteIp + "tried to update tile information when not logged in."); + return; + } byte[] areaData = PacketBuilder.CreateAreaMessage(forClient.LoggedinUser.X, forClient.LoggedinUser.Y); forClient.SendPacket(areaData); } + public static void UpdateWorld(Client forClient) + { + if (!forClient.LoggedIn) + { + Logger.ErrorPrint(forClient.RemoteIp + "tried to update world information when not logged in."); + return; + } + + byte[] WorldData = PacketBuilder.CreateWorldData(World.ServerTime.Minutes, World.ServerTime.Days, World.ServerTime.Years, World.GetWeather()); + forClient.SendPacket(WorldData); + } + + public static void UpdatePlayer(Client forClient) + { + if (!forClient.LoggedIn) + { + Logger.ErrorPrint(forClient.RemoteIp + "tried to update player information when not logged in."); + return; + } + byte[] PlayerData = PacketBuilder.CreatePlayerData(forClient.LoggedinUser.Money, Server.GetNumberOfPlayers(), forClient.LoggedinUser.MailBox.MailCount); + forClient.SendPacket(PlayerData); + } + + public static void UpdateUserInfo(User user) + { + byte[] playerInfoBytes = PacketBuilder.CreatePlayerInfoUpdateOrCreate(user.X, user.Y, user.Facing, user.CharacterId, user.Username); + foreach (Client client in ConnectedClients) + if (client.LoggedIn) + if (client.LoggedinUser.Id != user.Id) + client.SendPacket(playerInfoBytes); + } + public static int GetNumberOfPlayers() { int count = 0; foreach(Client client in ConnectedClients) { if (client.LoggedIn) - count++; + if(!client.LoggedinUser.Stealth) + count++; } return count; } @@ -349,6 +471,10 @@ namespace Horse_Isle_Server return count; } + private static void onTick(object state) + { + World.TickWorldClock(); + } public static void StartServer() { ServerSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); @@ -358,13 +484,15 @@ namespace Horse_Isle_Server Logger.DebugPrint("Binding to ip: " + ConfigReader.BindIP + " On port: " + ConfigReader.Port.ToString()); ServerSocket.Listen(10000); - while(true) + serverTimer = new Timer(new TimerCallback(onTick), null, gameTickSpeed, gameTickSpeed); + + while (true) { Logger.DebugPrint("Waiting for new connections..."); Socket cientSocket = ServerSocket.Accept(); Client client = new Client(cientSocket); - ConnectedClients.Add(client); + connectedClients.Add(client); } } } diff --git a/Horse Isle Server/Horse Isle Server/User.cs b/Horse Isle Server/Horse Isle Server/User.cs index 05ba372..d588d3d 100644 --- a/Horse Isle Server/Horse Isle Server/User.cs +++ b/Horse Isle Server/Horse Isle Server/User.cs @@ -22,8 +22,12 @@ namespace Horse_Isle_Server public bool MuteSocials = false; public bool MuteLogins = false; + public bool Stealth = false; + + public int Facing; public Mailbox MailBox; public Friends Friends; + public string Password; // For chat filter. public int ChatViolations { get @@ -157,7 +161,7 @@ namespace Horse_Isle_Server Id = UserId; Username = Database.GetUsername(UserId); - + Administrator = Database.CheckUserIsAdmin(Username); Moderator = Database.CheckUserIsModerator(Username); @@ -166,6 +170,8 @@ namespace Horse_Isle_Server y = Database.GetPlayerY(UserId); charId = Database.GetPlayerCharId(UserId); + Facing = PacketBuilder.DIRECTION_DOWN; + money = Database.GetPlayerMoney(UserId); bankMoney = Database.GetPlayerBankMoney(UserId); @@ -181,6 +187,7 @@ namespace Horse_Isle_Server SecCodeSeeds[2] = (byte)rng.Next(40, 140); SecCodeInc = (byte)rng.Next(0, 99); + // Make some friends! (Get a life!) Friends = new Friends(this); diff --git a/Horse Isle Server/Horse Isle Server/World.cs b/Horse Isle Server/Horse Isle Server/World.cs index 2612d63..c7fdf99 100644 --- a/Horse Isle Server/Horse Isle Server/World.cs +++ b/Horse Isle Server/Horse Isle Server/World.cs @@ -38,39 +38,47 @@ namespace Horse_Isle_Server public struct Time { - public int minutes; - public int hours; - public int days; - public int year; + public int Minutes; + public int Days; + public int Years; } - public const int MINUTE = 4320; + + public static Time ServerTime = new Time(); public static List Isles = new List(); public static List Towns = new List(); public static List Areas = new List(); - public static Time GetGameTime() + + public static void TickWorldClock() { - int epoch = Database.GetServerCreationTime(); - DateTime serverCreationTime = DateTimeOffset.FromUnixTimeSeconds(epoch).DateTime; - DateTime currentTime = DateTime.Now; + ServerTime.Minutes += 1; - TimeSpan difference = (currentTime.Date - currentTime.Date); + int hours = ServerTime.Minutes / 60; - int totalMilis = Convert.ToInt32(difference.TotalMilliseconds); + // Periodically write time to database: + if (ServerTime.Minutes % 10 == 0) // every 10-in-game minutes) + Database.SetServerTime(ServerTime.Minutes, ServerTime.Days, ServerTime.Years); - - int gameMinutes = totalMilis / MINUTE; - int gameHours = (totalMilis / MINUTE * 600); - int gameDays = (totalMilis / (MINUTE * 60) * 24); - int gameYears = ((totalMilis / (MINUTE * 60) * 24)*365); + if (hours == 24) // 1 day + { + ServerTime.Days += 1; + ServerTime.Minutes = 0; + } - Time time = new Time(); - time.days = gameDays; - time.year = gameYears; - time.minutes = gameMinutes; - time.hours = gameHours; + if (ServerTime.Days == 366) // 1 year! + { + ServerTime.Days = 0; + ServerTime.Years += 1; + } + } - return time; + public static void ReadWorldData() + { + Logger.DebugPrint("Reading time from database..."); + ServerTime.Minutes = Database.GetServerTime(); + ServerTime.Days = Database.GetServerDay(); + ServerTime.Years = Database.GetServerYear(); + Logger.InfoPrint("It is " + ServerTime.Minutes / 60 + ":" + ServerTime.Minutes % 60 + " on Day " + ServerTime.Days + " in Year " + ServerTime.Years + "!!!"); } public static bool InArea(int x, int y) diff --git a/WebInterface/game-site/mod/jumpingarena1.swf b/WebInterface/game-site/mod/jumpingarena1.swf new file mode 100644 index 0000000..85911f7 Binary files /dev/null and b/WebInterface/game-site/mod/jumpingarena1.swf differ diff --git a/WebInterface/game-site/mod/jumpingarena2.swf b/WebInterface/game-site/mod/jumpingarena2.swf new file mode 100644 index 0000000..1007ea5 Binary files /dev/null and b/WebInterface/game-site/mod/jumpingarena2.swf differ