diff --git a/CPHelper/.svn/all-wcprops b/CPHelper/.svn/all-wcprops new file mode 100644 index 0000000..a547f8a --- /dev/null +++ b/CPHelper/.svn/all-wcprops @@ -0,0 +1,17 @@ +K 25 +svn:wc:ra_dav:version-url +V 31 +/svn/!svn/ver/55/trunk/CPHelper +END +CPHelper.csproj +K 25 +svn:wc:ra_dav:version-url +V 47 +/svn/!svn/ver/30/trunk/CPHelper/CPHelper.csproj +END +CPHelper.cs +K 25 +svn:wc:ra_dav:version-url +V 43 +/svn/!svn/ver/55/trunk/CPHelper/CPHelper.cs +END diff --git a/CPHelper/.svn/desktop.ini b/CPHelper/.svn/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/CPHelper/.svn/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/CPHelper/.svn/dir-prop-base b/CPHelper/.svn/dir-prop-base new file mode 100644 index 0000000..f1b96ea --- /dev/null +++ b/CPHelper/.svn/dir-prop-base @@ -0,0 +1,5 @@ +K 14 +bugtraq:number +V 4 +true +END diff --git a/CPHelper/.svn/entries b/CPHelper/.svn/entries new file mode 100644 index 0000000..8066b76 --- /dev/null +++ b/CPHelper/.svn/entries @@ -0,0 +1,99 @@ +10 + +dir +58 +http://proxymud.googlecode.com/svn/trunk/CPHelper +http://proxymud.googlecode.com/svn + + + +2012-02-03T09:23:01.115255Z +55 +default8p@gmail.com +has-props + + + + + + + + + + + + + +8a6e9f07-fe1d-2472-fcf8-0b435762827a + +Properties +dir + +CPHelper.csproj +file + + + + +2016-03-25T22:18:42.968136Z +b6b9d8532fe49f254ea48003963156b0 +2012-01-23T07:49:14.623991Z +30 +default8p@gmail.com + + + + + + + + + + + + + + + + + + + + + +3161 + +CPHelper.cs +file + + + + +2016-03-25T22:18:42.968136Z +d4798a728907666a4b0eccfa26afc339 +2012-02-03T09:23:01.115255Z +55 +default8p@gmail.com + + + + + + + + + + + + + + + + + + + + + +48141 + diff --git a/CPHelper/.svn/prop-base/desktop.ini b/CPHelper/.svn/prop-base/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/CPHelper/.svn/prop-base/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/CPHelper/.svn/props/desktop.ini b/CPHelper/.svn/props/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/CPHelper/.svn/props/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/CPHelper/.svn/text-base/CPHelper.cs.svn-base b/CPHelper/.svn/text-base/CPHelper.cs.svn-base new file mode 100644 index 0000000..7429a2f --- /dev/null +++ b/CPHelper/.svn/text-base/CPHelper.cs.svn-base @@ -0,0 +1,1342 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; +using Mapper; +using MobDB; +using ProxyCore; +using ProxyCore.Input; +using ProxyCore.Output; +using ProxyCore.Scripting; + +namespace CPHelper +{ + public class CPHelper : Plugin + { + public CPHelper() + : base("cphelper", "Campaign Helper") + { + Author = "Duckbat"; + Version = 5; + Description = "Matches mobs from database to rooms. Creates useful tags for campaign check."; + UpdateUrl = "www.duckbat.com/plugins/update.cphelper.txt"; + Website = "code.google.com/p/proxymud/"; + + Config = new CPHelperConfig(); + + RegisterCommand("autonoexp", @"^(\d+)", AutoNoexpCommand); + RegisterCommand("gowhere", "", GoWhereCommand, 3); + RegisterCommand("where", "(.+)", WhereCommand, 3); + RegisterCommand("gquest", "(.+)", GQCheckCommand, 2); + RegisterCommand("campaign", "(.+)", CampaignCheckCommand, 5); + RegisterCommand("cp", "(.+)", CampaignCheckCommand, 0); + RegisterCommand("awhere", "(.+)", AutoWhereCommand, 2); + RegisterCommand("ahunttrick", "(.+)", AutoHuntTrickCommand, 2); + RegisterCommand("hunt", "(.+)", HuntCommand, 2); + RegisterCommand("astop", "", AutoStopCommand, 2); + + RegisterTrigger("gq.quit", @"@wYou are no longer part of the current quest.", TriggerGQLevel2, TriggerFlags.NotRegex); + RegisterTrigger("hunt.target", @"@wYou seem unable to hunt that target for some reason.", TriggerHuntT, TriggerFlags.NotRegex); + RegisterTrigger("hunt.fail1", @"@wNo one in this area by that name.", TriggerHuntFail, TriggerFlags.NotRegex); + RegisterTrigger("hunt.fail2", @"^@wYou couldn't find a path to .+from here\.$", TriggerHuntNT); + RegisterTrigger("hunt.fail3", @"(.+?)is here!$", TriggerHuntFail); + RegisterTrigger("hunt.nottarget", @"^@wYou are confident that .+passed through here, heading \w+\.$", TriggerHuntNT); + RegisterTrigger("hunt.nottarget2", @"^@wYou have no idea what you're doing, but maybe .+left .+\?$", TriggerHuntNT); + RegisterTrigger("hunt.nottarget3", @"^@wYou are almost certain that .+is .+from here\.$", TriggerHuntNT); + RegisterTrigger("hunt.nottarget4", @"^@wThe trail of .+is confusing, but you're reasonable sure .+headed .+\.$", TriggerHuntNT); + RegisterTrigger("hunt.nottarget5", @"^@wThere are traces of .+having been here\. Perhaps they lead .+\?$", TriggerHuntNT); + RegisterTrigger("hunt.nottarget6", @"^@wYou are certain that .+is .+from here\.$", TriggerHuntNT); + RegisterTrigger("where.fail1", @"@wThere are too many doors and fences to see who is in this area.", TriggerWhereFail, TriggerFlags.NotRegex); + RegisterTrigger("where.fail2", @"^@wThere is no .+around here\.$", TriggerWhereFail); + RegisterTrigger("quest0", @"^\$gmcp\.comm\.quest\.action start$", TriggerQuest0); + RegisterTrigger("quest1", @"^\$gmcp\.comm\.quest\.room (.+)", TriggerQuest2); + RegisterTrigger("quest2", @"^\$gmcp\.comm\.quest\.area (.+)", TriggerQuest3); + RegisterTrigger("quest3", @"^\$gmcp\.comm\.quest\.targ (.+)", TriggerQuest1); + RegisterTrigger("enterroom", @"^\$gmcp\.room\.info\.num (-?\d+)$", TriggerRoomNum); + RegisterTrigger("check", @"^@wYou still have to kill (@c\d @w)?\* (.+?) (@w)?\((.+?)(@w)?\)$", TriggerCheck); + RegisterTrigger("char.level", @"^\$gmcp\.char\.status\.level (\d+)$", TriggerLevel); + RegisterTrigger("char.tnl", @"^\$gmcp\.char\.status\.tnl (\d+)$", TriggerTNL); + RegisterTrigger("request", @"^@.Commander Barcett tells you 'Good luck in your campaign!'$", TriggerRequest); + RegisterTrigger("cplevel", @"^@cLevel Taken\.\.\.\.\.\.\.\.: @g\[ \s+@w(\d+) @g\]$", TriggerCPLevel); + RegisterTrigger("gqlevel", @"^@RGlobal Quest@Y: @gGlobal quest # \d+ @whas been declared for levels @g(\d+) @wto @g(\d+)@w\.$", TriggerGQLevel); + RegisterTrigger("gqlevel2", @"^@RGlobal Quest@Y: @wThe global quest has been won by @Y\w+ @w- @Y\d+(st|th|rd|nd) @wwin\.$", TriggerGQLevel2); + RegisterTrigger("noexp1", @"@RYou will no longer receive experience. Happy questing!", NoexpTrigger1, TriggerFlags.NotRegex); + RegisterTrigger("noexp2", @"@wYou will now receive experience. Happy leveling!", NoexpTrigger2, TriggerFlags.NotRegex); + RegisterTrigger("cpcomplete", @"@GCONGRATULATIONS! @wYou have completed your campaign.", TriggerCPComplete, TriggerFlags.NotRegex); + RegisterTrigger("cpfail", "@wCampaign cleared.", TriggerCPComplete, TriggerFlags.NotRegex); + RegisterTrigger("scan1", "@w{scan}", TriggerScan1, TriggerFlags.NotRegex); + RegisterTrigger("scan0", "@w{/scan}", TriggerScan0, TriggerFlags.NotRegex); + RegisterTrigger("scan2", "^ @w- (.+)", TriggerScan2); + RegisterTrigger("scan.room", @"^@C(\d )?(North|East|West|South|Down|Up) from here you see:", TriggerScanRoom); + RegisterTrigger("scan.room2", @"^@CRight here you see:", TriggerScanRoom2); + RegisterTrigger("enemy", @"^$gmcp\.char\.status\.enemy(.*)", TriggerCurrentEnemy); + RegisterTrigger("cp.kill", @"@WCongratulations, that was one of your CAMPAIGN mobs!", TriggerOnKilled1, TriggerFlags.NotRegex); + RegisterTrigger("gq.kill", @"@RCongratulations, that was one of the GLOBAL QUEST mobs!", TriggerOnKilled0, TriggerFlags.NotRegex); + RegisterTrigger("room.area", @"^\$gmcp\.room\.info\.zone (.*)$", TriggerRoomInfoArea); + RegisterTrigger("where", @"^(.{28}) (.+)", TriggerWhere, TriggerFlags.NonAnsi); + } + + private uint CurrentRoomId = uint.MaxValue; + private bool AllowScan = false; + private int MyLvl = 0; + private int MyXP = 99999; + private int CampaignLvl = 0; + private int GQLvl = 0; + private long Spam = 0; + private bool IsNoexp = false; + private int AutoNoexp = 0; + private bool didEnter = false; + private readonly List[] Targets = new[] { new List(), new List() }; + private string CurEnemy = ""; + private string RoomInfoArea = ""; + private long WhereTimeout = 0; + private long HuntTimeout = 0; + private readonly List WhereRooms = new List(); + private uint FirstWhereRoom = uint.MaxValue; + private readonly List ScanRooms = new List(); + private uint CurScanRoom = uint.MaxValue; + private string QuestTarget = string.Empty; + private string QuestRoom = string.Empty; + private string QuestArea = string.Empty; + private bool QuestListen = false; + + private int AutoWhereNth = 1; + private string AutoWhereKey = string.Empty; + private int AutoHuntNth = 1; + private string AutoHuntKey = string.Empty; + + private bool TriggerHuntT(TriggerData t) + { + World.Instance.Execute("where " + AutoHuntNth + "." + AutoHuntKey, true); + AutoHuntKey = string.Empty; + AutoHuntNth = 1; + return false; + } + + private bool TriggerHuntNT(TriggerData t) + { + HuntTimeout = 0; + AutoHuntNth++; + return false; + } + + private bool TriggerWhereFail(TriggerData t) + { + AutoWhereKey = string.Empty; + AutoWhereNth = 1; + WhereTimeout = 0; + return false; + } + + private bool TriggerHuntFail(TriggerData t) + { + AutoHuntKey = string.Empty; + AutoHuntNth = 1; + HuntTimeout = 0; + return false; + } + + private bool AutoStopCommand(InputData i) + { + AutoWhereKey = string.Empty; + AutoHuntKey = string.Empty; + return true; + } + + private bool AutoWhereCommand(InputData i) + { + string arg; + if(!i.Arguments.Success || (arg = i.Arguments.Groups[1].Value.Trim()).Length == 0) + { + World.Instance.SendMessage("@wSyntax: awhere ", i.ClientMask); + return true; + } + + WhereTimeout = 0; + Match m = _argRegex.Match(arg); + if(m.Success) + { + AutoWhereKey = m.Groups[2].Value; + if(!int.TryParse(m.Groups[1].Value, out AutoWhereNth)) + AutoWhereNth = 1; + } + else + { + AutoWhereNth = 1; + AutoWhereKey = arg; + } + return true; + } + + private bool AutoHuntTrickCommand(InputData i) + { + string arg; + if(!i.Arguments.Success || (arg = i.Arguments.Groups[1].Value.Trim()).Length == 0) + { + World.Instance.SendMessage("@wSyntax: ahunttrick ", i.ClientMask); + return true; + } + + HuntTimeout = 0; + Match m = _argRegex.Match(arg); + if(m.Success) + { + AutoHuntKey = m.Groups[2].Value; + if(!int.TryParse(m.Groups[1].Value, out AutoHuntNth)) + AutoHuntNth = 1; + } + else + { + AutoHuntNth = 1; + AutoHuntKey = arg; + } + return true; + } + + private static Regex _argRegex = new Regex(@"^(\d+)\.(.+)", RegexOptions.Compiled); + + private bool TriggerQuest0(TriggerData t) + { + QuestListen = true; + return false; + } + + private bool TriggerQuest1(TriggerData t) + { + if(!QuestListen) + return false; + + QuestTarget = MobDB.MobDB.NormalizeName(t.Match.Groups[1].Value.Trim()); + return false; + } + + private bool TriggerQuest2(TriggerData t) + { + if(!QuestListen) + return false; + + QuestRoom = t.Match.Groups[1].Value.Trim(); + return false; + } + + private bool TriggerQuest3(TriggerData t) + { + if(!QuestListen) + return false; + + QuestListen = false; + QuestArea = t.Match.Groups[1].Value.Trim(); + + int minLevel = MyLvl - 8; + int maxLevel = MyLvl + 10; + if(MyLvl >= 200) + maxLevel = MyLvl + 20; + + uint bestMobRoom = uint.MaxValue; + MobDB.MobDB db = PluginMgr.GetPlugin("mobdb") as MobDB.MobDB; + Mapper.Mapper map = PluginMgr.GetPlugin("mapper") as Mapper.Mapper; + List Areas = new List(); + List Rooms = new List(); + foreach(Area x in map.Areas) + { + if(x.Name == QuestArea) + Areas.Add(x.Keyword); + } + foreach(Room r in map.Rooms) + { + if(r.Area.Name != QuestArea) + continue; + + if(r.Name != QuestRoom) + continue; + + Rooms.Add(r.Entry); + } + foreach(Mob m in db.Mobs) + { + if(m.Level < minLevel || m.Level > maxLevel) + continue; + + if(!m.Name.Contains(QuestTarget)) + continue; + + if(!m.Areas.Contains("all")) + { + bool f = false; + foreach(string x in m.Areas) + { + if(Areas.Contains(x)) + { + f = true; + break; + } + } + + if(!f) + continue; + } + + bestMobRoom = m.GetBestRoom(); + if(bestMobRoom == uint.MaxValue) + continue; + + Room br = map.GetRoom(bestMobRoom); + if(br != null) + { + Pathfinder_Mob pf = new Pathfinder_Mob(m, Rooms.ToArray()); + pf.StartRooms = new[] { br }; + PathfindResult pr = map.Get(pf); + if(!pr.Success || pr.Target == null) + { + bestMobRoom = uint.MaxValue; + continue; + } + + bestMobRoom = pr.Target.Entry; + break; + } + } + + + if(Rooms.Count != 0) + { + WhereRooms.Clear(); + WhereRooms.AddRange(Rooms); + FirstWhereRoom = bestMobRoom; + World.Instance.SendMessage("@wAdded @C" + Rooms.Count + " @wroom" + (Rooms.Count != 1 ? "s" : "") + " to @G\"where\" @wlist. Use '@Wgowhere@w' to visit them."); + } + + return false; + } + + private bool TriggerScanRoom(TriggerData t) + { + CurScanRoom = uint.MaxValue; + int c = 1; + if(t.Match.Groups[1].Length != 0) + int.TryParse(t.Match.Groups[1].Value, out c); + char d = t.Match.Groups[2].Value.ToLower()[0]; + + Mapper.Mapper map = PluginMgr.GetPlugin("mapper") as Mapper.Mapper; + if(map == null) + return false; + + Room r = map.GetRoom(CurrentRoomId); + if(r == null) + return false; + + for(int i = 0; i < c; i++) + { + Exit e = r.GetExit(d); + if(e == null) + return false; + + r = e.To; + } + + if(string.IsNullOrEmpty(r.Name)) + return false; + + CurScanRoom = r.Entry; + return false; + } + + private bool TriggerScanRoom2(TriggerData t) + { + CurScanRoom = CurrentRoomId; + return false; + } + + private bool GQCheckCommand(InputData i) + { + if(i.Arguments.Success && i.Arguments.Groups[1].Length <= 5 && + "check".StartsWith(i.Arguments.Groups[1].Value.ToLower())) + Targets[0].Clear(); + return false; + } + + private bool CampaignCheckCommand(InputData i) + { + if(i.Arguments.Success && i.Arguments.Groups[1].Length <= 5 && + "check".StartsWith(i.Arguments.Groups[1].Value.ToLower())) + Targets[1].Clear(); + return false; + } + + private bool TriggerRoomNum(TriggerData t) + { + uint u; + if(uint.TryParse(t.Match.Groups[1].Value, out u)) + { + CurrentRoomId = u; + if(FirstWhereRoom == u) + FirstWhereRoom = uint.MaxValue; + if(WhereRooms.Remove(u)) + World.Instance.SendMessage("@wEntered a @G\"where\" @wroom. Now have @C" + WhereRooms.Count + " @wroom" + (WhereRooms.Count != 1 ? "s" : "") + " remaining. Use '@Wgowhere@w' to go to the next one."); + } + else + CurrentRoomId = uint.MaxValue; + return false; + } + + private bool TriggerWhere(TriggerData t) + { + if(WhereTimeout < World.Instance.MSTime) + return false; + + Mapper.Mapper map = PluginMgr.GetPlugin("mapper") as Mapper.Mapper; + if(map == null) + return false; + + string rName = t.Match.Groups[2].Value.Trim(); + + List r = new List(); + foreach(Room x in map.Rooms) + { + if(x.Area.Keyword == RoomInfoArea && x.Name == rName) + r.Add(x); + } + + string mobName = t.Match.Groups[1].Value.Trim(); + mobName = MobDB.MobDB.NormalizeName(mobName); + + if(!string.IsNullOrEmpty(AutoWhereKey)) + { + if(Targets[0].Count != 0) + { + foreach(CPEntry x in Targets[0]) + { + if(x.Name.StartsWith(mobName)) + { + AutoWhereKey = string.Empty; + break; + } + } + } + else + { + foreach(CPEntry x in Targets[1]) + { + if(x.Name.StartsWith(mobName)) + { + AutoWhereKey = string.Empty; + break; + } + } + + if(QuestTarget.StartsWith(mobName)) + AutoWhereKey = string.Empty; + } + } + + if(r.Count == 0) + return false; + + WhereRooms.Clear(); + FirstWhereRoom = uint.MaxValue; + WhereTimeout = 0; + foreach(Room x in r) + { + if(CurrentRoomId != x.Entry) + WhereRooms.Add(x.Entry); + } + + if(WhereRooms.Count == 0) + return false; + + World.Instance.SendMessage("@wAdded @C" + WhereRooms.Count + " @wroom" + (WhereRooms.Count != 1 ? "s" : "") + " to @G\"where\"@w. Type '@Wgowhere@w' to go there."); + MobDB.MobDB db = PluginMgr.GetPlugin("mobdb") as MobDB.MobDB; + if(db == null) + return false; + + foreach(Mob m in db.Mobs) + { + if(!m.Areas.Contains("all") && !m.Areas.Contains(RoomInfoArea)) + continue; + + bool f = false; + foreach(string z in m.Name) + { + if(mobName.Length >= 26) + { + if(z.StartsWith(mobName)) + { + f = true; + break; + } + } + else if(z == mobName) + { + f = true; + break; + } + } + + if(!f) + continue; + + uint b = m.GetBestRoom(); + if(b == uint.MaxValue || b == CurrentRoomId) + continue; + + Room br = map.GetRoom(b); + if(br == null || br.Entry == CurrentRoomId) + continue; + + if(WhereRooms.Contains(b)) + FirstWhereRoom = b; + else + { + Pathfinder_Mob pf = new Pathfinder_Mob(m, WhereRooms.ToArray()); + pf.StartRooms = new[] { br }; + + PathfindResult pr = map.Get(pf); + if(pr.Success && pr.Target != null) + FirstWhereRoom = pr.Target.Entry; + } + + break; + } + + return false; + } + + private bool WhereCommand(InputData i) + { + if(i.Arguments.Success && i.Arguments.Groups[1].Value.Trim().Length > 0) + WhereTimeout = World.Instance.MSTime + 6000; + return false; + } + + private bool HuntCommand(InputData i) + { + if(i.Arguments.Success && i.Arguments.Groups[1].Value.Trim().Length > 0) + HuntTimeout = World.Instance.MSTime + 6000; + return false; + } + + private bool GoWhereCommand(InputData i) + { + if(WhereRooms.Count == 0) + World.Instance.SendMessage("@wThere are no where rooms available.", i.ClientMask); + else + { + Mapper.Mapper map = PluginMgr.GetPlugin("mapper") as Mapper.Mapper; + if(map == null) + { + World.Instance.SendMessage("@wInternal error.", i.ClientMask); + return true; + } + + Pathfinder_Entry pf = new Pathfinder_Entry(FirstWhereRoom != uint.MaxValue ? new[] { FirstWhereRoom } : WhereRooms.ToArray()); + map.FillPathFinder(pf); + PathfindResult pr = map.Get(pf); + if(!pr.Success) + World.Instance.SendMessage("@wCouldn't find a path to any of the where rooms.", i.ClientMask); + else + map.Goto(pr); + } + return true; + } + + public override void OnLogin() + { + base.OnLogin(); + + RegisterCommand("goto", @"(.+)", GotoMobCommand, 2, CMDFlags.None, "mobdb"); + } + + private bool GotoMobCommand(InputData i) + { + if(string.IsNullOrEmpty(RoomInfoArea)) + { + World.Instance.SendMessage("@wDon't know yet which area we are in. Type look to find out.", i.ClientMask); + return true; + } + + if(!i.Arguments.Success) + { + World.Instance.SendMessage("@wSyntax: mobdb goto ", i.ClientMask); + return true; + } + + MobDB.MobDB db = PluginMgr.GetPlugin("mobdb") as MobDB.MobDB; + if(db == null) + { + World.Instance.SendMessage("@wInternal error.", i.ClientMask); + return true; + } + + List toGoRooms = new List(); + string name = i.Arguments.Groups[1].Value.ToLower(); + foreach(Mob m in db.Mobs) + { + if(!m.Areas.Contains("all") && !m.Areas.Contains(RoomInfoArea)) + continue; + + uint p = m.GetBestRoom(); + if(p == uint.MaxValue) + continue; + + foreach(string z in m.Name) + { + if(z.ToLower().Contains(name)) + { + if(!toGoRooms.Contains(p)) + toGoRooms.Add(p); + break; + } + } + } + + if(toGoRooms.Count == 0) + { + World.Instance.SendMessage("@wFound no mobs with that name in current area.", i.ClientMask); + return true; + } + + Mapper.Mapper map = PluginMgr.GetPlugin("mapper") as Mapper.Mapper; + if(map == null) + { + World.Instance.SendMessage("@wInternal error.", i.ClientMask); + return true; + } + + Pathfinder_Entry pf = new Pathfinder_Entry(toGoRooms.ToArray()); + if(!map.FillPathFinder(pf)) + { + World.Instance.SendMessage("@wWe are in an unknown room.", i.ClientMask); + return true; + } + + PathfindResult pr = map.Get(pf); + if(!pr.Success) + { + World.Instance.SendMessage("@wCouldn't find a path to any of the mobs with that name.", i.ClientMask); + return true; + } + + map.Goto(pr); + return true; + } + + private bool TriggerRoomInfoArea(TriggerData t) + { + RoomInfoArea = t.Match.Groups[1].Value.Trim(); + return false; + } + + private bool TriggerOnKilled0(TriggerData t) + { + if(string.IsNullOrEmpty(CurEnemy)) + return false; + + MobDB.MobDB db = PluginMgr.GetPlugin("mobdb") as MobDB.MobDB; + if(db == null) + return false; + + CurEnemy = MobDB.MobDB.NormalizeName(CurEnemy); + + for(int i = 0; i < Targets[0].Count; i++) + { + CPEntry x = Targets[0][i]; + + if(x.Name != CurEnemy) + continue; + + foreach(uint u in x.Mobs) + { + Mob m = db.GetMob(u); + if(m == null) + continue; + + if(!m.Areas.Contains("all") && !m.Areas.Contains(RoomInfoArea)) + continue; + + if(m.Name.Contains(CurEnemy)) + { + if(x.Count > 1) + { + x.Count--; + return false; + } + + Targets[0].RemoveAt(i); + UpdateColors(); + return false; + } + } + } + + return false; + } + + private bool TriggerOnKilled1(TriggerData t) + { + if(string.IsNullOrEmpty(CurEnemy)) + return false; + + MobDB.MobDB db = PluginMgr.GetPlugin("mobdb") as MobDB.MobDB; + if(db == null) + return false; + + CurEnemy = MobDB.MobDB.NormalizeName(CurEnemy); + + for(int i = 0; i < Targets[1].Count; i++) + { + CPEntry x = Targets[1][i]; + + if(x.Name != CurEnemy) + continue; + + foreach(uint u in x.Mobs) + { + Mob m = db.GetMob(u); + if(m == null) + continue; + + if(!m.Areas.Contains("all") && !m.Areas.Contains(RoomInfoArea)) + continue; + + if(m.Name.Contains(CurEnemy)) + { + if(x.Count > 1) + { + x.Count--; + return false; + } + + Targets[1].RemoveAt(i); + UpdateColors(); + return false; + } + } + } + + return false; + } + + private bool TriggerCurrentEnemy(TriggerData t) + { + CurEnemy = Colors.RemoveColors(t.Match.Groups[1].Value, false).Trim(); + return false; + } + + private bool TriggerScan0(TriggerData t) + { + AllowScan = false; + if(Config.GetInt32("Tags.Scan.Gag", 1) != 0) + t.Msg.AuthMask = 0; + + StringBuilder strScan = new StringBuilder(); + foreach(uint u in ScanRooms) + { + if(strScan.Length > 0) + strScan.Append(" "); + strScan.Append(u); + } + World.Instance.SendMessage("@w{scan_rooms}" + strScan); + return false; + } + + private bool TriggerScan1(TriggerData t) + { + ScanRooms.Clear(); + AllowScan = true; + if(Config.GetInt32("Tags.Scan.Gag", 1) != 0) + t.Msg.AuthMask = 0; + return false; + } + + private bool TriggerScan2(TriggerData td) + { + if(!AllowScan) + return false; + + if(Targets[0].Count == 0 && Targets[1].Count == 0) + return false; + + MobDB.MobDB db = PluginMgr.GetPlugin("mobdb") as MobDB.MobDB; + if(db == null) + return false; + + string t = Colors.RemoveDuplicateColors("@w" + td.Match.Groups[1].Value); + if(t.StartsWith("@R(Wounded)")) + t = Colors.RemoveDuplicateColors("@R" + t.Substring("@R(Wounded)".Length)).Trim(); + + if(t.StartsWith("@w(Invis)")) + t = Colors.RemoveDuplicateColors("@w" + t.Substring("@w(Invis)".Length)).Trim(); + else if(t.StartsWith("@w(I)")) + t = Colors.RemoveDuplicateColors("@w" + t.Substring("@w(I)".Length)).Trim(); + + if(t.StartsWith("@w(Hidden)")) + t = Colors.RemoveDuplicateColors("@w" + t.Substring("@w(Hidden)".Length)).Trim(); + else if(t.StartsWith("@w(H)")) + t = Colors.RemoveDuplicateColors("@w" + t.Substring("@w(H)".Length)).Trim(); + + if(t.StartsWith("@W(Translucent)")) + t = Colors.RemoveDuplicateColors("@W" + t.Substring("@W(Translucent)".Length)).Trim(); + else if(t.StartsWith("@W(T)")) + t = Colors.RemoveDuplicateColors("@W" + t.Substring("@W(T)".Length)).Trim(); + + if(t.StartsWith("@C(Charmed) ")) + return false; + else if(t.StartsWith("@C(C)")) + return false; + + if(t.StartsWith("@M(Animated) ")) + return false; + else if(t.StartsWith("@M(A)")) + return false; + + if(t.StartsWith("@B(Diseased)")) + t = Colors.RemoveDuplicateColors("@B" + t.Substring("@B(Diseased)".Length)).Trim(); + else if(t.StartsWith("@B(D)")) + t = Colors.RemoveDuplicateColors("@B" + t.Substring("@B(D)".Length)).Trim(); + + if(t.StartsWith("@D(Marked)")) + t = Colors.RemoveDuplicateColors("@D" + t.Substring("@D(Marked)".Length)).Trim(); + else if(t.StartsWith("@D(X)")) + t = Colors.RemoveDuplicateColors("@D" + t.Substring("@D(X)".Length)).Trim(); + + if(t.StartsWith("@r(Red Aura)")) + t = Colors.RemoveDuplicateColors("@r" + t.Substring("@r(Red Aura)".Length)).Trim(); + else if(t.StartsWith("@r(R)")) + t = Colors.RemoveDuplicateColors("@r" + t.Substring("@r(R)".Length)).Trim(); + else if(t.StartsWith("@y(Golden Aura)")) + t = Colors.RemoveDuplicateColors("@y" + t.Substring("@y(Golden Aura)".Length)).Trim(); + else if(t.StartsWith("@y(G)")) + t = Colors.RemoveDuplicateColors("@y" + t.Substring("@y(G)".Length)).Trim(); + + if(t.StartsWith("@W(White Aura)")) + t = Colors.RemoveDuplicateColors("@W" + t.Substring("@W(White Aura)".Length)).Trim(); + else if(t.StartsWith("@W(W)")) + t = Colors.RemoveDuplicateColors("@W" + t.Substring("@W(W)".Length)).Trim(); + + if(t.StartsWith("@R(Angry)")) + t = Colors.RemoveDuplicateColors("@R" + t.Substring("@R(Angry)".Length)).Trim(); + + if(t.StartsWith("@w(Linkdead)")) + return false; + + if(t.StartsWith("@R(RAIDER)")) + return false; + + if(t.StartsWith("@R(TRAITOR)")) + return false; + + if(t.StartsWith("@G(DEFENDER)")) + return false; + + if(t.StartsWith("@R(WANTED)")) + return false; + + Mapper.Mapper map = PluginMgr.GetPlugin("mapper") as Mapper.Mapper; + if(map == null) + return false; + + string n = Colors.RemoveColors(t, false).ToLower().Trim(); + if(t.StartsWith("@") && !t.StartsWith("@@") && t.Length >= 2) + t = t.Substring(2); + if(Targets[0].Count != 0) + { + foreach(CPEntry x in Targets[0]) + { + if(x.Name.ToLower() != n) + continue; + + int ind = td.Msg.Msg.LastIndexOf(t); + if(ind != -1) + { + td.Msg.Msg = td.Msg.Msg.Remove(ind); + td.Msg.Msg = td.Msg.Msg.Insert(ind, Config.GetString("Color.Scan", "@R") + x.Name); + } + + if(CurScanRoom != uint.MaxValue && !ScanRooms.Contains(CurScanRoom)) + ScanRooms.Add(CurScanRoom); + + return false; + } + } + else + { + foreach(CPEntry x in Targets[1]) + { + if(x.Name.ToLower() == n) + { + int ind = td.Msg.Msg.LastIndexOf(t); + if(ind != -1) + { + td.Msg.Msg = td.Msg.Msg.Remove(ind); + td.Msg.Msg = td.Msg.Msg.Insert(ind, Config.GetString("Color.Scan", "@R") + x.Name); + } + + if(CurScanRoom != uint.MaxValue && !ScanRooms.Contains(CurScanRoom)) + ScanRooms.Add(CurScanRoom); + + return false; + } + } + } + + return false; + } + + private bool TriggerCPComplete(TriggerData t) + { + Targets[1].Clear(); + UpdateColors(); + return false; + } + + private bool NoexpTrigger1(TriggerData t) + { + IsNoexp = true; + didEnter = false; + return false; + } + + private bool NoexpTrigger2(TriggerData t) + { + IsNoexp = false; + didEnter = false; + return false; + } + + public override void Update(long msTime) + { + base.Update(msTime); + + if(!string.IsNullOrEmpty(AutoWhereKey)) + { + if(WhereTimeout > msTime) + return; + if(WhereTimeout != 0) + AutoWhereKey = string.Empty; + else + { + World.Instance.Execute("where " + AutoWhereNth + "." + AutoWhereKey, true); + AutoWhereNth++; + return; + } + } + + if(!string.IsNullOrEmpty(AutoHuntKey)) + { + if(HuntTimeout > msTime) + return; + if(HuntTimeout != 0) + AutoHuntKey = string.Empty; + else + { + World.Instance.Execute("hunt " + AutoHuntNth + "." + AutoHuntKey, true); + return; + } + } + + if(didEnter) + return; + + if(AutoNoexp == 0) + return; + + bool shouldNoExp = MyLvl > CampaignLvl && MyXP <= AutoNoexp; + if(shouldNoExp) + { + if(IsNoexp) + return; + } + else + { + if(!IsNoexp) + return; + } + + World.Instance.Execute("noexp", true); + didEnter = true; + } + + private bool AutoNoexpCommand(InputData t) + { + int n; + if(!t.Arguments.Success || !int.TryParse(t.Arguments.Groups[1].Value, out n)) + { + World.Instance.SendMessage("@wSyntax: autonoexp ", t.ClientMask); + return true; + } + + if(n <= 0) + { + AutoNoexp = 0; + World.Instance.SendMessage("@wYou will no longer turn noexp on automatically.", t.ClientMask); + return true; + } + + AutoNoexp = n; + World.Instance.SendMessage("@wYou will now turn noexp on when you can ask a campaign and XP goes to @C" + n + " @wor below.", t.ClientMask); + World.Instance.SendMessage("@wUse '@Wautonoexp 0@w' to turn this off.", t.ClientMask); + return true; + } + + private bool TriggerGQLevel(TriggerData t) + { + Targets[0].Clear(); + int lvl; + if(int.TryParse(t.Match.Groups[1].Value, out lvl)) + GQLvl = lvl; + UpdateColors(); + return false; + } + + private bool TriggerGQLevel2(TriggerData t) + { + Targets[0].Clear(); + GQLvl = 0; + UpdateColors(); + return false; + } + + private bool TriggerCPLevel(TriggerData t) + { + int lvl; + if(int.TryParse(t.Match.Groups[1].Value, out lvl)) + CampaignLvl = lvl; + return false; + } + + private bool TriggerRequest(TriggerData t) + { + CampaignLvl = MyLvl; + return false; + } + + private bool TriggerLevel(TriggerData t) + { + int lvl; + if(int.TryParse(t.Match.Groups[1].Value, out lvl)) + MyLvl = lvl; + return false; + } + + private bool TriggerTNL(TriggerData t) + { + int lvl; + if(int.TryParse(t.Match.Groups[1].Value, out lvl)) + MyXP = lvl; + return false; + } + + private bool TriggerCheck(TriggerData t) + { + string mobName = MobDB.MobDB.NormalizeName(Colors.RemoveColors(t.Match.Groups[2].Value, false).Trim()); + string placeName = Colors.RemoveColors(t.Match.Groups[4].Value, false).Trim(); + if(placeName.EndsWith(" - Dead")) + placeName = placeName.Substring(0, placeName.LastIndexOf(" - Dead")); + + if(Config.GetInt32("Tags.On", 1) != 0) + { + World.Instance.SendMessage("@w{cp_mob}" + mobName); + World.Instance.SendMessage("@w{cp_place}" + placeName); + } + + if(CampaignLvl == 0 && t.Match.Groups[1].Length == 0) + { + if(Spam < World.Instance.MSTime) + { + Spam = World.Instance.MSTime + 300; + World.Instance.SendMessage("@WPlease see '@Rcampaign info@W' first! I need the level to check for mobs."); + } + return false; + } + + MobDB.MobDB db = PluginMgr.GetPlugin("mobdb") as MobDB.MobDB; + Mapper.Mapper map = PluginMgr.GetPlugin("mapper") as Mapper.Mapper; + if(db == null || map == null) + return false; + + int minLevel = CampaignLvl - 5; + int maxLevel = CampaignLvl + 12; + if(CampaignLvl >= 200) + maxLevel = CampaignLvl + 20; + + if(t.Match.Groups[1].Length != 0) + { + minLevel = MyLvl - 20; + maxLevel = MyLvl + 10; + if(GQLvl != 0) + { + minLevel = GQLvl - 6; + maxLevel = GQLvl + 15; + if(GQLvl >= 186) + maxLevel = GQLvl + 21; + } + } + + List Rooms = new List(); + List Areas = new List(); + foreach(Area z in map.Areas) + { + if(z.Name == placeName) + Areas.Add(z.Keyword); + } + + CPEntry e = new CPEntry(); + e.Name = mobName; + e.PlaceName = placeName; + + if(Areas.Count != 0) + { + // Area CP / GQ? + foreach(string a in Areas) + { + foreach(Mob x in db.Mobs) + { + if(x.Level < minLevel || x.Level > maxLevel) + continue; + if(!x.Areas.Contains("all") && !x.Areas.Contains(a)) + continue; + + if(!x.Name.Contains(mobName)) + continue; + + uint roomId = x.GetBestRoom(); + if(roomId == uint.MaxValue) + continue; + + Rooms.Add(roomId); + if(!e.Mobs.Contains(x.Entry)) + e.Mobs.Add(x.Entry); + } + } + } + else + { + List r = new List(); + List p = new List(); + foreach(Room x in map.Rooms) + { + if(x.Name == placeName) + { + r.Add(x.Entry); + if(!p.Contains(x.Area.Keyword)) + p.Add(x.Area.Keyword); + } + } + + foreach(Mob x in db.Mobs) + { + if(x.Level < minLevel || x.Level > maxLevel) + continue; + if(!x.Areas.Contains("all")) + { + bool f = false; + foreach(string z in x.Areas) + { + if(p.Contains(z)) + { + f = true; + break; + } + } + + if(!f) + continue; + } + + if(!x.Name.Contains(mobName)) + continue; + + if(!e.Mobs.Contains(x.Entry)) + e.Mobs.Add(x.Entry); + + uint u = x.GetBestRoom(); + if(u == uint.MaxValue) + continue; + + Room br = map.GetRoom(u); + if(br == null) + continue; + + Pathfinder_Mob pf = new Pathfinder_Mob(x, r.ToArray()); + pf.StartRooms = new[] { br }; + PathfindResult pr = map.Get(pf); + if(pr.Success && pr.Target != null) + u = pr.Target.Entry; + + if(!Rooms.Contains(u)) + Rooms.Add(u); + } + } + + if(t.Match.Groups[1].Length == 0) + e.Count = 1; + else + { + int n; + if(int.TryParse(Colors.RemoveColors(t.Match.Groups[1].Value, false).Trim(), out n)) + { + e.Count = n; + e.IsGQ = true; + } + else + { + e.Count = 1; + e.IsGQ = true; + } + } + + if(e.IsGQ) + Targets[0].Add(e); + else + Targets[1].Add(e); + + StringBuilder strRooms = new StringBuilder(); + foreach(uint u in Rooms) + { + if(strRooms.Length > 0) + strRooms.Append(" "); + strRooms.Append(u); + } + World.Instance.SendMessage("@w{cp_room}" + strRooms); + + UpdateColors(); + return false; + } + + private void UpdateColors() + { + MobDB.MobDB db = PluginMgr.GetPlugin("mobdb") as MobDB.MobDB; + if(db == null) + return; + + db.ClearMobColors(); + if(string.IsNullOrEmpty(Config.GetString("Color.Room", "@C"))) + return; + + if(Targets[0].Count != 0) + { + foreach(CPEntry x in Targets[0]) + { + foreach(uint u in x.Mobs) + db.SetMobColor(u, Config.GetString("Color.Room", "@C")); + } + } + else + { + foreach(CPEntry x in Targets[1]) + { + foreach(uint u in x.Mobs) + db.SetMobColor(u, Config.GetString("Color.Room", "@C")); + } + } + } + + private CPEntry IsSame(List entries, string mobName, string placeName) + { + Mapper.Mapper map = PluginMgr.GetPlugin("mapper") as Mapper.Mapper; + MobDB.MobDB db = PluginMgr.GetPlugin("mobdb") as MobDB.MobDB; + if(map == null || db == null) + return null; + + List areas = new List(); + foreach(Area x in map.Areas) + { + if(x.Name == placeName) + areas.Add(x.Keyword); + } + if(areas.Count == 0) + { + foreach(Room x in map.Rooms) + { + if(x.Name == placeName && !areas.Contains(x.Area.Keyword)) + areas.Add(x.Area.Keyword); + } + } + + foreach(CPEntry x in entries) + { + if(x.Name != mobName) + continue; + + foreach(uint u in x.Mobs) + { + Mob m = db.GetMob(u); + if(m == null) + continue; + + if(!m.Areas.Contains("all")) + { + bool f = false; + foreach(string y in m.Areas) + { + if(areas.Contains(y)) + { + f = true; + break; + } + } + + if(!f) + continue; + } + + return x; + } + } + + return null; + } + } + + public class Pathfinder_Mob : Pathfinder_Entry + { + public Pathfinder_Mob(Mob m, params uint[] roomId) + : base(roomId) + { + mob = m; + CanUsePortals = false; + CanUseRecalls = false; + CharacterLevel = m.Level; + CharacterTier = 0; + IsGlobalQuest = false; + IsSingleClassTier0 = false; + } + + private Mob mob; + private static string[] Normals = new[] { "n", "e", "s", "w", "u", "d" }; + + public override bool CanUseExit(Exit e) + { + if(!Normals.Contains(e.Command)) + return false; + + if(!mob.Areas.Contains("all") && !mob.Areas.Contains(e.To.Area.Keyword)) + return false; + + return base.CanUseExit(e); + } + } + + public class CPHelperConfig : ConfigFile + { + protected override void OnCreated() + { + base.OnCreated(); + + CreateSetting("Tags.On", 1, "Display tags on campaign / gq check messages for easier capture. If you turn tags off then room IDs will still be displayed if we find a mob in database."); + CreateSetting("Tags.Scan.Gag", 1, "Gag {scan} tags."); + CreateSetting("Color.Room", "@C", "Color campaign / gq mobs differently (the $mob.color value) when we have a CP / GQ mob target. Enter empty value to skip this. Mob has to be in database for this to work."); + CreateSetting("Color.Scan", "@R", "Color campaign / gq mobs differently when scanning. Enter empty value to skip this. You need to have \"tags scan on\" for this to work. Mob has to be in database for this to work."); + } + } + + internal class CPEntry + { + internal bool IsGQ = false; + internal string Name; + internal int Count; + internal string PlaceName; + internal List Mobs = new List(); + } +} diff --git a/CPHelper/.svn/text-base/CPHelper.csproj.svn-base b/CPHelper/.svn/text-base/CPHelper.csproj.svn-base new file mode 100644 index 0000000..7f0290f --- /dev/null +++ b/CPHelper/.svn/text-base/CPHelper.csproj.svn-base @@ -0,0 +1,71 @@ + + + + Debug + AnyCPU + 9.0.30729 + 2.0 + {11D11063-A123-4F02-9C20-FB76C49A4B52} + Library + Properties + CPHelper + CPHelper + v3.5 + 512 + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + False + ..\Mapper\bin\Release\Mapper.dll + + + False + ..\MobDB\bin\Release\MobDB.dll + + + False + ..\ProxyCore\bin\ProxyCore.dll + + + + 3.5 + + + 3.5 + + + 3.5 + + + + + + + + + + + \ No newline at end of file diff --git a/CPHelper/.svn/text-base/desktop.ini b/CPHelper/.svn/text-base/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/CPHelper/.svn/text-base/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/CPHelper/.svn/tmp/desktop.ini b/CPHelper/.svn/tmp/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/CPHelper/.svn/tmp/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/CPHelper/.svn/tmp/prop-base/desktop.ini b/CPHelper/.svn/tmp/prop-base/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/CPHelper/.svn/tmp/prop-base/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/CPHelper/.svn/tmp/props/desktop.ini b/CPHelper/.svn/tmp/props/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/CPHelper/.svn/tmp/props/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/CPHelper/.svn/tmp/text-base/desktop.ini b/CPHelper/.svn/tmp/text-base/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/CPHelper/.svn/tmp/text-base/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/CPHelper/CPHelper.cs b/CPHelper/CPHelper.cs new file mode 100644 index 0000000..7429a2f --- /dev/null +++ b/CPHelper/CPHelper.cs @@ -0,0 +1,1342 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; +using Mapper; +using MobDB; +using ProxyCore; +using ProxyCore.Input; +using ProxyCore.Output; +using ProxyCore.Scripting; + +namespace CPHelper +{ + public class CPHelper : Plugin + { + public CPHelper() + : base("cphelper", "Campaign Helper") + { + Author = "Duckbat"; + Version = 5; + Description = "Matches mobs from database to rooms. Creates useful tags for campaign check."; + UpdateUrl = "www.duckbat.com/plugins/update.cphelper.txt"; + Website = "code.google.com/p/proxymud/"; + + Config = new CPHelperConfig(); + + RegisterCommand("autonoexp", @"^(\d+)", AutoNoexpCommand); + RegisterCommand("gowhere", "", GoWhereCommand, 3); + RegisterCommand("where", "(.+)", WhereCommand, 3); + RegisterCommand("gquest", "(.+)", GQCheckCommand, 2); + RegisterCommand("campaign", "(.+)", CampaignCheckCommand, 5); + RegisterCommand("cp", "(.+)", CampaignCheckCommand, 0); + RegisterCommand("awhere", "(.+)", AutoWhereCommand, 2); + RegisterCommand("ahunttrick", "(.+)", AutoHuntTrickCommand, 2); + RegisterCommand("hunt", "(.+)", HuntCommand, 2); + RegisterCommand("astop", "", AutoStopCommand, 2); + + RegisterTrigger("gq.quit", @"@wYou are no longer part of the current quest.", TriggerGQLevel2, TriggerFlags.NotRegex); + RegisterTrigger("hunt.target", @"@wYou seem unable to hunt that target for some reason.", TriggerHuntT, TriggerFlags.NotRegex); + RegisterTrigger("hunt.fail1", @"@wNo one in this area by that name.", TriggerHuntFail, TriggerFlags.NotRegex); + RegisterTrigger("hunt.fail2", @"^@wYou couldn't find a path to .+from here\.$", TriggerHuntNT); + RegisterTrigger("hunt.fail3", @"(.+?)is here!$", TriggerHuntFail); + RegisterTrigger("hunt.nottarget", @"^@wYou are confident that .+passed through here, heading \w+\.$", TriggerHuntNT); + RegisterTrigger("hunt.nottarget2", @"^@wYou have no idea what you're doing, but maybe .+left .+\?$", TriggerHuntNT); + RegisterTrigger("hunt.nottarget3", @"^@wYou are almost certain that .+is .+from here\.$", TriggerHuntNT); + RegisterTrigger("hunt.nottarget4", @"^@wThe trail of .+is confusing, but you're reasonable sure .+headed .+\.$", TriggerHuntNT); + RegisterTrigger("hunt.nottarget5", @"^@wThere are traces of .+having been here\. Perhaps they lead .+\?$", TriggerHuntNT); + RegisterTrigger("hunt.nottarget6", @"^@wYou are certain that .+is .+from here\.$", TriggerHuntNT); + RegisterTrigger("where.fail1", @"@wThere are too many doors and fences to see who is in this area.", TriggerWhereFail, TriggerFlags.NotRegex); + RegisterTrigger("where.fail2", @"^@wThere is no .+around here\.$", TriggerWhereFail); + RegisterTrigger("quest0", @"^\$gmcp\.comm\.quest\.action start$", TriggerQuest0); + RegisterTrigger("quest1", @"^\$gmcp\.comm\.quest\.room (.+)", TriggerQuest2); + RegisterTrigger("quest2", @"^\$gmcp\.comm\.quest\.area (.+)", TriggerQuest3); + RegisterTrigger("quest3", @"^\$gmcp\.comm\.quest\.targ (.+)", TriggerQuest1); + RegisterTrigger("enterroom", @"^\$gmcp\.room\.info\.num (-?\d+)$", TriggerRoomNum); + RegisterTrigger("check", @"^@wYou still have to kill (@c\d @w)?\* (.+?) (@w)?\((.+?)(@w)?\)$", TriggerCheck); + RegisterTrigger("char.level", @"^\$gmcp\.char\.status\.level (\d+)$", TriggerLevel); + RegisterTrigger("char.tnl", @"^\$gmcp\.char\.status\.tnl (\d+)$", TriggerTNL); + RegisterTrigger("request", @"^@.Commander Barcett tells you 'Good luck in your campaign!'$", TriggerRequest); + RegisterTrigger("cplevel", @"^@cLevel Taken\.\.\.\.\.\.\.\.: @g\[ \s+@w(\d+) @g\]$", TriggerCPLevel); + RegisterTrigger("gqlevel", @"^@RGlobal Quest@Y: @gGlobal quest # \d+ @whas been declared for levels @g(\d+) @wto @g(\d+)@w\.$", TriggerGQLevel); + RegisterTrigger("gqlevel2", @"^@RGlobal Quest@Y: @wThe global quest has been won by @Y\w+ @w- @Y\d+(st|th|rd|nd) @wwin\.$", TriggerGQLevel2); + RegisterTrigger("noexp1", @"@RYou will no longer receive experience. Happy questing!", NoexpTrigger1, TriggerFlags.NotRegex); + RegisterTrigger("noexp2", @"@wYou will now receive experience. Happy leveling!", NoexpTrigger2, TriggerFlags.NotRegex); + RegisterTrigger("cpcomplete", @"@GCONGRATULATIONS! @wYou have completed your campaign.", TriggerCPComplete, TriggerFlags.NotRegex); + RegisterTrigger("cpfail", "@wCampaign cleared.", TriggerCPComplete, TriggerFlags.NotRegex); + RegisterTrigger("scan1", "@w{scan}", TriggerScan1, TriggerFlags.NotRegex); + RegisterTrigger("scan0", "@w{/scan}", TriggerScan0, TriggerFlags.NotRegex); + RegisterTrigger("scan2", "^ @w- (.+)", TriggerScan2); + RegisterTrigger("scan.room", @"^@C(\d )?(North|East|West|South|Down|Up) from here you see:", TriggerScanRoom); + RegisterTrigger("scan.room2", @"^@CRight here you see:", TriggerScanRoom2); + RegisterTrigger("enemy", @"^$gmcp\.char\.status\.enemy(.*)", TriggerCurrentEnemy); + RegisterTrigger("cp.kill", @"@WCongratulations, that was one of your CAMPAIGN mobs!", TriggerOnKilled1, TriggerFlags.NotRegex); + RegisterTrigger("gq.kill", @"@RCongratulations, that was one of the GLOBAL QUEST mobs!", TriggerOnKilled0, TriggerFlags.NotRegex); + RegisterTrigger("room.area", @"^\$gmcp\.room\.info\.zone (.*)$", TriggerRoomInfoArea); + RegisterTrigger("where", @"^(.{28}) (.+)", TriggerWhere, TriggerFlags.NonAnsi); + } + + private uint CurrentRoomId = uint.MaxValue; + private bool AllowScan = false; + private int MyLvl = 0; + private int MyXP = 99999; + private int CampaignLvl = 0; + private int GQLvl = 0; + private long Spam = 0; + private bool IsNoexp = false; + private int AutoNoexp = 0; + private bool didEnter = false; + private readonly List[] Targets = new[] { new List(), new List() }; + private string CurEnemy = ""; + private string RoomInfoArea = ""; + private long WhereTimeout = 0; + private long HuntTimeout = 0; + private readonly List WhereRooms = new List(); + private uint FirstWhereRoom = uint.MaxValue; + private readonly List ScanRooms = new List(); + private uint CurScanRoom = uint.MaxValue; + private string QuestTarget = string.Empty; + private string QuestRoom = string.Empty; + private string QuestArea = string.Empty; + private bool QuestListen = false; + + private int AutoWhereNth = 1; + private string AutoWhereKey = string.Empty; + private int AutoHuntNth = 1; + private string AutoHuntKey = string.Empty; + + private bool TriggerHuntT(TriggerData t) + { + World.Instance.Execute("where " + AutoHuntNth + "." + AutoHuntKey, true); + AutoHuntKey = string.Empty; + AutoHuntNth = 1; + return false; + } + + private bool TriggerHuntNT(TriggerData t) + { + HuntTimeout = 0; + AutoHuntNth++; + return false; + } + + private bool TriggerWhereFail(TriggerData t) + { + AutoWhereKey = string.Empty; + AutoWhereNth = 1; + WhereTimeout = 0; + return false; + } + + private bool TriggerHuntFail(TriggerData t) + { + AutoHuntKey = string.Empty; + AutoHuntNth = 1; + HuntTimeout = 0; + return false; + } + + private bool AutoStopCommand(InputData i) + { + AutoWhereKey = string.Empty; + AutoHuntKey = string.Empty; + return true; + } + + private bool AutoWhereCommand(InputData i) + { + string arg; + if(!i.Arguments.Success || (arg = i.Arguments.Groups[1].Value.Trim()).Length == 0) + { + World.Instance.SendMessage("@wSyntax: awhere ", i.ClientMask); + return true; + } + + WhereTimeout = 0; + Match m = _argRegex.Match(arg); + if(m.Success) + { + AutoWhereKey = m.Groups[2].Value; + if(!int.TryParse(m.Groups[1].Value, out AutoWhereNth)) + AutoWhereNth = 1; + } + else + { + AutoWhereNth = 1; + AutoWhereKey = arg; + } + return true; + } + + private bool AutoHuntTrickCommand(InputData i) + { + string arg; + if(!i.Arguments.Success || (arg = i.Arguments.Groups[1].Value.Trim()).Length == 0) + { + World.Instance.SendMessage("@wSyntax: ahunttrick ", i.ClientMask); + return true; + } + + HuntTimeout = 0; + Match m = _argRegex.Match(arg); + if(m.Success) + { + AutoHuntKey = m.Groups[2].Value; + if(!int.TryParse(m.Groups[1].Value, out AutoHuntNth)) + AutoHuntNth = 1; + } + else + { + AutoHuntNth = 1; + AutoHuntKey = arg; + } + return true; + } + + private static Regex _argRegex = new Regex(@"^(\d+)\.(.+)", RegexOptions.Compiled); + + private bool TriggerQuest0(TriggerData t) + { + QuestListen = true; + return false; + } + + private bool TriggerQuest1(TriggerData t) + { + if(!QuestListen) + return false; + + QuestTarget = MobDB.MobDB.NormalizeName(t.Match.Groups[1].Value.Trim()); + return false; + } + + private bool TriggerQuest2(TriggerData t) + { + if(!QuestListen) + return false; + + QuestRoom = t.Match.Groups[1].Value.Trim(); + return false; + } + + private bool TriggerQuest3(TriggerData t) + { + if(!QuestListen) + return false; + + QuestListen = false; + QuestArea = t.Match.Groups[1].Value.Trim(); + + int minLevel = MyLvl - 8; + int maxLevel = MyLvl + 10; + if(MyLvl >= 200) + maxLevel = MyLvl + 20; + + uint bestMobRoom = uint.MaxValue; + MobDB.MobDB db = PluginMgr.GetPlugin("mobdb") as MobDB.MobDB; + Mapper.Mapper map = PluginMgr.GetPlugin("mapper") as Mapper.Mapper; + List Areas = new List(); + List Rooms = new List(); + foreach(Area x in map.Areas) + { + if(x.Name == QuestArea) + Areas.Add(x.Keyword); + } + foreach(Room r in map.Rooms) + { + if(r.Area.Name != QuestArea) + continue; + + if(r.Name != QuestRoom) + continue; + + Rooms.Add(r.Entry); + } + foreach(Mob m in db.Mobs) + { + if(m.Level < minLevel || m.Level > maxLevel) + continue; + + if(!m.Name.Contains(QuestTarget)) + continue; + + if(!m.Areas.Contains("all")) + { + bool f = false; + foreach(string x in m.Areas) + { + if(Areas.Contains(x)) + { + f = true; + break; + } + } + + if(!f) + continue; + } + + bestMobRoom = m.GetBestRoom(); + if(bestMobRoom == uint.MaxValue) + continue; + + Room br = map.GetRoom(bestMobRoom); + if(br != null) + { + Pathfinder_Mob pf = new Pathfinder_Mob(m, Rooms.ToArray()); + pf.StartRooms = new[] { br }; + PathfindResult pr = map.Get(pf); + if(!pr.Success || pr.Target == null) + { + bestMobRoom = uint.MaxValue; + continue; + } + + bestMobRoom = pr.Target.Entry; + break; + } + } + + + if(Rooms.Count != 0) + { + WhereRooms.Clear(); + WhereRooms.AddRange(Rooms); + FirstWhereRoom = bestMobRoom; + World.Instance.SendMessage("@wAdded @C" + Rooms.Count + " @wroom" + (Rooms.Count != 1 ? "s" : "") + " to @G\"where\" @wlist. Use '@Wgowhere@w' to visit them."); + } + + return false; + } + + private bool TriggerScanRoom(TriggerData t) + { + CurScanRoom = uint.MaxValue; + int c = 1; + if(t.Match.Groups[1].Length != 0) + int.TryParse(t.Match.Groups[1].Value, out c); + char d = t.Match.Groups[2].Value.ToLower()[0]; + + Mapper.Mapper map = PluginMgr.GetPlugin("mapper") as Mapper.Mapper; + if(map == null) + return false; + + Room r = map.GetRoom(CurrentRoomId); + if(r == null) + return false; + + for(int i = 0; i < c; i++) + { + Exit e = r.GetExit(d); + if(e == null) + return false; + + r = e.To; + } + + if(string.IsNullOrEmpty(r.Name)) + return false; + + CurScanRoom = r.Entry; + return false; + } + + private bool TriggerScanRoom2(TriggerData t) + { + CurScanRoom = CurrentRoomId; + return false; + } + + private bool GQCheckCommand(InputData i) + { + if(i.Arguments.Success && i.Arguments.Groups[1].Length <= 5 && + "check".StartsWith(i.Arguments.Groups[1].Value.ToLower())) + Targets[0].Clear(); + return false; + } + + private bool CampaignCheckCommand(InputData i) + { + if(i.Arguments.Success && i.Arguments.Groups[1].Length <= 5 && + "check".StartsWith(i.Arguments.Groups[1].Value.ToLower())) + Targets[1].Clear(); + return false; + } + + private bool TriggerRoomNum(TriggerData t) + { + uint u; + if(uint.TryParse(t.Match.Groups[1].Value, out u)) + { + CurrentRoomId = u; + if(FirstWhereRoom == u) + FirstWhereRoom = uint.MaxValue; + if(WhereRooms.Remove(u)) + World.Instance.SendMessage("@wEntered a @G\"where\" @wroom. Now have @C" + WhereRooms.Count + " @wroom" + (WhereRooms.Count != 1 ? "s" : "") + " remaining. Use '@Wgowhere@w' to go to the next one."); + } + else + CurrentRoomId = uint.MaxValue; + return false; + } + + private bool TriggerWhere(TriggerData t) + { + if(WhereTimeout < World.Instance.MSTime) + return false; + + Mapper.Mapper map = PluginMgr.GetPlugin("mapper") as Mapper.Mapper; + if(map == null) + return false; + + string rName = t.Match.Groups[2].Value.Trim(); + + List r = new List(); + foreach(Room x in map.Rooms) + { + if(x.Area.Keyword == RoomInfoArea && x.Name == rName) + r.Add(x); + } + + string mobName = t.Match.Groups[1].Value.Trim(); + mobName = MobDB.MobDB.NormalizeName(mobName); + + if(!string.IsNullOrEmpty(AutoWhereKey)) + { + if(Targets[0].Count != 0) + { + foreach(CPEntry x in Targets[0]) + { + if(x.Name.StartsWith(mobName)) + { + AutoWhereKey = string.Empty; + break; + } + } + } + else + { + foreach(CPEntry x in Targets[1]) + { + if(x.Name.StartsWith(mobName)) + { + AutoWhereKey = string.Empty; + break; + } + } + + if(QuestTarget.StartsWith(mobName)) + AutoWhereKey = string.Empty; + } + } + + if(r.Count == 0) + return false; + + WhereRooms.Clear(); + FirstWhereRoom = uint.MaxValue; + WhereTimeout = 0; + foreach(Room x in r) + { + if(CurrentRoomId != x.Entry) + WhereRooms.Add(x.Entry); + } + + if(WhereRooms.Count == 0) + return false; + + World.Instance.SendMessage("@wAdded @C" + WhereRooms.Count + " @wroom" + (WhereRooms.Count != 1 ? "s" : "") + " to @G\"where\"@w. Type '@Wgowhere@w' to go there."); + MobDB.MobDB db = PluginMgr.GetPlugin("mobdb") as MobDB.MobDB; + if(db == null) + return false; + + foreach(Mob m in db.Mobs) + { + if(!m.Areas.Contains("all") && !m.Areas.Contains(RoomInfoArea)) + continue; + + bool f = false; + foreach(string z in m.Name) + { + if(mobName.Length >= 26) + { + if(z.StartsWith(mobName)) + { + f = true; + break; + } + } + else if(z == mobName) + { + f = true; + break; + } + } + + if(!f) + continue; + + uint b = m.GetBestRoom(); + if(b == uint.MaxValue || b == CurrentRoomId) + continue; + + Room br = map.GetRoom(b); + if(br == null || br.Entry == CurrentRoomId) + continue; + + if(WhereRooms.Contains(b)) + FirstWhereRoom = b; + else + { + Pathfinder_Mob pf = new Pathfinder_Mob(m, WhereRooms.ToArray()); + pf.StartRooms = new[] { br }; + + PathfindResult pr = map.Get(pf); + if(pr.Success && pr.Target != null) + FirstWhereRoom = pr.Target.Entry; + } + + break; + } + + return false; + } + + private bool WhereCommand(InputData i) + { + if(i.Arguments.Success && i.Arguments.Groups[1].Value.Trim().Length > 0) + WhereTimeout = World.Instance.MSTime + 6000; + return false; + } + + private bool HuntCommand(InputData i) + { + if(i.Arguments.Success && i.Arguments.Groups[1].Value.Trim().Length > 0) + HuntTimeout = World.Instance.MSTime + 6000; + return false; + } + + private bool GoWhereCommand(InputData i) + { + if(WhereRooms.Count == 0) + World.Instance.SendMessage("@wThere are no where rooms available.", i.ClientMask); + else + { + Mapper.Mapper map = PluginMgr.GetPlugin("mapper") as Mapper.Mapper; + if(map == null) + { + World.Instance.SendMessage("@wInternal error.", i.ClientMask); + return true; + } + + Pathfinder_Entry pf = new Pathfinder_Entry(FirstWhereRoom != uint.MaxValue ? new[] { FirstWhereRoom } : WhereRooms.ToArray()); + map.FillPathFinder(pf); + PathfindResult pr = map.Get(pf); + if(!pr.Success) + World.Instance.SendMessage("@wCouldn't find a path to any of the where rooms.", i.ClientMask); + else + map.Goto(pr); + } + return true; + } + + public override void OnLogin() + { + base.OnLogin(); + + RegisterCommand("goto", @"(.+)", GotoMobCommand, 2, CMDFlags.None, "mobdb"); + } + + private bool GotoMobCommand(InputData i) + { + if(string.IsNullOrEmpty(RoomInfoArea)) + { + World.Instance.SendMessage("@wDon't know yet which area we are in. Type look to find out.", i.ClientMask); + return true; + } + + if(!i.Arguments.Success) + { + World.Instance.SendMessage("@wSyntax: mobdb goto ", i.ClientMask); + return true; + } + + MobDB.MobDB db = PluginMgr.GetPlugin("mobdb") as MobDB.MobDB; + if(db == null) + { + World.Instance.SendMessage("@wInternal error.", i.ClientMask); + return true; + } + + List toGoRooms = new List(); + string name = i.Arguments.Groups[1].Value.ToLower(); + foreach(Mob m in db.Mobs) + { + if(!m.Areas.Contains("all") && !m.Areas.Contains(RoomInfoArea)) + continue; + + uint p = m.GetBestRoom(); + if(p == uint.MaxValue) + continue; + + foreach(string z in m.Name) + { + if(z.ToLower().Contains(name)) + { + if(!toGoRooms.Contains(p)) + toGoRooms.Add(p); + break; + } + } + } + + if(toGoRooms.Count == 0) + { + World.Instance.SendMessage("@wFound no mobs with that name in current area.", i.ClientMask); + return true; + } + + Mapper.Mapper map = PluginMgr.GetPlugin("mapper") as Mapper.Mapper; + if(map == null) + { + World.Instance.SendMessage("@wInternal error.", i.ClientMask); + return true; + } + + Pathfinder_Entry pf = new Pathfinder_Entry(toGoRooms.ToArray()); + if(!map.FillPathFinder(pf)) + { + World.Instance.SendMessage("@wWe are in an unknown room.", i.ClientMask); + return true; + } + + PathfindResult pr = map.Get(pf); + if(!pr.Success) + { + World.Instance.SendMessage("@wCouldn't find a path to any of the mobs with that name.", i.ClientMask); + return true; + } + + map.Goto(pr); + return true; + } + + private bool TriggerRoomInfoArea(TriggerData t) + { + RoomInfoArea = t.Match.Groups[1].Value.Trim(); + return false; + } + + private bool TriggerOnKilled0(TriggerData t) + { + if(string.IsNullOrEmpty(CurEnemy)) + return false; + + MobDB.MobDB db = PluginMgr.GetPlugin("mobdb") as MobDB.MobDB; + if(db == null) + return false; + + CurEnemy = MobDB.MobDB.NormalizeName(CurEnemy); + + for(int i = 0; i < Targets[0].Count; i++) + { + CPEntry x = Targets[0][i]; + + if(x.Name != CurEnemy) + continue; + + foreach(uint u in x.Mobs) + { + Mob m = db.GetMob(u); + if(m == null) + continue; + + if(!m.Areas.Contains("all") && !m.Areas.Contains(RoomInfoArea)) + continue; + + if(m.Name.Contains(CurEnemy)) + { + if(x.Count > 1) + { + x.Count--; + return false; + } + + Targets[0].RemoveAt(i); + UpdateColors(); + return false; + } + } + } + + return false; + } + + private bool TriggerOnKilled1(TriggerData t) + { + if(string.IsNullOrEmpty(CurEnemy)) + return false; + + MobDB.MobDB db = PluginMgr.GetPlugin("mobdb") as MobDB.MobDB; + if(db == null) + return false; + + CurEnemy = MobDB.MobDB.NormalizeName(CurEnemy); + + for(int i = 0; i < Targets[1].Count; i++) + { + CPEntry x = Targets[1][i]; + + if(x.Name != CurEnemy) + continue; + + foreach(uint u in x.Mobs) + { + Mob m = db.GetMob(u); + if(m == null) + continue; + + if(!m.Areas.Contains("all") && !m.Areas.Contains(RoomInfoArea)) + continue; + + if(m.Name.Contains(CurEnemy)) + { + if(x.Count > 1) + { + x.Count--; + return false; + } + + Targets[1].RemoveAt(i); + UpdateColors(); + return false; + } + } + } + + return false; + } + + private bool TriggerCurrentEnemy(TriggerData t) + { + CurEnemy = Colors.RemoveColors(t.Match.Groups[1].Value, false).Trim(); + return false; + } + + private bool TriggerScan0(TriggerData t) + { + AllowScan = false; + if(Config.GetInt32("Tags.Scan.Gag", 1) != 0) + t.Msg.AuthMask = 0; + + StringBuilder strScan = new StringBuilder(); + foreach(uint u in ScanRooms) + { + if(strScan.Length > 0) + strScan.Append(" "); + strScan.Append(u); + } + World.Instance.SendMessage("@w{scan_rooms}" + strScan); + return false; + } + + private bool TriggerScan1(TriggerData t) + { + ScanRooms.Clear(); + AllowScan = true; + if(Config.GetInt32("Tags.Scan.Gag", 1) != 0) + t.Msg.AuthMask = 0; + return false; + } + + private bool TriggerScan2(TriggerData td) + { + if(!AllowScan) + return false; + + if(Targets[0].Count == 0 && Targets[1].Count == 0) + return false; + + MobDB.MobDB db = PluginMgr.GetPlugin("mobdb") as MobDB.MobDB; + if(db == null) + return false; + + string t = Colors.RemoveDuplicateColors("@w" + td.Match.Groups[1].Value); + if(t.StartsWith("@R(Wounded)")) + t = Colors.RemoveDuplicateColors("@R" + t.Substring("@R(Wounded)".Length)).Trim(); + + if(t.StartsWith("@w(Invis)")) + t = Colors.RemoveDuplicateColors("@w" + t.Substring("@w(Invis)".Length)).Trim(); + else if(t.StartsWith("@w(I)")) + t = Colors.RemoveDuplicateColors("@w" + t.Substring("@w(I)".Length)).Trim(); + + if(t.StartsWith("@w(Hidden)")) + t = Colors.RemoveDuplicateColors("@w" + t.Substring("@w(Hidden)".Length)).Trim(); + else if(t.StartsWith("@w(H)")) + t = Colors.RemoveDuplicateColors("@w" + t.Substring("@w(H)".Length)).Trim(); + + if(t.StartsWith("@W(Translucent)")) + t = Colors.RemoveDuplicateColors("@W" + t.Substring("@W(Translucent)".Length)).Trim(); + else if(t.StartsWith("@W(T)")) + t = Colors.RemoveDuplicateColors("@W" + t.Substring("@W(T)".Length)).Trim(); + + if(t.StartsWith("@C(Charmed) ")) + return false; + else if(t.StartsWith("@C(C)")) + return false; + + if(t.StartsWith("@M(Animated) ")) + return false; + else if(t.StartsWith("@M(A)")) + return false; + + if(t.StartsWith("@B(Diseased)")) + t = Colors.RemoveDuplicateColors("@B" + t.Substring("@B(Diseased)".Length)).Trim(); + else if(t.StartsWith("@B(D)")) + t = Colors.RemoveDuplicateColors("@B" + t.Substring("@B(D)".Length)).Trim(); + + if(t.StartsWith("@D(Marked)")) + t = Colors.RemoveDuplicateColors("@D" + t.Substring("@D(Marked)".Length)).Trim(); + else if(t.StartsWith("@D(X)")) + t = Colors.RemoveDuplicateColors("@D" + t.Substring("@D(X)".Length)).Trim(); + + if(t.StartsWith("@r(Red Aura)")) + t = Colors.RemoveDuplicateColors("@r" + t.Substring("@r(Red Aura)".Length)).Trim(); + else if(t.StartsWith("@r(R)")) + t = Colors.RemoveDuplicateColors("@r" + t.Substring("@r(R)".Length)).Trim(); + else if(t.StartsWith("@y(Golden Aura)")) + t = Colors.RemoveDuplicateColors("@y" + t.Substring("@y(Golden Aura)".Length)).Trim(); + else if(t.StartsWith("@y(G)")) + t = Colors.RemoveDuplicateColors("@y" + t.Substring("@y(G)".Length)).Trim(); + + if(t.StartsWith("@W(White Aura)")) + t = Colors.RemoveDuplicateColors("@W" + t.Substring("@W(White Aura)".Length)).Trim(); + else if(t.StartsWith("@W(W)")) + t = Colors.RemoveDuplicateColors("@W" + t.Substring("@W(W)".Length)).Trim(); + + if(t.StartsWith("@R(Angry)")) + t = Colors.RemoveDuplicateColors("@R" + t.Substring("@R(Angry)".Length)).Trim(); + + if(t.StartsWith("@w(Linkdead)")) + return false; + + if(t.StartsWith("@R(RAIDER)")) + return false; + + if(t.StartsWith("@R(TRAITOR)")) + return false; + + if(t.StartsWith("@G(DEFENDER)")) + return false; + + if(t.StartsWith("@R(WANTED)")) + return false; + + Mapper.Mapper map = PluginMgr.GetPlugin("mapper") as Mapper.Mapper; + if(map == null) + return false; + + string n = Colors.RemoveColors(t, false).ToLower().Trim(); + if(t.StartsWith("@") && !t.StartsWith("@@") && t.Length >= 2) + t = t.Substring(2); + if(Targets[0].Count != 0) + { + foreach(CPEntry x in Targets[0]) + { + if(x.Name.ToLower() != n) + continue; + + int ind = td.Msg.Msg.LastIndexOf(t); + if(ind != -1) + { + td.Msg.Msg = td.Msg.Msg.Remove(ind); + td.Msg.Msg = td.Msg.Msg.Insert(ind, Config.GetString("Color.Scan", "@R") + x.Name); + } + + if(CurScanRoom != uint.MaxValue && !ScanRooms.Contains(CurScanRoom)) + ScanRooms.Add(CurScanRoom); + + return false; + } + } + else + { + foreach(CPEntry x in Targets[1]) + { + if(x.Name.ToLower() == n) + { + int ind = td.Msg.Msg.LastIndexOf(t); + if(ind != -1) + { + td.Msg.Msg = td.Msg.Msg.Remove(ind); + td.Msg.Msg = td.Msg.Msg.Insert(ind, Config.GetString("Color.Scan", "@R") + x.Name); + } + + if(CurScanRoom != uint.MaxValue && !ScanRooms.Contains(CurScanRoom)) + ScanRooms.Add(CurScanRoom); + + return false; + } + } + } + + return false; + } + + private bool TriggerCPComplete(TriggerData t) + { + Targets[1].Clear(); + UpdateColors(); + return false; + } + + private bool NoexpTrigger1(TriggerData t) + { + IsNoexp = true; + didEnter = false; + return false; + } + + private bool NoexpTrigger2(TriggerData t) + { + IsNoexp = false; + didEnter = false; + return false; + } + + public override void Update(long msTime) + { + base.Update(msTime); + + if(!string.IsNullOrEmpty(AutoWhereKey)) + { + if(WhereTimeout > msTime) + return; + if(WhereTimeout != 0) + AutoWhereKey = string.Empty; + else + { + World.Instance.Execute("where " + AutoWhereNth + "." + AutoWhereKey, true); + AutoWhereNth++; + return; + } + } + + if(!string.IsNullOrEmpty(AutoHuntKey)) + { + if(HuntTimeout > msTime) + return; + if(HuntTimeout != 0) + AutoHuntKey = string.Empty; + else + { + World.Instance.Execute("hunt " + AutoHuntNth + "." + AutoHuntKey, true); + return; + } + } + + if(didEnter) + return; + + if(AutoNoexp == 0) + return; + + bool shouldNoExp = MyLvl > CampaignLvl && MyXP <= AutoNoexp; + if(shouldNoExp) + { + if(IsNoexp) + return; + } + else + { + if(!IsNoexp) + return; + } + + World.Instance.Execute("noexp", true); + didEnter = true; + } + + private bool AutoNoexpCommand(InputData t) + { + int n; + if(!t.Arguments.Success || !int.TryParse(t.Arguments.Groups[1].Value, out n)) + { + World.Instance.SendMessage("@wSyntax: autonoexp ", t.ClientMask); + return true; + } + + if(n <= 0) + { + AutoNoexp = 0; + World.Instance.SendMessage("@wYou will no longer turn noexp on automatically.", t.ClientMask); + return true; + } + + AutoNoexp = n; + World.Instance.SendMessage("@wYou will now turn noexp on when you can ask a campaign and XP goes to @C" + n + " @wor below.", t.ClientMask); + World.Instance.SendMessage("@wUse '@Wautonoexp 0@w' to turn this off.", t.ClientMask); + return true; + } + + private bool TriggerGQLevel(TriggerData t) + { + Targets[0].Clear(); + int lvl; + if(int.TryParse(t.Match.Groups[1].Value, out lvl)) + GQLvl = lvl; + UpdateColors(); + return false; + } + + private bool TriggerGQLevel2(TriggerData t) + { + Targets[0].Clear(); + GQLvl = 0; + UpdateColors(); + return false; + } + + private bool TriggerCPLevel(TriggerData t) + { + int lvl; + if(int.TryParse(t.Match.Groups[1].Value, out lvl)) + CampaignLvl = lvl; + return false; + } + + private bool TriggerRequest(TriggerData t) + { + CampaignLvl = MyLvl; + return false; + } + + private bool TriggerLevel(TriggerData t) + { + int lvl; + if(int.TryParse(t.Match.Groups[1].Value, out lvl)) + MyLvl = lvl; + return false; + } + + private bool TriggerTNL(TriggerData t) + { + int lvl; + if(int.TryParse(t.Match.Groups[1].Value, out lvl)) + MyXP = lvl; + return false; + } + + private bool TriggerCheck(TriggerData t) + { + string mobName = MobDB.MobDB.NormalizeName(Colors.RemoveColors(t.Match.Groups[2].Value, false).Trim()); + string placeName = Colors.RemoveColors(t.Match.Groups[4].Value, false).Trim(); + if(placeName.EndsWith(" - Dead")) + placeName = placeName.Substring(0, placeName.LastIndexOf(" - Dead")); + + if(Config.GetInt32("Tags.On", 1) != 0) + { + World.Instance.SendMessage("@w{cp_mob}" + mobName); + World.Instance.SendMessage("@w{cp_place}" + placeName); + } + + if(CampaignLvl == 0 && t.Match.Groups[1].Length == 0) + { + if(Spam < World.Instance.MSTime) + { + Spam = World.Instance.MSTime + 300; + World.Instance.SendMessage("@WPlease see '@Rcampaign info@W' first! I need the level to check for mobs."); + } + return false; + } + + MobDB.MobDB db = PluginMgr.GetPlugin("mobdb") as MobDB.MobDB; + Mapper.Mapper map = PluginMgr.GetPlugin("mapper") as Mapper.Mapper; + if(db == null || map == null) + return false; + + int minLevel = CampaignLvl - 5; + int maxLevel = CampaignLvl + 12; + if(CampaignLvl >= 200) + maxLevel = CampaignLvl + 20; + + if(t.Match.Groups[1].Length != 0) + { + minLevel = MyLvl - 20; + maxLevel = MyLvl + 10; + if(GQLvl != 0) + { + minLevel = GQLvl - 6; + maxLevel = GQLvl + 15; + if(GQLvl >= 186) + maxLevel = GQLvl + 21; + } + } + + List Rooms = new List(); + List Areas = new List(); + foreach(Area z in map.Areas) + { + if(z.Name == placeName) + Areas.Add(z.Keyword); + } + + CPEntry e = new CPEntry(); + e.Name = mobName; + e.PlaceName = placeName; + + if(Areas.Count != 0) + { + // Area CP / GQ? + foreach(string a in Areas) + { + foreach(Mob x in db.Mobs) + { + if(x.Level < minLevel || x.Level > maxLevel) + continue; + if(!x.Areas.Contains("all") && !x.Areas.Contains(a)) + continue; + + if(!x.Name.Contains(mobName)) + continue; + + uint roomId = x.GetBestRoom(); + if(roomId == uint.MaxValue) + continue; + + Rooms.Add(roomId); + if(!e.Mobs.Contains(x.Entry)) + e.Mobs.Add(x.Entry); + } + } + } + else + { + List r = new List(); + List p = new List(); + foreach(Room x in map.Rooms) + { + if(x.Name == placeName) + { + r.Add(x.Entry); + if(!p.Contains(x.Area.Keyword)) + p.Add(x.Area.Keyword); + } + } + + foreach(Mob x in db.Mobs) + { + if(x.Level < minLevel || x.Level > maxLevel) + continue; + if(!x.Areas.Contains("all")) + { + bool f = false; + foreach(string z in x.Areas) + { + if(p.Contains(z)) + { + f = true; + break; + } + } + + if(!f) + continue; + } + + if(!x.Name.Contains(mobName)) + continue; + + if(!e.Mobs.Contains(x.Entry)) + e.Mobs.Add(x.Entry); + + uint u = x.GetBestRoom(); + if(u == uint.MaxValue) + continue; + + Room br = map.GetRoom(u); + if(br == null) + continue; + + Pathfinder_Mob pf = new Pathfinder_Mob(x, r.ToArray()); + pf.StartRooms = new[] { br }; + PathfindResult pr = map.Get(pf); + if(pr.Success && pr.Target != null) + u = pr.Target.Entry; + + if(!Rooms.Contains(u)) + Rooms.Add(u); + } + } + + if(t.Match.Groups[1].Length == 0) + e.Count = 1; + else + { + int n; + if(int.TryParse(Colors.RemoveColors(t.Match.Groups[1].Value, false).Trim(), out n)) + { + e.Count = n; + e.IsGQ = true; + } + else + { + e.Count = 1; + e.IsGQ = true; + } + } + + if(e.IsGQ) + Targets[0].Add(e); + else + Targets[1].Add(e); + + StringBuilder strRooms = new StringBuilder(); + foreach(uint u in Rooms) + { + if(strRooms.Length > 0) + strRooms.Append(" "); + strRooms.Append(u); + } + World.Instance.SendMessage("@w{cp_room}" + strRooms); + + UpdateColors(); + return false; + } + + private void UpdateColors() + { + MobDB.MobDB db = PluginMgr.GetPlugin("mobdb") as MobDB.MobDB; + if(db == null) + return; + + db.ClearMobColors(); + if(string.IsNullOrEmpty(Config.GetString("Color.Room", "@C"))) + return; + + if(Targets[0].Count != 0) + { + foreach(CPEntry x in Targets[0]) + { + foreach(uint u in x.Mobs) + db.SetMobColor(u, Config.GetString("Color.Room", "@C")); + } + } + else + { + foreach(CPEntry x in Targets[1]) + { + foreach(uint u in x.Mobs) + db.SetMobColor(u, Config.GetString("Color.Room", "@C")); + } + } + } + + private CPEntry IsSame(List entries, string mobName, string placeName) + { + Mapper.Mapper map = PluginMgr.GetPlugin("mapper") as Mapper.Mapper; + MobDB.MobDB db = PluginMgr.GetPlugin("mobdb") as MobDB.MobDB; + if(map == null || db == null) + return null; + + List areas = new List(); + foreach(Area x in map.Areas) + { + if(x.Name == placeName) + areas.Add(x.Keyword); + } + if(areas.Count == 0) + { + foreach(Room x in map.Rooms) + { + if(x.Name == placeName && !areas.Contains(x.Area.Keyword)) + areas.Add(x.Area.Keyword); + } + } + + foreach(CPEntry x in entries) + { + if(x.Name != mobName) + continue; + + foreach(uint u in x.Mobs) + { + Mob m = db.GetMob(u); + if(m == null) + continue; + + if(!m.Areas.Contains("all")) + { + bool f = false; + foreach(string y in m.Areas) + { + if(areas.Contains(y)) + { + f = true; + break; + } + } + + if(!f) + continue; + } + + return x; + } + } + + return null; + } + } + + public class Pathfinder_Mob : Pathfinder_Entry + { + public Pathfinder_Mob(Mob m, params uint[] roomId) + : base(roomId) + { + mob = m; + CanUsePortals = false; + CanUseRecalls = false; + CharacterLevel = m.Level; + CharacterTier = 0; + IsGlobalQuest = false; + IsSingleClassTier0 = false; + } + + private Mob mob; + private static string[] Normals = new[] { "n", "e", "s", "w", "u", "d" }; + + public override bool CanUseExit(Exit e) + { + if(!Normals.Contains(e.Command)) + return false; + + if(!mob.Areas.Contains("all") && !mob.Areas.Contains(e.To.Area.Keyword)) + return false; + + return base.CanUseExit(e); + } + } + + public class CPHelperConfig : ConfigFile + { + protected override void OnCreated() + { + base.OnCreated(); + + CreateSetting("Tags.On", 1, "Display tags on campaign / gq check messages for easier capture. If you turn tags off then room IDs will still be displayed if we find a mob in database."); + CreateSetting("Tags.Scan.Gag", 1, "Gag {scan} tags."); + CreateSetting("Color.Room", "@C", "Color campaign / gq mobs differently (the $mob.color value) when we have a CP / GQ mob target. Enter empty value to skip this. Mob has to be in database for this to work."); + CreateSetting("Color.Scan", "@R", "Color campaign / gq mobs differently when scanning. Enter empty value to skip this. You need to have \"tags scan on\" for this to work. Mob has to be in database for this to work."); + } + } + + internal class CPEntry + { + internal bool IsGQ = false; + internal string Name; + internal int Count; + internal string PlaceName; + internal List Mobs = new List(); + } +} diff --git a/CPHelper/CPHelper.csproj b/CPHelper/CPHelper.csproj new file mode 100644 index 0000000..a5c3c6b --- /dev/null +++ b/CPHelper/CPHelper.csproj @@ -0,0 +1,98 @@ + + + + Debug + AnyCPU + 9.0.30729 + 2.0 + {11D11063-A123-4F02-9C20-FB76C49A4B52} + Library + Properties + CPHelper + CPHelper + v3.5 + 512 + + + + + 3.5 + publish\ + true + Disk + false + Foreground + 7 + Days + false + false + true + 0 + 1.0.0.%2a + false + false + true + + + true + full + false + ..\..\..\..\Desktop\MushProxy-Build\Plugins\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + ..\..\..\..\Desktop\MushProxy-Build\Plugins\ + TRACE + prompt + 4 + + + + False + ..\Mapper\bin\Release\Mapper.dll + + + False + ..\MobDB\bin\Release\MobDB.dll + + + False + ..\ProxyCore\bin\ProxyCore.dll + + + + 3.5 + + + 3.5 + + + 3.5 + + + + + + + + + + + False + .NET Framework 3.5 SP1 + true + + + + + \ No newline at end of file diff --git a/CPHelper/Properties/.svn/all-wcprops b/CPHelper/Properties/.svn/all-wcprops new file mode 100644 index 0000000..48556f4 --- /dev/null +++ b/CPHelper/Properties/.svn/all-wcprops @@ -0,0 +1,11 @@ +K 25 +svn:wc:ra_dav:version-url +V 42 +/svn/!svn/ver/30/trunk/CPHelper/Properties +END +AssemblyInfo.cs +K 25 +svn:wc:ra_dav:version-url +V 58 +/svn/!svn/ver/30/trunk/CPHelper/Properties/AssemblyInfo.cs +END diff --git a/CPHelper/Properties/.svn/desktop.ini b/CPHelper/Properties/.svn/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/CPHelper/Properties/.svn/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/CPHelper/Properties/.svn/dir-prop-base b/CPHelper/Properties/.svn/dir-prop-base new file mode 100644 index 0000000..f1b96ea --- /dev/null +++ b/CPHelper/Properties/.svn/dir-prop-base @@ -0,0 +1,5 @@ +K 14 +bugtraq:number +V 4 +true +END diff --git a/CPHelper/Properties/.svn/entries b/CPHelper/Properties/.svn/entries new file mode 100644 index 0000000..e7a83ae --- /dev/null +++ b/CPHelper/Properties/.svn/entries @@ -0,0 +1,62 @@ +10 + +dir +58 +http://proxymud.googlecode.com/svn/trunk/CPHelper/Properties +http://proxymud.googlecode.com/svn + + + +2012-01-23T07:49:14.623991Z +30 +default8p@gmail.com +has-props + + + + + + + + + + + + + +8a6e9f07-fe1d-2472-fcf8-0b435762827a + +AssemblyInfo.cs +file + + + + +2016-03-25T22:18:42.968136Z +d030e90d841aa34a6cbe51f326db4af8 +2012-01-23T07:49:14.623991Z +30 +default8p@gmail.com + + + + + + + + + + + + + + + + + + + + + +1428 + diff --git a/CPHelper/Properties/.svn/prop-base/desktop.ini b/CPHelper/Properties/.svn/prop-base/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/CPHelper/Properties/.svn/prop-base/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/CPHelper/Properties/.svn/props/desktop.ini b/CPHelper/Properties/.svn/props/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/CPHelper/Properties/.svn/props/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/CPHelper/Properties/.svn/text-base/AssemblyInfo.cs.svn-base b/CPHelper/Properties/.svn/text-base/AssemblyInfo.cs.svn-base new file mode 100644 index 0000000..69bf221 --- /dev/null +++ b/CPHelper/Properties/.svn/text-base/AssemblyInfo.cs.svn-base @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("CPHelper")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("CPHelper")] +[assembly: AssemblyCopyright("Copyright © 2012")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("1010ed0e-d884-4c43-96d5-5549f787d8c4")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/CPHelper/Properties/.svn/text-base/desktop.ini b/CPHelper/Properties/.svn/text-base/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/CPHelper/Properties/.svn/text-base/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/CPHelper/Properties/.svn/tmp/desktop.ini b/CPHelper/Properties/.svn/tmp/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/CPHelper/Properties/.svn/tmp/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/CPHelper/Properties/.svn/tmp/prop-base/desktop.ini b/CPHelper/Properties/.svn/tmp/prop-base/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/CPHelper/Properties/.svn/tmp/prop-base/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/CPHelper/Properties/.svn/tmp/props/desktop.ini b/CPHelper/Properties/.svn/tmp/props/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/CPHelper/Properties/.svn/tmp/props/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/CPHelper/Properties/.svn/tmp/text-base/desktop.ini b/CPHelper/Properties/.svn/tmp/text-base/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/CPHelper/Properties/.svn/tmp/text-base/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/CPHelper/Properties/AssemblyInfo.cs b/CPHelper/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..69bf221 --- /dev/null +++ b/CPHelper/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("CPHelper")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("CPHelper")] +[assembly: AssemblyCopyright("Copyright © 2012")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("1010ed0e-d884-4c43-96d5-5549f787d8c4")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/CPHelper/Properties/desktop.ini b/CPHelper/Properties/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/CPHelper/Properties/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/CPHelper/desktop.ini b/CPHelper/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/CPHelper/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/CommandEcho/.svn/all-wcprops b/CommandEcho/.svn/all-wcprops new file mode 100644 index 0000000..8ac1029 --- /dev/null +++ b/CommandEcho/.svn/all-wcprops @@ -0,0 +1,17 @@ +K 25 +svn:wc:ra_dav:version-url +V 33 +/svn/!svn/ver/7/trunk/CommandEcho +END +CommandEcho.cs +K 25 +svn:wc:ra_dav:version-url +V 48 +/svn/!svn/ver/7/trunk/CommandEcho/CommandEcho.cs +END +CommandEcho.csproj +K 25 +svn:wc:ra_dav:version-url +V 52 +/svn/!svn/ver/7/trunk/CommandEcho/CommandEcho.csproj +END diff --git a/CommandEcho/.svn/desktop.ini b/CommandEcho/.svn/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/CommandEcho/.svn/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/CommandEcho/.svn/dir-prop-base b/CommandEcho/.svn/dir-prop-base new file mode 100644 index 0000000..f1b96ea --- /dev/null +++ b/CommandEcho/.svn/dir-prop-base @@ -0,0 +1,5 @@ +K 14 +bugtraq:number +V 4 +true +END diff --git a/CommandEcho/.svn/entries b/CommandEcho/.svn/entries new file mode 100644 index 0000000..cde5a6e --- /dev/null +++ b/CommandEcho/.svn/entries @@ -0,0 +1,99 @@ +10 + +dir +58 +http://proxymud.googlecode.com/svn/trunk/CommandEcho +http://proxymud.googlecode.com/svn + + + +2012-01-18T13:01:52.613929Z +7 +default8p@gmail.com +has-props + + + + + + + + + + + + + +8a6e9f07-fe1d-2472-fcf8-0b435762827a + +CommandEcho.cs +file + + + + +2016-03-25T22:18:43.232138Z +c4958e94321a3cbd77f4759bb9a6e2d6 +2012-01-18T13:01:52.613929Z +7 +default8p@gmail.com + + + + + + + + + + + + + + + + + + + + + +2112 + +Properties +dir + +CommandEcho.csproj +file + + + + +2016-03-25T22:18:43.232138Z +1c5a5dcde35304dcd226132e20a22816 +2012-01-18T13:01:52.613929Z +7 +default8p@gmail.com + + + + + + + + + + + + + + + + + + + + + +2727 + diff --git a/CommandEcho/.svn/prop-base/desktop.ini b/CommandEcho/.svn/prop-base/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/CommandEcho/.svn/prop-base/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/CommandEcho/.svn/props/desktop.ini b/CommandEcho/.svn/props/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/CommandEcho/.svn/props/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/CommandEcho/.svn/text-base/CommandEcho.cs.svn-base b/CommandEcho/.svn/text-base/CommandEcho.cs.svn-base new file mode 100644 index 0000000..5c015b8 --- /dev/null +++ b/CommandEcho/.svn/text-base/CommandEcho.cs.svn-base @@ -0,0 +1,47 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using ProxyCore; +using ProxyCore.Scripting; + +namespace CommandEcho +{ + public class CommandEcho : Plugin + { + public CommandEcho() + : base("cmdecho", "Command echo") + { + Author = "Duckbat"; + Version = 1; + Description = "Echos commands from certain security mask back to other clients. This way you can use your regular MUD client to execute another user's commands. For example if the user is on the phone or whereever."; + Website = "code.google.com/p/proxymud/"; + UpdateUrl = "www.duckbat.com/plugins/update.cmdecho.txt"; + + Config = new CMDEchoConfig(); + } + + public override void OnEnteredCommandAfter(ref string Msg, uint ClientId, int AuthLevel) + { + base.OnEnteredCommandAfter(ref Msg, ClientId, AuthLevel); + + ulong echoFrom = Config.GetUInt64("Echo.From.AuthMask", 1); + if((echoFrom & ((ulong)1 << (AuthLevel - 1))) != 0) + { + World.Instance.SendMessage("@w{CommandEcho,Level=" + AuthLevel + ",Id=" + ClientId + "}" + Msg, Config.GetUInt64("Echo.To.AuthMask", ulong.MaxValue - 1)); + Msg = null; + } + } + } + + public class CMDEchoConfig : ConfigFile + { + protected override void OnCreated() + { + base.OnCreated(); + + CreateSetting("Echo.From.AuthMask", 1, "Whose commands do we echo? This is a security mask. Default is 1 which means users with auth level 1 will send commands to other users."); + CreateSetting("Echo.To.AuthMask", (ulong.MaxValue - 1), "Who do we echo the commands to. Default is " + (ulong.MaxValue - 1) + " which means every security level except 1.\n\nCommands will be echoed in this format:\n@w{CommandEcho,Level=1,Id=1}say yay\nLevel means Auth level of client who entered command, Id means client id who entered command. If Id is 0 then command was entered from a plugin."); + } + } +} diff --git a/CommandEcho/.svn/text-base/CommandEcho.csproj.svn-base b/CommandEcho/.svn/text-base/CommandEcho.csproj.svn-base new file mode 100644 index 0000000..494b83e --- /dev/null +++ b/CommandEcho/.svn/text-base/CommandEcho.csproj.svn-base @@ -0,0 +1,63 @@ + + + + Debug + AnyCPU + 9.0.30729 + 2.0 + {A51883B5-8A7B-414F-92A9-A171A9846411} + Library + Properties + CommandEcho + CommandEcho + v3.5 + 512 + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + False + ..\ProxyCore\bin\ProxyCore.dll + + + + 3.5 + + + 3.5 + + + 3.5 + + + + + + + + + + + \ No newline at end of file diff --git a/CommandEcho/.svn/text-base/desktop.ini b/CommandEcho/.svn/text-base/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/CommandEcho/.svn/text-base/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/CommandEcho/.svn/tmp/desktop.ini b/CommandEcho/.svn/tmp/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/CommandEcho/.svn/tmp/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/CommandEcho/.svn/tmp/prop-base/desktop.ini b/CommandEcho/.svn/tmp/prop-base/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/CommandEcho/.svn/tmp/prop-base/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/CommandEcho/.svn/tmp/props/desktop.ini b/CommandEcho/.svn/tmp/props/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/CommandEcho/.svn/tmp/props/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/CommandEcho/.svn/tmp/text-base/desktop.ini b/CommandEcho/.svn/tmp/text-base/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/CommandEcho/.svn/tmp/text-base/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/CommandEcho/CommandEcho.cs b/CommandEcho/CommandEcho.cs new file mode 100644 index 0000000..5c015b8 --- /dev/null +++ b/CommandEcho/CommandEcho.cs @@ -0,0 +1,47 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using ProxyCore; +using ProxyCore.Scripting; + +namespace CommandEcho +{ + public class CommandEcho : Plugin + { + public CommandEcho() + : base("cmdecho", "Command echo") + { + Author = "Duckbat"; + Version = 1; + Description = "Echos commands from certain security mask back to other clients. This way you can use your regular MUD client to execute another user's commands. For example if the user is on the phone or whereever."; + Website = "code.google.com/p/proxymud/"; + UpdateUrl = "www.duckbat.com/plugins/update.cmdecho.txt"; + + Config = new CMDEchoConfig(); + } + + public override void OnEnteredCommandAfter(ref string Msg, uint ClientId, int AuthLevel) + { + base.OnEnteredCommandAfter(ref Msg, ClientId, AuthLevel); + + ulong echoFrom = Config.GetUInt64("Echo.From.AuthMask", 1); + if((echoFrom & ((ulong)1 << (AuthLevel - 1))) != 0) + { + World.Instance.SendMessage("@w{CommandEcho,Level=" + AuthLevel + ",Id=" + ClientId + "}" + Msg, Config.GetUInt64("Echo.To.AuthMask", ulong.MaxValue - 1)); + Msg = null; + } + } + } + + public class CMDEchoConfig : ConfigFile + { + protected override void OnCreated() + { + base.OnCreated(); + + CreateSetting("Echo.From.AuthMask", 1, "Whose commands do we echo? This is a security mask. Default is 1 which means users with auth level 1 will send commands to other users."); + CreateSetting("Echo.To.AuthMask", (ulong.MaxValue - 1), "Who do we echo the commands to. Default is " + (ulong.MaxValue - 1) + " which means every security level except 1.\n\nCommands will be echoed in this format:\n@w{CommandEcho,Level=1,Id=1}say yay\nLevel means Auth level of client who entered command, Id means client id who entered command. If Id is 0 then command was entered from a plugin."); + } + } +} diff --git a/CommandEcho/CommandEcho.csproj b/CommandEcho/CommandEcho.csproj new file mode 100644 index 0000000..20b01f3 --- /dev/null +++ b/CommandEcho/CommandEcho.csproj @@ -0,0 +1,90 @@ + + + + Debug + AnyCPU + 9.0.30729 + 2.0 + {A51883B5-8A7B-414F-92A9-A171A9846411} + Library + Properties + CommandEcho + CommandEcho + v3.5 + 512 + + + + + 3.5 + publish\ + true + Disk + false + Foreground + 7 + Days + false + false + true + 0 + 1.0.0.%2a + false + false + true + + + true + full + false + ..\..\..\..\Desktop\MushProxy-Build\Plugins\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + ..\..\..\..\Desktop\MushProxy-Build\Plugins\ + TRACE + prompt + 4 + + + + False + ..\ProxyCore\bin\ProxyCore.dll + + + + 3.5 + + + 3.5 + + + 3.5 + + + + + + + + + + + False + .NET Framework 3.5 SP1 + true + + + + + \ No newline at end of file diff --git a/CommandEcho/Properties/.svn/all-wcprops b/CommandEcho/Properties/.svn/all-wcprops new file mode 100644 index 0000000..aa6850d --- /dev/null +++ b/CommandEcho/Properties/.svn/all-wcprops @@ -0,0 +1,11 @@ +K 25 +svn:wc:ra_dav:version-url +V 44 +/svn/!svn/ver/7/trunk/CommandEcho/Properties +END +AssemblyInfo.cs +K 25 +svn:wc:ra_dav:version-url +V 60 +/svn/!svn/ver/7/trunk/CommandEcho/Properties/AssemblyInfo.cs +END diff --git a/CommandEcho/Properties/.svn/desktop.ini b/CommandEcho/Properties/.svn/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/CommandEcho/Properties/.svn/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/CommandEcho/Properties/.svn/dir-prop-base b/CommandEcho/Properties/.svn/dir-prop-base new file mode 100644 index 0000000..f1b96ea --- /dev/null +++ b/CommandEcho/Properties/.svn/dir-prop-base @@ -0,0 +1,5 @@ +K 14 +bugtraq:number +V 4 +true +END diff --git a/CommandEcho/Properties/.svn/entries b/CommandEcho/Properties/.svn/entries new file mode 100644 index 0000000..8652594 --- /dev/null +++ b/CommandEcho/Properties/.svn/entries @@ -0,0 +1,62 @@ +10 + +dir +58 +http://proxymud.googlecode.com/svn/trunk/CommandEcho/Properties +http://proxymud.googlecode.com/svn + + + +2012-01-18T13:01:52.613929Z +7 +default8p@gmail.com +has-props + + + + + + + + + + + + + +8a6e9f07-fe1d-2472-fcf8-0b435762827a + +AssemblyInfo.cs +file + + + + +2016-03-25T22:18:43.232138Z +35d863597b8948ecb9b10d9230e62387 +2012-01-18T13:01:52.613929Z +7 +default8p@gmail.com + + + + + + + + + + + + + + + + + + + + + +1434 + diff --git a/CommandEcho/Properties/.svn/prop-base/desktop.ini b/CommandEcho/Properties/.svn/prop-base/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/CommandEcho/Properties/.svn/prop-base/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/CommandEcho/Properties/.svn/props/desktop.ini b/CommandEcho/Properties/.svn/props/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/CommandEcho/Properties/.svn/props/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/CommandEcho/Properties/.svn/text-base/AssemblyInfo.cs.svn-base b/CommandEcho/Properties/.svn/text-base/AssemblyInfo.cs.svn-base new file mode 100644 index 0000000..bafedd8 --- /dev/null +++ b/CommandEcho/Properties/.svn/text-base/AssemblyInfo.cs.svn-base @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("CommandEcho")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("CommandEcho")] +[assembly: AssemblyCopyright("Copyright © 2012")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("fcd404fe-2f3b-4407-8fa1-f2063c2c7dc6")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/CommandEcho/Properties/.svn/text-base/desktop.ini b/CommandEcho/Properties/.svn/text-base/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/CommandEcho/Properties/.svn/text-base/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/CommandEcho/Properties/.svn/tmp/desktop.ini b/CommandEcho/Properties/.svn/tmp/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/CommandEcho/Properties/.svn/tmp/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/CommandEcho/Properties/.svn/tmp/prop-base/desktop.ini b/CommandEcho/Properties/.svn/tmp/prop-base/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/CommandEcho/Properties/.svn/tmp/prop-base/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/CommandEcho/Properties/.svn/tmp/props/desktop.ini b/CommandEcho/Properties/.svn/tmp/props/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/CommandEcho/Properties/.svn/tmp/props/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/CommandEcho/Properties/.svn/tmp/text-base/desktop.ini b/CommandEcho/Properties/.svn/tmp/text-base/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/CommandEcho/Properties/.svn/tmp/text-base/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/CommandEcho/Properties/AssemblyInfo.cs b/CommandEcho/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..bafedd8 --- /dev/null +++ b/CommandEcho/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("CommandEcho")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("CommandEcho")] +[assembly: AssemblyCopyright("Copyright © 2012")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("fcd404fe-2f3b-4407-8fa1-f2063c2c7dc6")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/CommandEcho/Properties/desktop.ini b/CommandEcho/Properties/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/CommandEcho/Properties/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/CommandEcho/desktop.ini b/CommandEcho/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/CommandEcho/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/GMCPEcho/.svn/all-wcprops b/GMCPEcho/.svn/all-wcprops new file mode 100644 index 0000000..f1144b0 --- /dev/null +++ b/GMCPEcho/.svn/all-wcprops @@ -0,0 +1,17 @@ +K 25 +svn:wc:ra_dav:version-url +V 30 +/svn/!svn/ver/2/trunk/GMCPEcho +END +GMCPEcho.csproj +K 25 +svn:wc:ra_dav:version-url +V 46 +/svn/!svn/ver/2/trunk/GMCPEcho/GMCPEcho.csproj +END +GMCPEcho.cs +K 25 +svn:wc:ra_dav:version-url +V 42 +/svn/!svn/ver/2/trunk/GMCPEcho/GMCPEcho.cs +END diff --git a/GMCPEcho/.svn/desktop.ini b/GMCPEcho/.svn/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/GMCPEcho/.svn/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/GMCPEcho/.svn/dir-prop-base b/GMCPEcho/.svn/dir-prop-base new file mode 100644 index 0000000..f1b96ea --- /dev/null +++ b/GMCPEcho/.svn/dir-prop-base @@ -0,0 +1,5 @@ +K 14 +bugtraq:number +V 4 +true +END diff --git a/GMCPEcho/.svn/entries b/GMCPEcho/.svn/entries new file mode 100644 index 0000000..ab05e7a --- /dev/null +++ b/GMCPEcho/.svn/entries @@ -0,0 +1,99 @@ +10 + +dir +58 +http://proxymud.googlecode.com/svn/trunk/GMCPEcho +http://proxymud.googlecode.com/svn + + + +2012-01-17T10:55:35.805502Z +2 +default8p@gmail.com +has-props + + + + + + + + + + + + + +8a6e9f07-fe1d-2472-fcf8-0b435762827a + +GMCPEcho.csproj +file + + + + +2016-03-25T22:18:43.064138Z +76fb0ddd83ae3b24fd40628d322b5e47 +2012-01-17T10:55:35.805502Z +2 +default8p@gmail.com + + + + + + + + + + + + + + + + + + + + + +2718 + +GMCPEcho.cs +file + + + + +2016-03-25T22:18:43.064138Z +9aaa0c4c8ac82fc1c1898d1cefd5cde5 +2012-01-17T10:55:35.805502Z +2 +default8p@gmail.com + + + + + + + + + + + + + + + + + + + + + +2717 + +Properties +dir + diff --git a/GMCPEcho/.svn/prop-base/desktop.ini b/GMCPEcho/.svn/prop-base/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/GMCPEcho/.svn/prop-base/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/GMCPEcho/.svn/props/desktop.ini b/GMCPEcho/.svn/props/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/GMCPEcho/.svn/props/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/GMCPEcho/.svn/text-base/GMCPEcho.cs.svn-base b/GMCPEcho/.svn/text-base/GMCPEcho.cs.svn-base new file mode 100644 index 0000000..cd254a7 --- /dev/null +++ b/GMCPEcho/.svn/text-base/GMCPEcho.cs.svn-base @@ -0,0 +1,71 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using ProxyCore.Scripting; +using ProxyCore; +using ProxyCore.Output; + +namespace GMCPEcho +{ + public class GMCPEcho : Plugin + { + public GMCPEcho() + : base("gmcpecho", "GMCP Echo") + { + Author = "Duckbat"; + Version = 1; + Description = "Echos all GMCP specified by user back. This way you can see GMCP in clients that normally don't support it."; + UpdateUrl = "www.duckbat.com/plugins/update.gmcpecho.txt"; + Website = "www.duckbat.com/plugins/index.php?t=gmcpecho"; + + Config = new GMCPEchoConfig(); + + RegisterTrigger("gmcp", @"^\$gmcp\.", GMCPTrigger); + } + + private string[] AllowedModules; + + private bool GMCPTrigger(TriggerData t) + { + if(AllowedModules == null) + AllowedModules = Config.GetString("GMCP.Modules", "gmcp.*").Split(new[] { ",", " " }, StringSplitOptions.RemoveEmptyEntries); + + string Module = t.Msg.Msg.Substring(1); + if(Module.Contains(' ')) + Module = Module.Substring(0, Module.IndexOf(' ')); + if(HasModule(Module)) + World.Instance.SendMessage(t.Msg.Msg, Config.GetUInt64("GMCP.AuthMask", ulong.MaxValue)); + return false; + } + + private bool HasModule(string Msg) + { + foreach(string x in AllowedModules) + { + if(x.EndsWith("*")) + { + if(Msg.StartsWith(x.Substring(0, x.Length - 1))) + return true; + continue; + } + + if(x == Msg) + return true; + } + + return false; + } + } + + public class GMCPEchoConfig : ConfigFile + { + protected override void OnCreated() + { + base.OnCreated(); + + CreateSetting("GMCP.Modules", "gmcp.*", "Which GMCP modules would you like to echo to client. Separate with ',' sign and use '*' for wildcard but the wildcard can only be at the end not in the middle or start. For example \"gmcp.char.*, gmcp.room.*\". Use \"gmcp.*\" to echo everything."); + CreateSetting("GMCP.AuthMask", ulong.MaxValue, "Which client security levels see GMCP echo. This is a 64 bit mask. For example if you want security level 1 and 3 to see GMCP you would enter value 5 (1 + 4). These values are 2 ^ (level - 1), for example security level 3 mask: 2 ^ (3 - 1) = 4. Then you just add these up. Default (all levels): " + ulong.MaxValue); + } + } +} diff --git a/GMCPEcho/.svn/text-base/GMCPEcho.csproj.svn-base b/GMCPEcho/.svn/text-base/GMCPEcho.csproj.svn-base new file mode 100644 index 0000000..d527a43 --- /dev/null +++ b/GMCPEcho/.svn/text-base/GMCPEcho.csproj.svn-base @@ -0,0 +1,63 @@ + + + + Debug + AnyCPU + 9.0.30729 + 2.0 + {86B2AA8D-5B03-4128-9C77-9E94F71CFFEE} + Library + Properties + GMCPEcho + GMCPEcho + v3.5 + 512 + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + False + ..\ProxyCore\bin\ProxyCore.dll + + + + 3.5 + + + 3.5 + + + 3.5 + + + + + + + + + + + \ No newline at end of file diff --git a/GMCPEcho/.svn/text-base/desktop.ini b/GMCPEcho/.svn/text-base/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/GMCPEcho/.svn/text-base/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/GMCPEcho/.svn/tmp/desktop.ini b/GMCPEcho/.svn/tmp/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/GMCPEcho/.svn/tmp/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/GMCPEcho/.svn/tmp/prop-base/desktop.ini b/GMCPEcho/.svn/tmp/prop-base/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/GMCPEcho/.svn/tmp/prop-base/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/GMCPEcho/.svn/tmp/props/desktop.ini b/GMCPEcho/.svn/tmp/props/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/GMCPEcho/.svn/tmp/props/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/GMCPEcho/.svn/tmp/text-base/desktop.ini b/GMCPEcho/.svn/tmp/text-base/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/GMCPEcho/.svn/tmp/text-base/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/GMCPEcho/GMCPEcho.cs b/GMCPEcho/GMCPEcho.cs new file mode 100644 index 0000000..cd254a7 --- /dev/null +++ b/GMCPEcho/GMCPEcho.cs @@ -0,0 +1,71 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using ProxyCore.Scripting; +using ProxyCore; +using ProxyCore.Output; + +namespace GMCPEcho +{ + public class GMCPEcho : Plugin + { + public GMCPEcho() + : base("gmcpecho", "GMCP Echo") + { + Author = "Duckbat"; + Version = 1; + Description = "Echos all GMCP specified by user back. This way you can see GMCP in clients that normally don't support it."; + UpdateUrl = "www.duckbat.com/plugins/update.gmcpecho.txt"; + Website = "www.duckbat.com/plugins/index.php?t=gmcpecho"; + + Config = new GMCPEchoConfig(); + + RegisterTrigger("gmcp", @"^\$gmcp\.", GMCPTrigger); + } + + private string[] AllowedModules; + + private bool GMCPTrigger(TriggerData t) + { + if(AllowedModules == null) + AllowedModules = Config.GetString("GMCP.Modules", "gmcp.*").Split(new[] { ",", " " }, StringSplitOptions.RemoveEmptyEntries); + + string Module = t.Msg.Msg.Substring(1); + if(Module.Contains(' ')) + Module = Module.Substring(0, Module.IndexOf(' ')); + if(HasModule(Module)) + World.Instance.SendMessage(t.Msg.Msg, Config.GetUInt64("GMCP.AuthMask", ulong.MaxValue)); + return false; + } + + private bool HasModule(string Msg) + { + foreach(string x in AllowedModules) + { + if(x.EndsWith("*")) + { + if(Msg.StartsWith(x.Substring(0, x.Length - 1))) + return true; + continue; + } + + if(x == Msg) + return true; + } + + return false; + } + } + + public class GMCPEchoConfig : ConfigFile + { + protected override void OnCreated() + { + base.OnCreated(); + + CreateSetting("GMCP.Modules", "gmcp.*", "Which GMCP modules would you like to echo to client. Separate with ',' sign and use '*' for wildcard but the wildcard can only be at the end not in the middle or start. For example \"gmcp.char.*, gmcp.room.*\". Use \"gmcp.*\" to echo everything."); + CreateSetting("GMCP.AuthMask", ulong.MaxValue, "Which client security levels see GMCP echo. This is a 64 bit mask. For example if you want security level 1 and 3 to see GMCP you would enter value 5 (1 + 4). These values are 2 ^ (level - 1), for example security level 3 mask: 2 ^ (3 - 1) = 4. Then you just add these up. Default (all levels): " + ulong.MaxValue); + } + } +} diff --git a/GMCPEcho/GMCPEcho.csproj b/GMCPEcho/GMCPEcho.csproj new file mode 100644 index 0000000..cbc3173 --- /dev/null +++ b/GMCPEcho/GMCPEcho.csproj @@ -0,0 +1,90 @@ + + + + Debug + AnyCPU + 9.0.30729 + 2.0 + {86B2AA8D-5B03-4128-9C77-9E94F71CFFEE} + Library + Properties + GMCPEcho + GMCPEcho + v3.5 + 512 + + + + + 3.5 + publish\ + true + Disk + false + Foreground + 7 + Days + false + false + true + 0 + 1.0.0.%2a + false + false + true + + + true + full + false + ..\..\..\..\Desktop\MushProxy-Build\Plugins\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + ..\..\..\..\Desktop\MushProxy-Build\Plugins\ + TRACE + prompt + 4 + + + + False + ..\ProxyCore\bin\ProxyCore.dll + + + + 3.5 + + + 3.5 + + + 3.5 + + + + + + + + + + + False + .NET Framework 3.5 SP1 + true + + + + + \ No newline at end of file diff --git a/GMCPEcho/Properties/.svn/all-wcprops b/GMCPEcho/Properties/.svn/all-wcprops new file mode 100644 index 0000000..10ef497 --- /dev/null +++ b/GMCPEcho/Properties/.svn/all-wcprops @@ -0,0 +1,11 @@ +K 25 +svn:wc:ra_dav:version-url +V 41 +/svn/!svn/ver/2/trunk/GMCPEcho/Properties +END +AssemblyInfo.cs +K 25 +svn:wc:ra_dav:version-url +V 57 +/svn/!svn/ver/2/trunk/GMCPEcho/Properties/AssemblyInfo.cs +END diff --git a/GMCPEcho/Properties/.svn/desktop.ini b/GMCPEcho/Properties/.svn/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/GMCPEcho/Properties/.svn/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/GMCPEcho/Properties/.svn/dir-prop-base b/GMCPEcho/Properties/.svn/dir-prop-base new file mode 100644 index 0000000..f1b96ea --- /dev/null +++ b/GMCPEcho/Properties/.svn/dir-prop-base @@ -0,0 +1,5 @@ +K 14 +bugtraq:number +V 4 +true +END diff --git a/GMCPEcho/Properties/.svn/entries b/GMCPEcho/Properties/.svn/entries new file mode 100644 index 0000000..3afebd8 --- /dev/null +++ b/GMCPEcho/Properties/.svn/entries @@ -0,0 +1,62 @@ +10 + +dir +58 +http://proxymud.googlecode.com/svn/trunk/GMCPEcho/Properties +http://proxymud.googlecode.com/svn + + + +2012-01-17T10:55:35.805502Z +2 +default8p@gmail.com +has-props + + + + + + + + + + + + + +8a6e9f07-fe1d-2472-fcf8-0b435762827a + +AssemblyInfo.cs +file + + + + +2016-03-25T22:18:43.064138Z +df762a418f90d48e08731801bf1106b8 +2012-01-17T10:55:35.805502Z +2 +default8p@gmail.com + + + + + + + + + + + + + + + + + + + + + +1428 + diff --git a/GMCPEcho/Properties/.svn/prop-base/desktop.ini b/GMCPEcho/Properties/.svn/prop-base/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/GMCPEcho/Properties/.svn/prop-base/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/GMCPEcho/Properties/.svn/props/desktop.ini b/GMCPEcho/Properties/.svn/props/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/GMCPEcho/Properties/.svn/props/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/GMCPEcho/Properties/.svn/text-base/AssemblyInfo.cs.svn-base b/GMCPEcho/Properties/.svn/text-base/AssemblyInfo.cs.svn-base new file mode 100644 index 0000000..e66e546 --- /dev/null +++ b/GMCPEcho/Properties/.svn/text-base/AssemblyInfo.cs.svn-base @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("GMCPEcho")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("GMCPEcho")] +[assembly: AssemblyCopyright("Copyright © 2012")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("692b7a44-ef7f-4680-a81c-8f013fe8fb4f")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/GMCPEcho/Properties/.svn/text-base/desktop.ini b/GMCPEcho/Properties/.svn/text-base/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/GMCPEcho/Properties/.svn/text-base/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/GMCPEcho/Properties/.svn/tmp/desktop.ini b/GMCPEcho/Properties/.svn/tmp/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/GMCPEcho/Properties/.svn/tmp/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/GMCPEcho/Properties/.svn/tmp/prop-base/desktop.ini b/GMCPEcho/Properties/.svn/tmp/prop-base/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/GMCPEcho/Properties/.svn/tmp/prop-base/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/GMCPEcho/Properties/.svn/tmp/props/desktop.ini b/GMCPEcho/Properties/.svn/tmp/props/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/GMCPEcho/Properties/.svn/tmp/props/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/GMCPEcho/Properties/.svn/tmp/text-base/desktop.ini b/GMCPEcho/Properties/.svn/tmp/text-base/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/GMCPEcho/Properties/.svn/tmp/text-base/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/GMCPEcho/Properties/AssemblyInfo.cs b/GMCPEcho/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..e66e546 --- /dev/null +++ b/GMCPEcho/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("GMCPEcho")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("GMCPEcho")] +[assembly: AssemblyCopyright("Copyright © 2012")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("692b7a44-ef7f-4680-a81c-8f013fe8fb4f")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/GMCPEcho/Properties/desktop.ini b/GMCPEcho/Properties/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/GMCPEcho/Properties/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/GMCPEcho/desktop.ini b/GMCPEcho/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/GMCPEcho/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/GQPredict/.svn/all-wcprops b/GQPredict/.svn/all-wcprops new file mode 100644 index 0000000..7a016fd --- /dev/null +++ b/GQPredict/.svn/all-wcprops @@ -0,0 +1,17 @@ +K 25 +svn:wc:ra_dav:version-url +V 31 +/svn/!svn/ver/2/trunk/GQPredict +END +GQPredict.cs +K 25 +svn:wc:ra_dav:version-url +V 44 +/svn/!svn/ver/2/trunk/GQPredict/GQPredict.cs +END +GQPredict.csproj +K 25 +svn:wc:ra_dav:version-url +V 48 +/svn/!svn/ver/2/trunk/GQPredict/GQPredict.csproj +END diff --git a/GQPredict/.svn/desktop.ini b/GQPredict/.svn/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/GQPredict/.svn/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/GQPredict/.svn/dir-prop-base b/GQPredict/.svn/dir-prop-base new file mode 100644 index 0000000..f1b96ea --- /dev/null +++ b/GQPredict/.svn/dir-prop-base @@ -0,0 +1,5 @@ +K 14 +bugtraq:number +V 4 +true +END diff --git a/GQPredict/.svn/entries b/GQPredict/.svn/entries new file mode 100644 index 0000000..c81150d --- /dev/null +++ b/GQPredict/.svn/entries @@ -0,0 +1,99 @@ +10 + +dir +58 +http://proxymud.googlecode.com/svn/trunk/GQPredict +http://proxymud.googlecode.com/svn + + + +2012-01-17T10:55:35.805502Z +2 +default8p@gmail.com +has-props + + + + + + + + + + + + + +8a6e9f07-fe1d-2472-fcf8-0b435762827a + +GQPredict.cs +file + + + + +2016-03-25T22:18:43.000137Z +99116d9829ec2e9c0161fbde0f88f370 +2012-01-17T10:55:35.805502Z +2 +default8p@gmail.com + + + + + + + + + + + + + + + + + + + + + +5817 + +Properties +dir + +GQPredict.csproj +file + + + + +2016-03-25T22:18:43.000137Z +ad86ea1e250fa576b1ac563a9d244254 +2012-01-17T10:55:35.805502Z +2 +default8p@gmail.com + + + + + + + + + + + + + + + + + + + + + +2721 + diff --git a/GQPredict/.svn/prop-base/desktop.ini b/GQPredict/.svn/prop-base/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/GQPredict/.svn/prop-base/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/GQPredict/.svn/props/desktop.ini b/GQPredict/.svn/props/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/GQPredict/.svn/props/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/GQPredict/.svn/text-base/GQPredict.cs.svn-base b/GQPredict/.svn/text-base/GQPredict.cs.svn-base new file mode 100644 index 0000000..647b946 --- /dev/null +++ b/GQPredict/.svn/text-base/GQPredict.cs.svn-base @@ -0,0 +1,151 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using ProxyCore.Scripting; +using ProxyCore.Input; +using ProxyCore.Output; +using ProxyCore; + +namespace GQPredict +{ + public class GQPredict : Plugin + { + public GQPredict() + : base("gqpredict", "Global Quest Predictor") + { + Author = "Duckbat"; + Version = 1; + Description = "Calculates the chance that the next global quest will be for you (or the level you specify). And shows the ranges that will occur and have already occured in a simple list sorted by range. Type gqpredict to see."; + UpdateUrl = "www.duckbat.com/plugins/update.gqpredict.txt"; + Website = "www.duckbat.com/plugins/index.php?t=gqpredict"; + + RegisterCommand("gqpredict", @"(\d+)", Predict, 3); + RegisterTrigger("ranges", @"^ \s*@w(\d+)\s+(\d+)\s+(Yes|No)$", Ranges); + RegisterTrigger("start", "@CFrom Level To Level Already Run?", Start, TriggerFlags.NotRegex); + RegisterTrigger("delimiter", "@W----------- --------- ------------", Delim, TriggerFlags.NotRegex); + RegisterTrigger("level", @"^\$gmcp\.char\.status\.level (\d+)$", Level); + } + + private int nt; + private int forLevel = 1; + private int charLevel = 1; + private int count; + private uint[] ClientMask; + private int Listen = 0; + private readonly SortedDictionary>> gqRanges = new SortedDictionary>>(); + + private bool Predict(InputData i) + { + Listen = 3; + if(i.Arguments.Success) + { + if(!int.TryParse(i.Arguments.Groups[1].Value, out forLevel)) + forLevel = charLevel; + } + else + forLevel = charLevel; + + i.Command = "gq ranges"; + ClientMask = i.ClientMask; + return false; + } + + private bool Ranges(TriggerData t) + { + if(Listen == 0) + return false; + int from; + int to; + if(!int.TryParse(t.Match.Groups[1].Value, out from) || + !int.TryParse(t.Match.Groups[2].Value, out to)) + return false; + + if(!gqRanges.ContainsKey(from)) + gqRanges[from] = new SortedDictionary>(); + if(!gqRanges[from].ContainsKey(to)) + gqRanges[from][to] = new List(); + gqRanges[from][to].Add(t.Match.Groups[3].Length == 3); + if(t.Match.Groups[3].Length != 3) + count++; + if(to == 201) + { + nt++; + if(nt == 3) + { + StringBuilder str = new StringBuilder(); + int i = 0; + int myGQ = 0; + foreach(KeyValuePair>> x in gqRanges) + { + foreach(KeyValuePair> y in x.Value) + { + foreach(bool z in y.Value) + { + if(forLevel < x.Key || forLevel > y.Key || z) + str.Append(z ? "@r" : "@g"); + else + { + str.Append("@G"); + myGQ++; + } + str.Append("(" + string.Format("{0,3}", x.Key) + " - " + string.Format("{0,3}", y.Key) + + ") "); + i++; + if(i == 6) + { + World.Instance.SendMessage(str.ToString(), ClientMask); + i = 0; + str.Remove(0, str.Length); + } + } + } + } + + if(i > 0) + World.Instance.SendMessage(str.ToString(), ClientMask); + + double chance = 0; + if(count > 0 && myGQ > 0) + chance = (double)myGQ / (double)count * 100.0; + World.Instance.SendMessage("@wChance that the next global quest will be for " + (forLevel != charLevel ? ("level " + forLevel) : "your level") + " is @Y" + string.Format("{0:0.00}", chance).Replace(',', '.') + "%@w.", ClientMask); + if(forLevel == charLevel) + World.Instance.SendMessage("@wUse '@Wgqpredict @w' to see from the viewpoint of another level.", ClientMask); + Listen = 0; + } + } + return true; + } + + private bool Level(TriggerData t) + { + int i; + if(int.TryParse(t.Match.Groups[1].Value, out i)) + charLevel = i; + return false; + } + + private bool Start(TriggerData t) + { + nt = 0; + gqRanges.Clear(); + count = 0; + if(Listen > 0) + { + Listen--; + return true; + } + return false; + } + + private bool Delim(TriggerData t) + { + if(Listen > 0) + { + Listen--; + return true; + } + return false; + } + } +} diff --git a/GQPredict/.svn/text-base/GQPredict.csproj.svn-base b/GQPredict/.svn/text-base/GQPredict.csproj.svn-base new file mode 100644 index 0000000..b2623f6 --- /dev/null +++ b/GQPredict/.svn/text-base/GQPredict.csproj.svn-base @@ -0,0 +1,63 @@ + + + + Debug + AnyCPU + 9.0.30729 + 2.0 + {BE332B80-9B00-4B31-A3D9-15E85B2BEA83} + Library + Properties + GQPredict + GQPredict + v3.5 + 512 + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + False + ..\ProxyCore\bin\ProxyCore.dll + + + + 3.5 + + + 3.5 + + + 3.5 + + + + + + + + + + + \ No newline at end of file diff --git a/GQPredict/.svn/text-base/desktop.ini b/GQPredict/.svn/text-base/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/GQPredict/.svn/text-base/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/GQPredict/.svn/tmp/desktop.ini b/GQPredict/.svn/tmp/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/GQPredict/.svn/tmp/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/GQPredict/.svn/tmp/prop-base/desktop.ini b/GQPredict/.svn/tmp/prop-base/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/GQPredict/.svn/tmp/prop-base/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/GQPredict/.svn/tmp/props/desktop.ini b/GQPredict/.svn/tmp/props/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/GQPredict/.svn/tmp/props/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/GQPredict/.svn/tmp/text-base/desktop.ini b/GQPredict/.svn/tmp/text-base/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/GQPredict/.svn/tmp/text-base/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/GQPredict/GQPredict.cs b/GQPredict/GQPredict.cs new file mode 100644 index 0000000..647b946 --- /dev/null +++ b/GQPredict/GQPredict.cs @@ -0,0 +1,151 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using ProxyCore.Scripting; +using ProxyCore.Input; +using ProxyCore.Output; +using ProxyCore; + +namespace GQPredict +{ + public class GQPredict : Plugin + { + public GQPredict() + : base("gqpredict", "Global Quest Predictor") + { + Author = "Duckbat"; + Version = 1; + Description = "Calculates the chance that the next global quest will be for you (or the level you specify). And shows the ranges that will occur and have already occured in a simple list sorted by range. Type gqpredict to see."; + UpdateUrl = "www.duckbat.com/plugins/update.gqpredict.txt"; + Website = "www.duckbat.com/plugins/index.php?t=gqpredict"; + + RegisterCommand("gqpredict", @"(\d+)", Predict, 3); + RegisterTrigger("ranges", @"^ \s*@w(\d+)\s+(\d+)\s+(Yes|No)$", Ranges); + RegisterTrigger("start", "@CFrom Level To Level Already Run?", Start, TriggerFlags.NotRegex); + RegisterTrigger("delimiter", "@W----------- --------- ------------", Delim, TriggerFlags.NotRegex); + RegisterTrigger("level", @"^\$gmcp\.char\.status\.level (\d+)$", Level); + } + + private int nt; + private int forLevel = 1; + private int charLevel = 1; + private int count; + private uint[] ClientMask; + private int Listen = 0; + private readonly SortedDictionary>> gqRanges = new SortedDictionary>>(); + + private bool Predict(InputData i) + { + Listen = 3; + if(i.Arguments.Success) + { + if(!int.TryParse(i.Arguments.Groups[1].Value, out forLevel)) + forLevel = charLevel; + } + else + forLevel = charLevel; + + i.Command = "gq ranges"; + ClientMask = i.ClientMask; + return false; + } + + private bool Ranges(TriggerData t) + { + if(Listen == 0) + return false; + int from; + int to; + if(!int.TryParse(t.Match.Groups[1].Value, out from) || + !int.TryParse(t.Match.Groups[2].Value, out to)) + return false; + + if(!gqRanges.ContainsKey(from)) + gqRanges[from] = new SortedDictionary>(); + if(!gqRanges[from].ContainsKey(to)) + gqRanges[from][to] = new List(); + gqRanges[from][to].Add(t.Match.Groups[3].Length == 3); + if(t.Match.Groups[3].Length != 3) + count++; + if(to == 201) + { + nt++; + if(nt == 3) + { + StringBuilder str = new StringBuilder(); + int i = 0; + int myGQ = 0; + foreach(KeyValuePair>> x in gqRanges) + { + foreach(KeyValuePair> y in x.Value) + { + foreach(bool z in y.Value) + { + if(forLevel < x.Key || forLevel > y.Key || z) + str.Append(z ? "@r" : "@g"); + else + { + str.Append("@G"); + myGQ++; + } + str.Append("(" + string.Format("{0,3}", x.Key) + " - " + string.Format("{0,3}", y.Key) + + ") "); + i++; + if(i == 6) + { + World.Instance.SendMessage(str.ToString(), ClientMask); + i = 0; + str.Remove(0, str.Length); + } + } + } + } + + if(i > 0) + World.Instance.SendMessage(str.ToString(), ClientMask); + + double chance = 0; + if(count > 0 && myGQ > 0) + chance = (double)myGQ / (double)count * 100.0; + World.Instance.SendMessage("@wChance that the next global quest will be for " + (forLevel != charLevel ? ("level " + forLevel) : "your level") + " is @Y" + string.Format("{0:0.00}", chance).Replace(',', '.') + "%@w.", ClientMask); + if(forLevel == charLevel) + World.Instance.SendMessage("@wUse '@Wgqpredict @w' to see from the viewpoint of another level.", ClientMask); + Listen = 0; + } + } + return true; + } + + private bool Level(TriggerData t) + { + int i; + if(int.TryParse(t.Match.Groups[1].Value, out i)) + charLevel = i; + return false; + } + + private bool Start(TriggerData t) + { + nt = 0; + gqRanges.Clear(); + count = 0; + if(Listen > 0) + { + Listen--; + return true; + } + return false; + } + + private bool Delim(TriggerData t) + { + if(Listen > 0) + { + Listen--; + return true; + } + return false; + } + } +} diff --git a/GQPredict/GQPredict.csproj b/GQPredict/GQPredict.csproj new file mode 100644 index 0000000..c27449e --- /dev/null +++ b/GQPredict/GQPredict.csproj @@ -0,0 +1,90 @@ + + + + Debug + AnyCPU + 9.0.30729 + 2.0 + {BE332B80-9B00-4B31-A3D9-15E85B2BEA83} + Library + Properties + GQPredict + GQPredict + v3.5 + 512 + + + + + 3.5 + publish\ + true + Disk + false + Foreground + 7 + Days + false + false + true + 0 + 1.0.0.%2a + false + false + true + + + true + full + false + ..\..\..\..\Desktop\MushProxy-Build\Plugins\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + ..\..\..\..\Desktop\MushProxy-Build\Plugins\ + TRACE + prompt + 4 + + + + False + ..\ProxyCore\bin\ProxyCore.dll + + + + 3.5 + + + 3.5 + + + 3.5 + + + + + + + + + + + False + .NET Framework 3.5 SP1 + true + + + + + \ No newline at end of file diff --git a/GQPredict/Properties/.svn/all-wcprops b/GQPredict/Properties/.svn/all-wcprops new file mode 100644 index 0000000..97387e4 --- /dev/null +++ b/GQPredict/Properties/.svn/all-wcprops @@ -0,0 +1,11 @@ +K 25 +svn:wc:ra_dav:version-url +V 42 +/svn/!svn/ver/2/trunk/GQPredict/Properties +END +AssemblyInfo.cs +K 25 +svn:wc:ra_dav:version-url +V 58 +/svn/!svn/ver/2/trunk/GQPredict/Properties/AssemblyInfo.cs +END diff --git a/GQPredict/Properties/.svn/desktop.ini b/GQPredict/Properties/.svn/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/GQPredict/Properties/.svn/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/GQPredict/Properties/.svn/dir-prop-base b/GQPredict/Properties/.svn/dir-prop-base new file mode 100644 index 0000000..f1b96ea --- /dev/null +++ b/GQPredict/Properties/.svn/dir-prop-base @@ -0,0 +1,5 @@ +K 14 +bugtraq:number +V 4 +true +END diff --git a/GQPredict/Properties/.svn/entries b/GQPredict/Properties/.svn/entries new file mode 100644 index 0000000..8c7e7b3 --- /dev/null +++ b/GQPredict/Properties/.svn/entries @@ -0,0 +1,62 @@ +10 + +dir +58 +http://proxymud.googlecode.com/svn/trunk/GQPredict/Properties +http://proxymud.googlecode.com/svn + + + +2012-01-17T10:55:35.805502Z +2 +default8p@gmail.com +has-props + + + + + + + + + + + + + +8a6e9f07-fe1d-2472-fcf8-0b435762827a + +AssemblyInfo.cs +file + + + + +2016-03-25T22:18:43.000137Z +8de3c977f2718ff572dfd8c126340590 +2012-01-17T10:55:35.805502Z +2 +default8p@gmail.com + + + + + + + + + + + + + + + + + + + + + +1430 + diff --git a/GQPredict/Properties/.svn/prop-base/desktop.ini b/GQPredict/Properties/.svn/prop-base/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/GQPredict/Properties/.svn/prop-base/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/GQPredict/Properties/.svn/props/desktop.ini b/GQPredict/Properties/.svn/props/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/GQPredict/Properties/.svn/props/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/GQPredict/Properties/.svn/text-base/AssemblyInfo.cs.svn-base b/GQPredict/Properties/.svn/text-base/AssemblyInfo.cs.svn-base new file mode 100644 index 0000000..fd4407b --- /dev/null +++ b/GQPredict/Properties/.svn/text-base/AssemblyInfo.cs.svn-base @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("GQPredict")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("GQPredict")] +[assembly: AssemblyCopyright("Copyright © 2012")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("9710e6e6-243f-4053-8c8b-4c877d57a05a")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/GQPredict/Properties/.svn/text-base/desktop.ini b/GQPredict/Properties/.svn/text-base/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/GQPredict/Properties/.svn/text-base/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/GQPredict/Properties/.svn/tmp/desktop.ini b/GQPredict/Properties/.svn/tmp/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/GQPredict/Properties/.svn/tmp/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/GQPredict/Properties/.svn/tmp/prop-base/desktop.ini b/GQPredict/Properties/.svn/tmp/prop-base/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/GQPredict/Properties/.svn/tmp/prop-base/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/GQPredict/Properties/.svn/tmp/props/desktop.ini b/GQPredict/Properties/.svn/tmp/props/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/GQPredict/Properties/.svn/tmp/props/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/GQPredict/Properties/.svn/tmp/text-base/desktop.ini b/GQPredict/Properties/.svn/tmp/text-base/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/GQPredict/Properties/.svn/tmp/text-base/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/GQPredict/Properties/AssemblyInfo.cs b/GQPredict/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..fd4407b --- /dev/null +++ b/GQPredict/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("GQPredict")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("GQPredict")] +[assembly: AssemblyCopyright("Copyright © 2012")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("9710e6e6-243f-4053-8c8b-4c877d57a05a")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/GQPredict/Properties/desktop.ini b/GQPredict/Properties/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/GQPredict/Properties/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/GQPredict/desktop.ini b/GQPredict/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/GQPredict/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/Jayrock.Json.dll b/Jayrock.Json.dll new file mode 100644 index 0000000..eb1a3fa Binary files /dev/null and b/Jayrock.Json.dll differ diff --git a/Mapper/.svn/all-wcprops b/Mapper/.svn/all-wcprops new file mode 100644 index 0000000..8150d33 --- /dev/null +++ b/Mapper/.svn/all-wcprops @@ -0,0 +1,47 @@ +K 25 +svn:wc:ra_dav:version-url +V 29 +/svn/!svn/ver/57/trunk/Mapper +END +Edit.cs +K 25 +svn:wc:ra_dav:version-url +V 37 +/svn/!svn/ver/56/trunk/Mapper/Edit.cs +END +Area.cs +K 25 +svn:wc:ra_dav:version-url +V 37 +/svn/!svn/ver/30/trunk/Mapper/Area.cs +END +Exit.cs +K 25 +svn:wc:ra_dav:version-url +V 37 +/svn/!svn/ver/56/trunk/Mapper/Exit.cs +END +Room.cs +K 25 +svn:wc:ra_dav:version-url +V 37 +/svn/!svn/ver/56/trunk/Mapper/Room.cs +END +Pathfind.cs +K 25 +svn:wc:ra_dav:version-url +V 41 +/svn/!svn/ver/53/trunk/Mapper/Pathfind.cs +END +Mapper.csproj +K 25 +svn:wc:ra_dav:version-url +V 43 +/svn/!svn/ver/44/trunk/Mapper/Mapper.csproj +END +Mapper.cs +K 25 +svn:wc:ra_dav:version-url +V 39 +/svn/!svn/ver/57/trunk/Mapper/Mapper.cs +END diff --git a/Mapper/.svn/desktop.ini b/Mapper/.svn/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/Mapper/.svn/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/Mapper/.svn/dir-prop-base b/Mapper/.svn/dir-prop-base new file mode 100644 index 0000000..f1b96ea --- /dev/null +++ b/Mapper/.svn/dir-prop-base @@ -0,0 +1,5 @@ +K 14 +bugtraq:number +V 4 +true +END diff --git a/Mapper/.svn/entries b/Mapper/.svn/entries new file mode 100644 index 0000000..fef739c --- /dev/null +++ b/Mapper/.svn/entries @@ -0,0 +1,275 @@ +10 + +dir +58 +http://proxymud.googlecode.com/svn/trunk/Mapper +http://proxymud.googlecode.com/svn + + + +2012-02-08T08:41:07.654540Z +57 +default8p@gmail.com +has-props + + + + + + + + + + + + + +8a6e9f07-fe1d-2472-fcf8-0b435762827a + +Room.cs +file + + + + +2016-03-25T22:18:43.056138Z +95dbf07b465d67a2ff8ea0e5af815815 +2012-02-04T10:03:49.335283Z +56 +default8p@gmail.com + + + + + + + + + + + + + + + + + + + + + +6960 + +Pathfind.cs +file + + + + +2016-03-25T22:18:43.056138Z +ec6953b1a35794449cacb68dbe0aae26 +2012-02-01T14:22:33.260596Z +53 +default8p@gmail.com + + + + + + + + + + + + + + + + + + + + + +14532 + +Scripting +dir + +Mapper.csproj +file + + + + +2016-03-25T22:18:43.056138Z +6fd702b1cea90fece6e6b87004035eb1 +2012-01-29T09:57:36.978045Z +44 +default8p@gmail.com + + + + + + + + + + + + + + + + + + + + + +3302 + +Mapper.cs +file + + + + +2016-03-25T22:18:43.056138Z +6b66661e117b8a5de40936a66102f75f +2012-02-08T08:41:07.654540Z +57 +default8p@gmail.com + + + + + + + + + + + + + + + + + + + + + +64765 + +Edit.cs +file + + + + +2016-03-25T22:18:43.056138Z +9b3d59616a081f7a7a65d402a5e86869 +2012-02-04T10:03:49.335283Z +56 +default8p@gmail.com + + + + + + + + + + + + + + + + + + + + + +26524 + +Finders +dir + +Properties +dir + +Area.cs +file + + + + +2016-03-25T22:18:43.056138Z +dba52a3653c2be7d32371f3bf814812e +2012-01-23T07:49:14.623991Z +30 +default8p@gmail.com + + + + + + + + + + + + + + + + + + + + + +3480 + +Exit.cs +file + + + + +2016-03-25T22:18:43.056138Z +b64175e2244fa270c02ad2a954ff56c8 +2012-02-04T10:03:49.335283Z +56 +default8p@gmail.com + + + + + + + + + + + + + + + + + + + + + +3096 + diff --git a/Mapper/.svn/prop-base/desktop.ini b/Mapper/.svn/prop-base/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/Mapper/.svn/prop-base/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/Mapper/.svn/props/desktop.ini b/Mapper/.svn/props/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/Mapper/.svn/props/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/Mapper/.svn/text-base/Area.cs.svn-base b/Mapper/.svn/text-base/Area.cs.svn-base new file mode 100644 index 0000000..806ed53 --- /dev/null +++ b/Mapper/.svn/text-base/Area.cs.svn-base @@ -0,0 +1,147 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.Serialization; +using System.Text; + +namespace Mapper +{ + [DataContract] + public class Area + { + public Area(uint entry) + { + Entry = entry; + } + + [DataMember] + public readonly uint Entry; + + [DataMember] + public string Name + { + get; + internal set; + } + + [DataMember] + public string Keyword + { + get; + internal set; + } + + [DataMember] + public int MinLevel + { + get; + internal set; + } + + [DataMember] + public int MaxLevel + { + get; + internal set; + } + + [DataMember] + public int LevelLock + { + get; + internal set; + } + + [DataMember] + public uint StartRoom + { + get; + internal set; + } + + [DataMember] + internal List rooms = new List(); + + [DataMember] + internal List Portals = new List(); + + public Room[] Rooms + { + get + { + return rooms.ToArray(); + } + } + + [DataMember] + public int ExplorableRooms + { + get; + internal set; + } + + /// + /// Get all rooms in area with this name (exact, case sensitive). + /// + /// Name of room. + /// + public List GetRooms(string Name) + { + List r = new List(); + foreach(Room x in rooms) + { + if(x.Name == Name) + r.Add(x); + } + + return r; + } + + [DataMember] + internal List Flags = null; + + /// + /// Check if area has a flag. + /// + /// Flag to check for. + /// + public bool HasFlag(string flag) + { + return Flags != null && Flags.Contains(flag.ToLower().Trim()); + } + + /// + /// Add a flag to area. + /// + /// Flag to add. + public void AddFlag(string flag) + { + flag = flag != null ? flag.ToLower().Trim() : ""; + if(Flags == null) + Flags = new List(); + if(!string.IsNullOrEmpty(flag) && !Flags.Contains(flag)) + Flags.Add(flag); + } + + /// + /// Remove a flag from area. + /// + /// Flag to remove. + /// + public bool RemoveFlag(string flag) + { + flag = flag != null ? flag.ToLower().Trim() : ""; + if(Flags != null && Flags.Contains(flag)) + { + Flags.Remove(flag); + return true; + } + return false; + } + + public override string ToString() + { + return "Area '" + (!string.IsNullOrEmpty(Name) ? Name : "NULL") + "' [" + Entry + "]"; + } + } +} diff --git a/Mapper/.svn/text-base/Edit.cs.svn-base b/Mapper/.svn/text-base/Edit.cs.svn-base new file mode 100644 index 0000000..9f71d08 --- /dev/null +++ b/Mapper/.svn/text-base/Edit.cs.svn-base @@ -0,0 +1,497 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using ProxyCore; +using ProxyCore.Input; + +namespace Mapper +{ + public partial class Mapper + { + private bool CommandExit(InputData i) + { + // 1 2 3 4 + // @"^(help)?(room\s+\d+)?(\d+)?(\s+.+)?" + if(i.Arguments.Groups[1].Length != 0) + { + World.Instance.SendMessage("@wSyntax:", i.ClientMask); + World.Instance.SendMessage(string.Format("{0,-20}", "map exit") + " - show exits in current room.", i.ClientMask); + World.Instance.SendMessage(string.Format("{0,-20}", "map exit help") + " - show this message.", i.ClientMask); + World.Instance.SendMessage(string.Format("{0,-20}", "map exit room ") + " - show exits in room.", i.ClientMask); + World.Instance.SendMessage(string.Format("{0,-20}", "map exit [option] [value]") + " - change exit options / show information by exit ID.", i.ClientMask); + World.Instance.SendMessage("", i.ClientMask); + World.Instance.SendMessage("@wAvailable options for exit:", i.ClientMask); + World.Instance.SendMessage("@W" + string.Format("{0,-15}", "addflag") + " @w- Add a flag to exit.", i.ClientMask); + World.Instance.SendMessage("@W" + string.Format("{0,-15}", "removeflag") + " @w- Remove a flag from exit.", i.ClientMask); + World.Instance.SendMessage("@W" + string.Format("{0,-15}", "command") + " @w- Change command that activates exit.", i.ClientMask); + World.Instance.SendMessage("@W" + string.Format("{0,-15}", "doorcommand") + " @w- Change command that we use to open door, for example '@Wopen altar@w'. Use clear to remove this field.", i.ClientMask); + World.Instance.SendMessage("@W" + string.Format("{0,-15}", "cost") + " @w- Change cost of using exit.", i.ClientMask); + World.Instance.SendMessage("@W" + string.Format("{0,-15}", "minlevel") + " @w- Minimum level required to use exit.", i.ClientMask); + World.Instance.SendMessage("@W" + string.Format("{0,-15}", "maxlevel") + " @w- Maximum level allowed to use exit.", i.ClientMask); + World.Instance.SendMessage("@W" + string.Format("{0,-15}", "delete confirm") + " @w- Delete the exit.", i.ClientMask); + World.Instance.SendMessage("", i.ClientMask); + World.Instance.SendMessage("@wAvailable default flags:", i.ClientMask); + World.Instance.SendMessage("@W" + string.Format("{0,-15}", "recallmechanic") + " @w- This exit uses recall mechanic, can't use in norecall (for portals).", i.ClientMask); + World.Instance.SendMessage("@W" + string.Format("{0,-15}", "door") + " @w- This exit has a door.", i.ClientMask); + World.Instance.SendMessage("@W" + string.Format("{0,-15}", "nogq") + " @w- Don't use this exit on a global quest (for regular chaos portals).", i.ClientMask); + World.Instance.SendMessage("@W" + string.Format("{0,-15}", "disabled") + " @w- Don't use this exit ever.", i.ClientMask); + //World.Instance.SendMessage("@W" + string.Format("{0,-15}", "nopass") + " @w- The door is nopass.", i.ClientMask); + //World.Instance.SendMessage("@W" + string.Format("{0,-15}", "locked") + " @w- The door is locked.", i.ClientMask); + //World.Instance.SendMessage("@W" + string.Format("{0,-15}", "pickable") + " @w- Door can be pick locked or bashdoor.", i.ClientMask); + World.Instance.SendMessage("@wNote: there may be custom flags that are implemented by other plugins / scripts that aren't listed here.", i.ClientMask); + return true; + } + + if(i.Arguments.Groups[2].Length != 0 || (i.Arguments.Groups[2].Length == 0 && i.Arguments.Groups[1].Length == 0 && i.Arguments.Groups[3].Length == 0)) + { + uint roomId; + if(i.Arguments.Groups[2].Length != 0) + { + string str = i.Arguments.Groups[2].Value.Substring(4).Trim(); + if(!uint.TryParse(str, out roomId)) + { + World.Instance.SendMessage("@wInvalid room ID given. Type '@Wmap exit help@w' for syntax.", + i.ClientMask); + return true; + } + } + else + { + roomId = CurrentRoomId; + if(roomId == uint.MaxValue) + { + World.Instance.SendMessage("@wYou are in an unknown room.", i.ClientMask); + return true; + } + } + + Room r = GetRoom(roomId); + if(r == null) + { + World.Instance.SendMessage("@wNo such room in database (@R" + roomId + "@w).", i.ClientMask); + return true; + } + + World.Instance.SendMessage("@wExits in '@G" + r.Name + "@w' [@Y" + r.Entry + "@w]:", i.ClientMask); + if(r.exits.Count == 0) + World.Instance.SendMessage("@wNo exits found.", i.ClientMask); + else + { + World.Instance.SendMessage("@WEntry Command To", i.ClientMask); + World.Instance.SendMessage("@G====== ==================== ========================", i.ClientMask); + foreach(Exit e in r.exits) + World.Instance.SendMessage("@Y" + string.Format("{0,-6}", e.Entry) + " @W" + string.Format("{0,-20}", e.Command) + " @w[@Y" + string.Format("{0,6}", e.To.Entry) + "@w] @G" + e.To.Name, i.ClientMask); + World.Instance.SendMessage("", i.ClientMask); + World.Instance.SendMessage("@wType '@Wmap exit @w' for more information about an exit.", i.ClientMask); + World.Instance.SendMessage("@wOr '@Wmap exit help@w' for syntax.", i.ClientMask); + } + return true; + } + + if(i.Arguments.Groups[3].Length != 0) + { + uint exitId; + if(!uint.TryParse(i.Arguments.Groups[3].Value, out exitId)) + { + World.Instance.SendMessage("@wInvalid exit ID given. Type '@Wmap exit help@w' for syntax.", i.ClientMask); + return true; + } + + Exit e = GetExit(exitId); + if(e == null && IPortals.ContainsKey(exitId)) + e = IPortals[exitId]; + if(e == null) + { + World.Instance.SendMessage("@wNo such exit in database (@R" + exitId + "@w).", i.ClientMask); + return true; + } + + if(i.Arguments.Groups[4].Length != 0) + { + string key, val; + string str = i.Arguments.Groups[4].Value.Trim(); + if(str.Contains(' ')) + { + key = str.Substring(0, str.IndexOf(' ')).ToLower(); + val = str.Substring(key.Length).Trim(); + + switch(key) + { + case "addflag": + e.AddFlag(val); + break; + + case "removeflag": + e.RemoveFlag(val); + break; + + case "command": + val = val.ToLower(); + e.Command = PathfindResult.IsDirectionCommand(val) != 'x' ? + PathfindResult.IsDirectionCommand(val).ToString() : + val; + break; + + case "doorcommand": + val = val.ToLower(); + e.DoorCommand = val != "clear" ? val : null; + break; + + case "cost": + { + uint u; + if(uint.TryParse(val, out u)) + e.Cost = u; + } break; + + case "minlevel": + { + int lvl; + if(int.TryParse(val, out lvl)) + e.MinLevel = lvl; + } break; + + case "maxlevel": + { + int lvl; + if(int.TryParse(val, out lvl)) + e.MaxLevel = lvl; + } break; + + case "delete": + { + if(val == "confirm") + { + if(e.HasFlag("portal")) + { + IPortals.Remove(e.Entry); + e.To.Area.Portals.Remove(e); + } + else + { + IExits.Remove(e.Entry); + e.From.exits.Remove(e); + } + World.Instance.SendMessage("@wDeleted exit or portal (@R" + e.Entry + "@w).", + i.ClientMask); + return true; + } + World.Instance.SendMessage("@wEnter '@Wmap exit delete confirm@w' to remove the exit.", i.ClientMask); + } break; + + default: + World.Instance.SendMessage("@wInvalid key value pair entered '@R" + key + " " + val + "@w'.", i.ClientMask); + World.Instance.SendMessage("@wUse '@Wmap exit help@w' to see syntax.", i.ClientMask); + break; + } + } + } + + World.Instance.SendMessage("@w+----------------------------------------------------------------------+", i.ClientMask); + World.Instance.SendMessage("@w| @WEntry @w: @Y" + string.Format("{0,-55}", e.Entry) + "@w|", i.ClientMask); + if(!e.HasFlag("portal")) + World.Instance.SendMessage("@w| @WFrom @w: @w[@Y" + string.Format("{0,6}", e.From.Entry) + "@w] @G" + Utility.FormatColoredString(!string.IsNullOrEmpty(e.From.Name) ? e.From.Name : "Unknown", -46) + "@w|", i.ClientMask); + World.Instance.SendMessage("@w| @WTo @w: @w[@Y" + string.Format("{0,6}", e.To.Entry) + "@w] @G" + Utility.FormatColoredString(!string.IsNullOrEmpty(e.To.Name) ? e.To.Name : "Unknown", -46) + "@w|", i.ClientMask); + World.Instance.SendMessage("@w| @WCommand @w: @c" + string.Format("{0,-55}", e.Command) + "@w|", i.ClientMask); + World.Instance.SendMessage("@w| @WDoor command@w: @c" + string.Format("{0,-55}", !string.IsNullOrEmpty(e.DoorCommand) ? e.DoorCommand : "none") + "@w|", i.ClientMask); + World.Instance.SendMessage("@w| @WCost @w: @C" + string.Format("{0,-55}", e.Cost) + "@w|", i.ClientMask); + StringBuilder strFlags = new StringBuilder(); + if(e.IFlags != null) + { + foreach(string x in e.IFlags) + { + if(strFlags.Length > 0) + strFlags.Append(", "); + strFlags.Append(x); + } + } + + string[] spl = Utility.WrapColored(strFlags.ToString(), 54, 0); + for(int j = 0; j < spl.Length; j++) + { + if(j == 0) + World.Instance.SendMessage("@w| @WFlags @w: " + string.Format("{0,-55}", spl[j]) + "@w|", i.ClientMask); + else + World.Instance.SendMessage("@w| : " + string.Format("{0,-55}", spl[j]) + "@w|", i.ClientMask); + } + + World.Instance.SendMessage("@w| @WMin level @w: @W" + string.Format("{0,-55}", e.MinLevel) + "@w|", i.ClientMask); + World.Instance.SendMessage("@w| @WMax level @w: @W" + string.Format("{0,-55}", e.MaxLevel) + "@w|", i.ClientMask); + World.Instance.SendMessage("@w+----------------------------------------------------------------------+", i.ClientMask); + if(i.Arguments.Groups[4].Length == 0) + World.Instance.SendMessage("@wSee '@Wmap exit help@w' for information on how to edit this exit.", i.ClientMask); + return true; + } + + World.Instance.SendMessage("0", i.ClientMask); + return true; + } + + private bool CommandPortal(InputData i) + { + if(IPortals.Count == 0) + { + World.Instance.SendMessage("@wYou have no portals set.", i.ClientMask); + return true; + } + + int count = 0; + World.Instance.SendMessage("@WEntry Command To", i.ClientMask); + World.Instance.SendMessage("@G======== ================ =====================================", i.ClientMask); + foreach(KeyValuePair x in IPortals) + { + World.Instance.SendMessage("@w[@Y" + string.Format("{0,6}", x.Key) + "@w] @w" + string.Format("{0,-16}", x.Value.Command) + " @M" + x.Value.To.Area.Name + " @wroom [@Y" + x.Value.To.Entry + "@w]", i.ClientMask); + count++; + } + + World.Instance.SendMessage("@C" + count + " @wportals found.", i.ClientMask); + return true; + } + + private bool CommandCreateExit(InputData i) + { + if(!i.Arguments.Success) + { + World.Instance.SendMessage("@wSyntax: map createexit [from room ID = current] \"\"", i.ClientMask); + return true; + } + + uint fromId; + uint toId; + if(i.Arguments.Groups[2].Length > 0) + { + if(!uint.TryParse(i.Arguments.Groups[1].Value, out fromId) || + !uint.TryParse(i.Arguments.Groups[2].Value.Trim(), out toId)) + { + World.Instance.SendMessage("@wSyntax: map createexit [from room ID = current] \"\"", i.ClientMask); + return true; + } + } + else + { + fromId = CurrentRoomId; + if(!uint.TryParse(i.Arguments.Groups[1].Value, out toId)) + { + World.Instance.SendMessage("@wSyntax: map createexit [from room ID = current] \"\"", i.ClientMask); + return true; + } + } + + Room from = GetRoom(fromId); + Room to = GetRoom(toId); + if(from == null || to == null) + { + World.Instance.SendMessage("@wNo such room exists in mapper database.", i.ClientMask); + return true; + } + + char dir = PathfindResult.IsDirectionCommand(i.Arguments.Groups[3].Value); + Exit e = new Exit(++_guidExit); + e.Command = dir != 'x' ? char.ToLower(dir).ToString() : i.Arguments.Groups[3].Value.ToLower(); + e.From = from; + e.To = to; + e.From.exits.Add(e); + e.From.UpdateExits(); + IExits[e.Entry] = e; + World.Instance.SendMessage("@wCreated a new exit (@R" + e.Entry + "@w).", i.ClientMask); + World.Instance.SendMessage("@wType '@Wmap exit " + e.Entry + "@w' for more information or to edit.", i.ClientMask); + return true; + } + + private bool CommandCreatePortal(InputData i) + { + if(!i.Arguments.Success) + { + World.Instance.SendMessage("@wSyntax: map createportal \"\"", i.ClientMask); + return true; + } + + uint toId; + if(!uint.TryParse(i.Arguments.Groups[1].Value, out toId)) + { + World.Instance.SendMessage("@wSyntax: map createportal \"\"", i.ClientMask); + return true; + } + + Room to = GetRoom(toId); + if(to == null) + { + World.Instance.SendMessage("@wNo such room exists in mapper database.", i.ClientMask); + return true; + } + + Exit e = new Exit(++_guidExit); + e.Command = i.Arguments.Groups[2].Value.ToLower(); + e.To = to; + e.Cost = 5; + if(e.IFlags == null) + e.IFlags = new List(); + e.IFlags.Add("portal"); + IPortals[e.Entry] = e; + to.Area.Portals.Add(e); + World.Instance.SendMessage("@wCreated a new portal (@R" + e.Entry + "@w).", i.ClientMask); + World.Instance.SendMessage("@wType '@Wmap exit " + e.Entry + "@w' for more information or to edit.", i.ClientMask); + return true; + } + + private bool CommandRoomInfo(InputData i) + { + // 1 2 3 + // @"(help)?(\d+)?(\s+.+)?" + if(i.Arguments.Success && i.Arguments.Groups[1].Length != 0) + { + World.Instance.SendMessage("@wSyntax:", i.ClientMask); + World.Instance.SendMessage(string.Format("{0,-20}", "map room") + " - show info about current room.", i.ClientMask); + World.Instance.SendMessage(string.Format("{0,-20}", "map room help") + " - show this message.", i.ClientMask); + World.Instance.SendMessage(string.Format("{0,-20}", "map room [option] [value]") + " - show info about room by ID or change it.", i.ClientMask); + World.Instance.SendMessage("", i.ClientMask); + World.Instance.SendMessage("@wAvailable options for room:", i.ClientMask); + World.Instance.SendMessage("@W" + string.Format("{0,-15}", "addflag") + " @w- Add a flag to room.", i.ClientMask); + World.Instance.SendMessage("@W" + string.Format("{0,-15}", "removeflag") + " @w- Remove a flag from room.", i.ClientMask); + World.Instance.SendMessage("@W" + string.Format("{0,-15}", "addcflag") + " @w- Add a custom flag to room.", i.ClientMask); + World.Instance.SendMessage("@W" + string.Format("{0,-15}", "removecflag") + " @w- Remove a custom flag from room.", i.ClientMask); + World.Instance.SendMessage("@W" + string.Format("{0,-15}", "name") + " @w- Change name of room.", i.ClientMask); + World.Instance.SendMessage("@W" + string.Format("{0,-15}", "entrycost") + " @w- Change cost of entering room.", i.ClientMask); + World.Instance.SendMessage("@W" + string.Format("{0,-15}", "leavecost") + " @w- Change cost of leaving room.", i.ClientMask); + //World.Instance.SendMessage("@W" + string.Format("{0,-15}", "healrate") + " @w- Change heal rate.", i.ClientMask); + //World.Instance.SendMessage("@W" + string.Format("{0,-15}", "manarate") + " @w- Change mana rate.", i.ClientMask); + //World.Instance.SendMessage("@W" + string.Format("{0,-15}", "sector") + " @w- Change sector.", i.ClientMask); + return true; + } + + uint roomId; + if(i.Arguments.Success && i.Arguments.Groups[2].Length != 0) + { + if(!uint.TryParse(i.Arguments.Groups[2].Value, out roomId)) + { + World.Instance.SendMessage("@wInvalid room ID given (@R" + i.Arguments.Groups[2].Value + "@w).", i.ClientMask); + World.Instance.SendMessage("@wUse '@Wmap roominfo help@w' to see syntax.", i.ClientMask); + return true; + } + } + else + { + roomId = CurrentRoomId; + if(roomId == uint.MaxValue) + { + World.Instance.SendMessage("@wYou are in an invalid room.", i.ClientMask); + World.Instance.SendMessage("@wUse '@Wmap roominfo help@w' to see syntax.", i.ClientMask); + return true; + } + } + + Room r = GetRoom(roomId); + if(r == null) + { + World.Instance.SendMessage("@wNo such room in database (@R" + roomId + "@w).", i.ClientMask); + return true; + } + + if(i.Arguments.Success && i.Arguments.Groups[2].Length != 0 && i.Arguments.Groups[3].Length != 0) + { + string key, val; + string str = i.Arguments.Groups[3].Value.Trim(); + if(str.Contains(' ')) + { + key = str.Substring(0, str.IndexOf(' ')).ToLower(); + val = str.Substring(key.Length).Trim(); + + switch(key) + { + case "addflag": + r.AddFlag(val); + break; + + case "removeflag": + r.RemoveFlag(val); + break; + + case "addcflag": + r.AddCustomFlag(val); + break; + + case "removecflag": + r.RemoveCustomFlag(val); + break; + + case "name": + r.Name = val; + break; + + case "entrycost": + { + uint u; + if(uint.TryParse(val, out u)) + r.EntryCost = u; + } break; + + case "leavecost": + { + uint u; + if(uint.TryParse(val, out u)) + r.LeaveCost = u; + } break; + } + } + } + + World.Instance.SendMessage("@w+----------------------------------------------------------------------+", i.ClientMask); + World.Instance.SendMessage("@w| @WEntry @w: @Y" + string.Format("{0,-55}", r.Entry) + "@w|", i.ClientMask); + World.Instance.SendMessage("@w| @WName @w: @G" + Utility.FormatColoredString(!string.IsNullOrEmpty(r.Name) ? r.Name : "Unknown", -55) + "@w|", i.ClientMask); + World.Instance.SendMessage("@w| @WArea @w: @M" + string.Format("{0,-55}", !string.IsNullOrEmpty(r.Area.Name) ? r.Area.Name : "Unknown") + "@w|", i.ClientMask); + { + StringBuilder strFlags = new StringBuilder(); + if(r.IFlags != null) + { + foreach(string x in r.IFlags) + { + if(strFlags.Length > 0) + strFlags.Append(", "); + strFlags.Append(x); + } + } + + string[] spl = Utility.WrapColored(strFlags.ToString(), 54, 0); + for(int j = 0; j < spl.Length; j++) + { + if(j == 0) + World.Instance.SendMessage("@w| @WFlags @w: " + string.Format("{0,-55}", spl[j]) + "@w|", + i.ClientMask); + else + World.Instance.SendMessage("@w| : " + string.Format("{0,-55}", spl[j]) + "@w|", + i.ClientMask); + } + } + + { + StringBuilder strFlags = new StringBuilder(); + if(r.CFlags != null) + { + foreach(string x in r.CFlags) + { + if(strFlags.Length > 0) + strFlags.Append(", "); + strFlags.Append(x); + } + } + + string[] spl = Utility.WrapColored(strFlags.ToString(), 54, 0); + for(int j = 0; j < spl.Length; j++) + { + if(j == 0) + World.Instance.SendMessage("@w| @WCustom flags@w: " + string.Format("{0,-55}", spl[j]) + "@w|", i.ClientMask); + else + World.Instance.SendMessage("@w| : " + string.Format("{0,-55}", spl[j]) + "@w|", i.ClientMask); + } + } + + // Healrate, manarate, sector + + World.Instance.SendMessage("@w+----------------------------------------------------------------------+", i.ClientMask); + if(!i.Arguments.Success || (i.Arguments.Groups[1].Length == 0 && i.Arguments.Groups[2].Length == 0 && i.Arguments.Groups[3].Length == 0)) + World.Instance.SendMessage("@wUse '@Wmap roominfo help@w' to see syntax.", i.ClientMask); + return true; + } + } +} diff --git a/Mapper/.svn/text-base/Exit.cs.svn-base b/Mapper/.svn/text-base/Exit.cs.svn-base new file mode 100644 index 0000000..e36b754 --- /dev/null +++ b/Mapper/.svn/text-base/Exit.cs.svn-base @@ -0,0 +1,136 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.Serialization; +using System.Text; + +namespace Mapper +{ + [DataContract] + public class Exit + { + public Exit(uint entry) + { + Entry = entry; + MinLevel = 0; + MaxLevel = 210; + Cost = 1; + } + + [DataMember] + public readonly uint Entry; + + [DataMember] + public int MinLevel + { + get; + internal set; + } + + [DataMember] + public int MaxLevel + { + get; + internal set; + } + + public Room From + { + get; + internal set; + } + + public Room To + { + get + { + return _to; + } + internal set + { + _to = value; + ToRoom = value != null ? value.Entry : uint.MaxValue; + } + } + + private Room _to; + + [DataMember] + internal uint ToRoom; + + [DataMember] + public string Command + { + get; + internal set; + } + + [DataMember] + public string DoorCommand + { + get; + internal set; + } + + [DataMember] + internal List IFlags = null; + + public IEnumerable Flags + { + get + { + return IFlags; + } + } + + [DataMember] + public uint Cost + { + get; + internal set; + } + + /// + /// Check if exit has a flag. + /// + /// Flag to check for. + /// + public bool HasFlag(string flag) + { + return IFlags != null && IFlags.Contains(flag.ToLower().Trim()); + } + + /// + /// Add a flag to exit. + /// + /// Flag to add. + public void AddFlag(string flag) + { + flag = flag != null ? flag.ToLower().Trim() : ""; + if(flag == "portal") + return; + if(IFlags == null) + IFlags = new List(); + if(!string.IsNullOrEmpty(flag) && !IFlags.Contains(flag)) + IFlags.Add(flag); + } + + /// + /// Remove a flag from exit. + /// + /// Flag to remove. + /// + public bool RemoveFlag(string flag) + { + flag = flag != null ? flag.ToLower().Trim() : ""; + if(flag == "portal") + return false; + if(IFlags != null && IFlags.Contains(flag)) + { + IFlags.Remove(flag); + return true; + } + return false; + } + } +} diff --git a/Mapper/.svn/text-base/Mapper.cs.svn-base b/Mapper/.svn/text-base/Mapper.cs.svn-base new file mode 100644 index 0000000..40a8d72 --- /dev/null +++ b/Mapper/.svn/text-base/Mapper.cs.svn-base @@ -0,0 +1,1607 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; +using Mapper.Scripting; +using ProxyCore; +using ProxyCore.Input; +using ProxyCore.Output; +using ProxyCore.Scripting; +using System.IO; +using System.Runtime.Serialization; + +namespace Mapper +{ + public partial class Mapper : Plugin + { + public Mapper() + : base("mapper", "Mapper") + { + Author = "Duckbat"; + Version = 15; + Description = "This plugin will record what rooms you have been in and from that can generate speedwalks for you to easily move around the world of Aardwolf."; + UpdateUrl = "www.duckbat.com/plugins/update.mapper.txt"; + Website = "code.google.com/p/proxymud/"; + + Config = new MapperConfig(); + + RegisterCommand("map", "", CommandMapper); + RegisterCommand("all", @"(.+)", CommandAll, 0, CMDFlags.None, "map"); + RegisterCommand("count", "", CommandCount, 0, CMDFlags.None, "map"); + RegisterCommand("createexit", "^(\\d+)(\\s+\\d+)?\\s+\"(.+)\"$", CommandCreateExit, 0, CMDFlags.None, "map"); + RegisterCommand("createportal", "^(\\d+)\\s+\"(.+)\"$", CommandCreatePortal, 0, CMDFlags.None, "map"); + RegisterCommand("delete", @"^(area|room|exit|portal)\s+(\d+)", CommandDelete, 3, CMDFlags.None, "map"); + RegisterCommand("exits", @"^(help)?(room\s+\d+)?(\d+)?(\s+.+)?", CommandExit, 4, CMDFlags.None, "map"); + RegisterCommand("find", @"^(room|area)(\s+exact)?(\s+case)?\s+(.+)", CommandFind, 1, CMDFlags.None, "map"); + RegisterCommand("portals", "", CommandPortal, 4, CMDFlags.None, "map"); + RegisterCommand("goto", @"(.+)", CommandGoto, 2, CMDFlags.None, "map"); + RegisterCommand("import", @"(.+)", CommandImport, 0, CMDFlags.None, "map"); + RegisterCommand("roominfo", @"^(help)?(\d+)?(\s+.+)?", CommandRoomInfo, 4, CMDFlags.None, "map"); + RegisterCommand("save", @"(.+)", CommandSave, 4, CMDFlags.None, "map"); + RegisterCommand("unmapped", @"^(go|all)$", CommandUnmapped, 2, CMDFlags.None, "map"); + RegisterCommand("unreconed", @"^(go|all)$", CommandUnreconed, 3, CMDFlags.None, "map"); + + RegisterTrigger("room.id", @"^\$gmcp\.room\.info\.num (-?\d+)$", TriggerRoomInfoNum); + RegisterTrigger("room.name", @"^\$gmcp\.room\.info\.name (.*)$", TriggerRoomInfoName); + RegisterTrigger("room.area", @"^\$gmcp\.room\.info\.zone (.*)$", TriggerRoomInfoArea); + RegisterTrigger("room.exit", @"^\$gmcp\.room\.info\.exits\.(\w) (-?\d+)$", TriggerRoomInfoExits); + RegisterTrigger("room.finish", @"^\$gmcp\.room\.info\.coords?\.", TriggerRoomInfoFinish); + RegisterTrigger("char.level", @"^\$gmcp\.char\.status\.level (\d+)$", TriggerCharStatusLevel); + RegisterTrigger("char.tier", @"^\$gmcp\.char\.base\.tier (\d+)$", TriggerCharBaseTier); + RegisterTrigger("char.remorts", @"^\$gmcp\.char\.base\.remorts (\d+)$", TriggerCharBaseRemorts); + RegisterTrigger("gq.join", @"@wYou have now joined the quest. See 'help gquest' for available commands.", + TriggerJoinedGQ, TriggerFlags.NotRegex); + RegisterTrigger("gq.left", @"@wYou are no longer part of the current quest.", TriggerLeftGQ, + TriggerFlags.NotRegex); + RegisterTrigger("gq.win", + @"^@RGlobal Quest@Y: @wThe global quest has been won by @Y\w+ @w- @Y\d+.. @wwin\.$", + TriggerLeftGQ); + RegisterTrigger("gq.quit", @"@wYou are no longer part of the current quest.", TriggerLeftGQ, TriggerFlags.NotRegex); + RegisterTrigger("where.name", @"^@GYou are in area : (.+)", TriggerWhereName); + RegisterTrigger("where.level", @"^@GLevel range is : @R(\d+) to (\d+)", TriggerWhereLevel); + RegisterTrigger("areas.start", @"^@WFrom To Lock Keyword Area Name", TriggerAreasStart); + RegisterTrigger("areas.end", @"@w---------------------------------------------------------------", TriggerAreasEnd, TriggerFlags.NotRegex); + RegisterTrigger("areas.entry", @"^\s+@w(\d+)\s+(\d+)\s+(@R\d+\s+)?@g([\d\w]+)\s+@c(.+)", TriggerAreasEntry); + RegisterTrigger("home", @"@wYou cannot return home from this room.", TriggerNoRecall, TriggerFlags.NotRegex); + RegisterTrigger("recall", @"@wYou cannot recall from this room.", TriggerNoRecall, TriggerFlags.NotRegex); + RegisterTrigger("portal", @"@wMagic walls bounce you back.", TriggerPrison, TriggerFlags.NotRegex); + RegisterTrigger("recon.area", @"^@wArea Name : (.+)", TriggerReconArea); + RegisterTrigger("recon.sector", @"^@wSector type is : (.+)", TriggerReconSector); + RegisterTrigger("recon.flags", @"^@wBase flags :(.*)", TriggerReconFlags); + RegisterTrigger("recon.healrate", @"^@wHeal rate : @c(-?\d+)", TriggerReconHealRate); + RegisterTrigger("recon.manarate", @"^@wMana rate : @c(-?\d+)", TriggerReconManaRate); + RegisterTrigger("recon.unable", "@wYou cannot perform reconnaissance in this room.", TriggerNoRecon, TriggerFlags.NotRegex); + RegisterTrigger("tags.exits", @"^(@w)?\{exits\}(.*)", TriggerTagsExits); + + Load(); + + // If we don't have this unmapped area set then create it, just so we can save rooms we haven't explored yet + if(GetArea(uint.MaxValue) == null) + { + Area a = new Area(uint.MaxValue); + a.Keyword = "mapper_unmapped"; + a.Name = "Mapper unmapped rooms"; + IAreas[a.Entry] = a; + } + + Path_Init(); + } + + private const string DBFileName = "mapperdb.xml"; + private const string DBFileBackup = "mapperdb_backup.xml"; + + private int Level = 1; + private int Tier = 0; + private bool ListenArea = false; + private int Remorts = 1; + private bool HasGQ = false; + private long WhenSave = 0; + + private void OnDeleted(Room r) + { + List del = new List(); + foreach(KeyValuePair x in IExits) + { + if(x.Key == uint.MaxValue || x.Key == 0) + continue; + if(!IRooms.ContainsKey(x.Value.ToRoom)) + del.Add(x.Key); + } + + foreach(uint x in del) + { + IExits[x].From.exits.Remove(IExits[x]); + IExits.Remove(x); + } + } + + /// + /// Fill a pathfinder with our current character values and return if we were successful in doing that. + /// + /// + public bool FillPathFinder(Pathfinder p) + { + Room r; + if(CurrentRoomId == uint.MaxValue || (r = GetRoom(CurrentRoomId)) == null || r.Area.Entry == uint.MaxValue) + return false; + p.CharacterLevel = Level; + p.CharacterTier = Tier; + p.CanUseRecalls = true; + p.CanUsePortals = true; + p.IsGlobalQuest = HasGQ; + p.IsSingleClassTier0 = Tier == 0 && Remorts == 1; + p.StartRooms = new[] { r }; + return true; + } + + #region Commands + private bool CommandAll(InputData i) + { + string[] spl; + if(!i.Arguments.Success || (spl = i.Arguments.Groups[1].Value.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries)).Length == 0) + { + World.Instance.SendMessage("@wSyntax: map all [room id] ...", i.ClientMask); + return true; + } + + List rooms = new List(); + bool hadConfirm = false; + foreach(string x in spl) + { + uint u; + if(uint.TryParse(x, out u)) + { + Room r = GetRoom(u); + if(r != null && !rooms.Contains(r)) + rooms.Add(r); + } + else if(x.ToLower() == "confirm") + hadConfirm = true; + } + + if(rooms.Count < 2) + { + World.Instance.SendMessage("@wSyntax: map all [room id] ...", i.ClientMask); + return true; + } + + if(rooms.Count > 10 && !hadConfirm) + { + World.Instance.SendMessage("@RWarning! @wEntered more than 10 rooms. This may be too slow to finish. Enter confirm at the end if you are sure you wish to do this pathfind.", i.ClientMask); + return true; + } + + int ms = Environment.TickCount; + PathFinder_VisitAll pf = new PathFinder_VisitAll(this, rooms.ToArray()); + FillPathFinder(pf); + PathfindResult pr = Get(pf); + ms = Environment.TickCount - ms; + + World.Instance.SendMessage("@wPathfind took @W" + ms + " @wms.", i.ClientMask); + if(!pr.Success) + { + World.Instance.SendMessage("@wPathfind failed.", i.ClientMask); + return true; + } + + string sw = PathfindResult.Speedwalk(pr.Path); + World.Instance.SendMessage("@wCost: @W" + pr.Cost, i.ClientMask); + World.Instance.SendMessage("@wSW: " + sw, i.ClientMask); + return true; + } + + private bool CommandImport(InputData i) + { + if(!i.Arguments.Success) + { + World.Instance.SendMessage("@wSyntax: map import ", i.ClientMask); + return true; + } + + StreamReader f; + try + { + f = new StreamReader(i.Arguments.Groups[1].Value); + } + catch + { + World.Instance.SendMessage("@wFailed opening file. Make sure it is in the same folder as ProxyMud.exe and make sure you entered the file extension too.", i.ClientMask); + return true; + } + + string l; + while((l = f.ReadLine()) != null) + { + if(l.StartsWith("{area}")) + { + l = l.Substring(6); + string key = l.Substring(0, l.IndexOf('\t')).Trim().ToLower(); + l = l.Substring(l.IndexOf('\t') + 1); + + if(string.IsNullOrEmpty(key)) + continue; + + if(GetArea(key) == null) + { + Area a = new Area(++_guidArea); + a.Name = l; + a.Keyword = key; + IAreas[a.Entry] = a; + } + else if(string.IsNullOrEmpty(GetArea(key).Name)) + GetArea(key).Name = l; + } + else if(l.StartsWith("{room}")) + { + l = l.Substring(6); + string key = l.Substring(0, l.IndexOf('\t')); + uint k; + if(!uint.TryParse(key, out k)) + continue; + + l = l.Substring(l.IndexOf('\t') + 1); + string name = l.Substring(0, l.IndexOf('\t')); + + l = l.Substring(l.IndexOf('\t') + 1).Trim().ToLower(); + Area a = GetArea(l); + if(a == null) + { + a = new Area(++_guidArea); + a.Keyword = l; + IAreas[a.Entry] = a; + } + + Room r = GetRoom(k); + if(r == null) + { + r = new Room(k); + IRooms[k] = r; + r.Name = name; + r.Area = a; + } + else + { + if(r.Area != a) + r.Area = a; + r.Name = name; + } + } + else if(l.StartsWith("{exit}")) + { + l = l.Substring(6); + string cmd = l.Substring(0, l.IndexOf('\t')); + l = l.Substring(l.IndexOf('\t') + 1); + + string fr = l.Substring(0, l.IndexOf('\t')); + l = l.Substring(l.IndexOf('\t') + 1); + + string tr = l.Substring(0, l.IndexOf('\t')); + l = l.Substring(l.IndexOf('\t') + 1); + + uint from; + uint to; + int minLevel; + + if(!uint.TryParse(fr, out from) || !uint.TryParse(tr, out to) || !int.TryParse(l, out minLevel)) + continue; + + Room fromroom = GetRoom(from); + Room toroom = GetRoom(to); + if(fromroom == null || toroom == null) + continue; + + string door = ""; + if(cmd.Contains(';')) + { + door = cmd.Substring(0, cmd.IndexOf(';')); + if(!door.StartsWith("open ") && !door.StartsWith("ope ") && !door.StartsWith("op ") && + !door.StartsWith("o ")) + door = ""; + else + { + door = door.Substring(door.IndexOf(' ') + 1).Trim(); + char dir = PathfindResult.IsDirectionCommand(door); + if(dir == 'x') + door = "open " + door; + else + door = "o"; + cmd = cmd.Substring(cmd.IndexOf(';') + 1); + } + } + + Exit e = null; + if(PathfindResult.IsDirectionCommand(cmd) != 'x') + e = fromroom.GetExit(PathfindResult.IsDirectionCommand(cmd)); + else + e = fromroom.GetExit(cmd); + if(e == null) + { + e = new Exit(++_guidExit); + e.Command = PathfindResult.IsDirectionCommand(cmd) != 'x' ? PathfindResult.IsDirectionCommand(cmd).ToString() : cmd; + e.From = fromroom; + e.To = toroom; + e.From.exits.Add(e); + e.From.UpdateExits(); + IExits[e.Entry] = e; + + if(door == "o") + e.AddFlag("door"); + else if(!string.IsNullOrEmpty(door)) + e.DoorCommand = door; + } + } + else if(l.Length == 0) + continue; + else + { + f.Close(); + World.Instance.SendMessage("@wInvalid mapper format. You must convert it to readable format with the converter.", i.ClientMask); + return true; + } + } + + f.Close(); + World.Instance.SendMessage("@wDone importing missing rooms / areas / exits from MUSH database.", i.ClientMask); + return true; + } + + private bool CommandSave(InputData i) + { + string fileName = DBFileName; + if(i.Arguments.Success) + fileName = i.Arguments.Groups[0].Value; + + Save(fileName); + World.Instance.SendMessage("@wSaved mapper database to '@W" + fileName + "@w'.", i.ClientMask); + return true; + } + + private bool CommandUnmapped(InputData i) + { + if(!i.Arguments.Success) + { + Room r = GetRoom(CurrentRoomId); + if(r == null) + { + World.Instance.SendMessage("@wYou are in an unkown room.", i.ClientMask); + return true; + } + + uint c = 0; + foreach(KeyValuePair x in IRooms) + { + if(x.Value.Area.Entry != r.Area.Entry) + continue; + + bool f = false; + foreach(Exit e in x.Value.exits) + { + if(e.To.Area.Entry == uint.MaxValue) + { + f = true; + break; + } + } + + if(f) + c++; + } + + if(c == 0) + { + World.Instance.SendMessage("@wDidn't find any rooms with exits to unmapped rooms in this area.", + i.ClientMask); + } + else + { + World.Instance.SendMessage( + "@wFound @C" + c + " @wroom" + (c != 1 ? "s" : "") + + " in this area that have exits to unmapped rooms.", i.ClientMask); + } + World.Instance.SendMessage("@wUse '@Wmap unmapped all@w' to see areas where exits to unmapped rooms are found.", i.ClientMask); + World.Instance.SendMessage("@wUse '@Wmap unmapped go@w' to go to the closest room where an exit to unmapped room is found (in current area only).", i.ClientMask); + return true; + } + + if(i.Arguments.Groups[1].Value.ToLower() == "all") + { + SortedDictionary> Unmapped = new SortedDictionary>(); + foreach(KeyValuePair x in IRooms) + { + bool f = false; + foreach(Exit e in x.Value.exits) + { + if(e.To.Area.Entry == uint.MaxValue) + { + f = true; + break; + } + } + + if(f) + { + string n = x.Value.Area.Name; + if(string.IsNullOrEmpty(n)) + n = x.Value.Area.Keyword; + if(!Unmapped.ContainsKey(n)) + Unmapped[n] = new Dictionary(); + if(!Unmapped[n].ContainsKey(x.Value.Area)) + Unmapped[n][x.Value.Area] = 1; + else + Unmapped[n][x.Value.Area]++; + } + } + + if(Unmapped.Count == 0) + World.Instance.SendMessage("@wDidn't find any rooms in any area that have exits to unmapped rooms.", i.ClientMask); + else + { + World.Instance.SendMessage("@WEntry Area Unmapped rooms", i.ClientMask); + World.Instance.SendMessage("@G===== ============================================ ==============", i.ClientMask); + int c = 0; + foreach(KeyValuePair> x in Unmapped) + { + foreach(KeyValuePair y in x.Value) + { + c++; + World.Instance.SendMessage("@Y" + string.Format("{0,-5}", y.Key.Entry) + " @M" + string.Format("{0,-" + "============================================".Length + "}", (!string.IsNullOrEmpty(y.Key.Name) ? y.Key.Name : y.Key.Keyword)) + " @C" + y.Value, i.ClientMask); + } + } + + World.Instance.SendMessage("@wFound @C" + c + " @warea" + (c != 1 ? "s" : "") + " with exits to unmapped rooms.", i.ClientMask); + } + return true; + } + + if(GetRoom(CurrentRoomId) == null) + { + World.Instance.SendMessage("@wYou are in an invalid room.", i.ClientMask); + return true; + } + + Pathfinder_Unmapped p = new Pathfinder_Unmapped(false); + FillPathFinder(p); + PathfindResult pr = Get(p); + if(!pr.Success) + { + World.Instance.SendMessage("@wCouldn't find a path or there weren't any rooms in this area with exits that lead to unmapped rooms.", i.ClientMask); + return true; + } + Goto(pr); + return true; + } + + private bool CommandUnreconed(InputData i) + { + if(!i.Arguments.Success) + { + Room r = GetRoom(CurrentRoomId); + if(r == null) + { + World.Instance.SendMessage("@wYou are in an unknown room.", i.ClientMask); + return true; + } + + uint c = 0; + foreach(KeyValuePair x in IRooms) + { + if(x.Value.Area.Entry != r.Area.Entry) + continue; + + bool f = false; + foreach(Exit e in x.Value.exits) + { + if(e.To.Area.Entry == uint.MaxValue) + { + f = true; + break; + } + } + if(!f && !x.Value.HasCustomFlag("reconed")) + f = true; + + if(f) + c++; + } + + if(c == 0) + { + World.Instance.SendMessage("@wDidn't find any rooms with exits to unmapped rooms or unreconed in this area.", + i.ClientMask); + } + else + { + World.Instance.SendMessage( + "@wFound @C" + c + " @wroom" + (c != 1 ? "s" : "") + + " in this area that have exits to unmapped rooms or aren't reconed.", i.ClientMask); + } + World.Instance.SendMessage("@wUse '@Wmap unreconed all@w' to see areas where exits to unmapped rooms or rooms that aren't reconed are found.", i.ClientMask); + World.Instance.SendMessage("@wUse '@Wmap unreconed go@w' to go to the closest room where an exit to unmapped room is found or that isn't reconed (in current area only).", i.ClientMask); + return true; + } + + if(i.Arguments.Groups[1].Value.ToLower() == "all") + { + SortedDictionary> Unmapped = new SortedDictionary>(); + foreach(KeyValuePair x in IRooms) + { + bool f = false; + foreach(Exit e in x.Value.exits) + { + if(e.To.Area.Entry == uint.MaxValue) + { + f = true; + break; + } + } + if(!f && !x.Value.HasCustomFlag("reconed")) + f = true; + + if(f) + { + string n = x.Value.Area.Name; + if(string.IsNullOrEmpty(n)) + n = x.Value.Area.Keyword; + if(!Unmapped.ContainsKey(n)) + Unmapped[n] = new Dictionary(); + if(!Unmapped[n].ContainsKey(x.Value.Area)) + Unmapped[n][x.Value.Area] = 1; + else + Unmapped[n][x.Value.Area]++; + } + } + + if(Unmapped.Count == 0) + World.Instance.SendMessage("@wDidn't find any rooms in any area that have exits to unmapped rooms or that aren't reconed.", i.ClientMask); + else + { + World.Instance.SendMessage("@WEntry Area Unmapped/Unreconed rooms", i.ClientMask); + World.Instance.SendMessage("@G===== ============================================ ========================", i.ClientMask); + int c = 0; + foreach(KeyValuePair> x in Unmapped) + { + foreach(KeyValuePair y in x.Value) + { + c++; + World.Instance.SendMessage("@Y" + string.Format("{0,-5}", y.Key.Entry) + " @M" + string.Format("{0,-" + "============================================".Length + "}", (!string.IsNullOrEmpty(y.Key.Name) ? y.Key.Name : y.Key.Keyword)) + " @C" + y.Value, i.ClientMask); + } + } + + World.Instance.SendMessage("@wFound @C" + c + " @warea" + (c != 1 ? "s" : "") + " with exits to unmapped rooms or unreconed rooms.", i.ClientMask); + } + return true; + } + + if(GetRoom(CurrentRoomId) == null) + { + World.Instance.SendMessage("@wYou are in an invalid room.", i.ClientMask); + return true; + } + + Pathfinder_Unmapped p = new Pathfinder_Unmapped(true); + FillPathFinder(p); + PathfindResult pr = Get(p); + if(!pr.Success) + { + World.Instance.SendMessage("@wCouldn't find a path or there weren't any rooms in this area with exits that lead to unmapped rooms or that aren't reconed.", i.ClientMask); + return true; + } + Goto(pr); + return true; + } + + private bool CommandDelete(InputData i) + { + // @"^(area|room|exit|portal)\s+(\d+)" + uint id; + if(!i.Arguments.Success || !uint.TryParse(i.Arguments.Groups[2].Value, out id) || id == uint.MaxValue) + { + World.Instance.SendMessage("@wSyntax: map delete area ", i.ClientMask); + World.Instance.SendMessage(" @wmap delete exit ", i.ClientMask); + World.Instance.SendMessage(" @wmap delete portal ", i.ClientMask); + World.Instance.SendMessage(" @wmap delete room ", i.ClientMask); + return true; + } + + string w = i.Arguments.Groups[1].Value.ToLower(); + + switch(w) + { + case "area": + { + Area a = GetArea(id); + if(a == null) + { + World.Instance.SendMessage("@wNo such area (@R" + id + "@w).", i.ClientMask); + return true; + } + + IAreas.Remove(a.Entry); + foreach(Room r in a.rooms) + { + IRooms.Remove(r.Entry); + foreach(Exit e in r.exits) + IExits.Remove(e.Entry); + OnDeleted(r); + } + + if(!string.IsNullOrEmpty(a.Name)) + World.Instance.SendMessage("@wDeleted area '@M" + a.Name + "@w'.", i.ClientMask); + else + World.Instance.SendMessage("@wDeleted area '@w" + a.Keyword + "@w'.", i.ClientMask); + } break; + + case "exit": + case "portal": + { + Exit e = GetExit(id); + if(e == null) + e = IPortals.ContainsKey(id) ? IPortals[id] : null; + if(e == null) + { + World.Instance.SendMessage("@wNo such exit or portal (@R" + id + "@w).", i.ClientMask); + return true; + } + + IExits.Remove(e.Entry); + IPortals.Remove(e.Entry); + if(!e.HasFlag("portal")) + e.From.exits.Remove(e); + else + e.To.Area.Portals.Remove(e); + + World.Instance.SendMessage("@wDeleted exit '@Y" + e.Entry + "@w'.", i.ClientMask); + } break; + + case "room": + { + Room r = GetRoom(id); + if(r == null) + { + World.Instance.SendMessage("@wNo such room (@R" + id + "@w).", i.ClientMask); + return true; + } + + IRooms.Remove(r.Entry); + r.Area.rooms.Remove(r); + OnDeleted(r); + World.Instance.SendMessage("@wDeleted room '@G" + r.Name + "@w'.", i.ClientMask); + } break; + } + + return true; + } + + private bool CommandFind(InputData i) + { + // @"^(room|area)(\s+exact)?(\s+case)?\s+(.+)" + if(!i.Arguments.Success) + { + World.Instance.SendMessage("@wSyntax: map find room [exact] [case] ", i.ClientMask); + World.Instance.SendMessage(" @wmap find area [exact] [case] ", i.ClientMask); + return true; + } + + if(i.Arguments.Groups[1].Value.ToLower() == "room") + { + string Str = i.Arguments.Groups[4].Value; + if(i.Arguments.Groups[3].Length == 0) + Str = Str.ToLower(); + List Found = new List(); + foreach(KeyValuePair x in IRooms) + { + string Name = x.Value.Name; + if(string.IsNullOrEmpty(Name)) + continue; + if(i.Arguments.Groups[3].Length == 0) + Name = Name.ToLower(); + + if(i.Arguments.Groups[2].Length != 0) + { + if(Name == Str) + Found.Add(x.Value); + } + else if(Name.Contains(Str)) + Found.Add(x.Value); + } + + if(Found.Count == 0) + World.Instance.SendMessage("@wFound nothing!", i.ClientMask); + else + { + World.Instance.SendMessage("@WEntry Name Area", i.ClientMask); + World.Instance.SendMessage("@G====== ================================ ===============================", i.ClientMask); + foreach(Room f in Found) + { + World.Instance.SendMessage("@Y" + string.Format("{0,6}", f.Entry) + " @G" + Utility.FormatColoredString(f.Name, -"================================".Length) + " " + (!string.IsNullOrEmpty(f.Area.Name) ? ("@M" + f.Area.Name) : ("@w" + f.Area.Keyword)), i.ClientMask); + } + World.Instance.SendMessage("@wFound @C" + Found.Count + " @wroom" + (Found.Count != 1 ? "s" : "") + ".", i.ClientMask); + } + } + else + { + string Str = i.Arguments.Groups[4].Value; + if(i.Arguments.Groups[3].Length == 0) + Str = Str.ToLower(); + List Found = new List(); + foreach(KeyValuePair x in IAreas) + { + string Name = x.Value.Name; + if(string.IsNullOrEmpty(Name)) + continue; + if(i.Arguments.Groups[3].Length == 0) + Name = Name.ToLower(); + + if(i.Arguments.Groups[2].Length != 0) + { + if(Name == Str) + Found.Add(x.Value); + } + else if(Name.Contains(Str)) + Found.Add(x.Value); + } + + if(Found.Count == 0) + World.Instance.SendMessage("@wFound nothing!", i.ClientMask); + else + { + World.Instance.SendMessage("@WEntry Keyword Name", i.ClientMask); + World.Instance.SendMessage("@G====== ========== ========================================", i.ClientMask); + foreach(Area f in Found) + { + World.Instance.SendMessage("@Y" + string.Format("{0,6}", f.Entry) + " @w" + Utility.FormatColoredString(f.Keyword, -10) + " @M" + f.Name, i.ClientMask); + } + World.Instance.SendMessage("@wFound @C" + Found.Count + " @warea" + (Found.Count != 1 ? "s" : "") + ".", i.ClientMask); + } + } + return true; + } + + private bool CommandMapper(InputData i) + { + World.Instance.SendMessage("@wAvailable mapper commands:", i.ClientMask); + World.Instance.SendMessage("@Y" + string.Format("{0,-20}", "map all") + " @w- Shows speedwalk that runs through all the rooms (IDs) you entered starting from your current location.", i.ClientMask); + World.Instance.SendMessage("@Y" + string.Format("{0,-20}", "map count") + " @w- Shows how many rooms you have mapped.", i.ClientMask); + World.Instance.SendMessage("@Y" + string.Format("{0,-20}", "map createexit") + " @w- Create a new exit.", i.ClientMask); + World.Instance.SendMessage("@Y" + string.Format("{0,-20}", "map createportal") + " @w- Create a new portal.", i.ClientMask); + World.Instance.SendMessage("@Y" + string.Format("{0,-20}", "map delete") + " @w- Delete a room, area or an exit.", i.ClientMask); + World.Instance.SendMessage("@Y" + string.Format("{0,-20}", "map exits") + " @w- Show exits information or edit them.", i.ClientMask); + World.Instance.SendMessage("@Y" + string.Format("{0,-20}", "map find") + " @w- Find rooms or areas in mapper.", i.ClientMask); + World.Instance.SendMessage("@Y" + string.Format("{0,-20}", "map goto") + " @w- Goto a room or an area.", i.ClientMask); + World.Instance.SendMessage("@Y" + string.Format("{0,-20}", "map import") + " @w- Import data file converted from mush mapper.", i.ClientMask); + World.Instance.SendMessage("@Y" + string.Format("{0,-20}", "map portals") + " @w- List all portals.", i.ClientMask); + World.Instance.SendMessage("@Y" + string.Format("{0,-20}", "map roominfo") + " @w- Show more information about a room or edit it.", i.ClientMask); + World.Instance.SendMessage("@Y" + string.Format("{0,-20}", "map save") + " @w- Save the mapper database now. Enter argument to save to another file.", i.ClientMask); + World.Instance.SendMessage("@Y" + string.Format("{0,-20}", "map unmapped") + " @w- Find unmapped rooms.", i.ClientMask); + World.Instance.SendMessage("@Y" + string.Format("{0,-20}", "map unreconed") + " @w- Find unmapped or unreconed rooms.", i.ClientMask); + return true; + } + + private bool CommandGoto(InputData i) + { + if(!i.Arguments.Success || i.Arguments.Groups[1].Value.Trim().Length == 0) + { + World.Instance.SendMessage("@wGo to the closest room entered.", i.ClientMask); + World.Instance.SendMessage("@wSyntax: map goto [room id] [room id]", i.ClientMask); + World.Instance.SendMessage(" @wmap goto ", i.ClientMask); + World.Instance.SendMessage(" @wmap goto ", i.ClientMask); + return true; + } + + if(CurrentRoomId == uint.MaxValue || GetRoom(CurrentRoomId) == null) + { + World.Instance.SendMessage("@wWe are in an unknown room.", i.ClientMask); + return true; + } + + List roomId = new List(); + Area aTarget = null; + string[] testIds = i.Arguments.Groups[1].Value.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); + foreach(string x in testIds) + { + uint u; + if(uint.TryParse(x, out u)) + { + if(GetRoom(u) == null) + { + World.Instance.SendMessage("@wNo such room (@R" + u + "@w)!", i.ClientMask); + continue; + } + if(!roomId.Contains(u)) + roomId.Add(u); + } + else + { + roomId = null; + break; + } + } + + if(roomId == null) + aTarget = GetArea(i.Arguments.Groups[1].Value); + + Pathfinder e; + if(roomId != null) + e = new Pathfinder_Entry(roomId.ToArray()); + else if(aTarget != null) + { + if(aTarget.StartRoom != 0) + e = new Pathfinder_Entry(aTarget.StartRoom); + else + e = new Pathfinder_Area(aTarget.Entry); + } + else + e = new Pathfinder_Name(NameTypes.Partial | NameTypes.CaseInsensitive, i.Arguments.Groups[1].Value); + + FillPathFinder(e); + PathfindResult pr = Get(e); + if(!pr.Success) + { + World.Instance.SendMessage("@wCouldn't find a path to any of the rooms entered.", i.ClientMask); + return true; + } + + if(aTarget != null) + World.Instance.SendMessage("@wGoing to area '@C" + pr.Target.Area.Name + "@w'...", i.ClientMask); + else + World.Instance.SendMessage("@wGoing to room '@G" + pr.Target.Name + "@w'...", i.ClientMask); + + Goto(pr); + return true; + } + + private bool CommandCount(InputData i) + { + int thisArea = 0; + int total = 0; + foreach(KeyValuePair x in IRooms) + { + if(x.Value.Area.Keyword == RoomInfoArea) + thisArea++; + if(x.Value.Area.Entry != uint.MaxValue) + total++; + } + World.Instance.SendMessage("@wYou have mapped @G" + thisArea + " @wrooms in this area.", i.ClientMask); + World.Instance.SendMessage("@wYou have @G" + (IAreas.Count - 1) + " @wareas in mapper.", i.ClientMask); + World.Instance.SendMessage("@wYou have mapped @G" + total + " @wrooms of Aardwolf.", i.ClientMask); + return true; + } + + #endregion + + #region Triggers + private bool TriggerNoRecon(TriggerData t) + { + Room r = GetRoom(CurrentRoomId); + if(r != null) + { + r.AddCustomFlag("reconed"); + r.AddCustomFlag("norecon"); + } + return false; + } + + private bool TriggerTagsExits(TriggerData t) + { + if(Config.GetInt32("Tags.Exits", 1) == 0) + return false; + + Room r = GetRoom(CurrentRoomId); + + StringBuilder str = new StringBuilder(); + string[] Exits = t.Match.Groups[2].Value.ToLower().Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); + CheckExit("north", 'n', Exits.Contains("north") || Exits.Contains("(north)"), Exits.Contains("(north)"), RoomInfoExits.ContainsKey('n') ? RoomInfoExits['n'] : 0, str); + CheckExit("east", 'e', Exits.Contains("east") || Exits.Contains("(east)"), Exits.Contains("(east)"), RoomInfoExits.ContainsKey('e') ? RoomInfoExits['e'] : 0, str); + CheckExit("south", 's', Exits.Contains("south") || Exits.Contains("(south)"), Exits.Contains("(south)"), RoomInfoExits.ContainsKey('s') ? RoomInfoExits['s'] : 0, str); + CheckExit("west", 'w', Exits.Contains("west") || Exits.Contains("(west)"), Exits.Contains("(west)"), RoomInfoExits.ContainsKey('w') ? RoomInfoExits['w'] : 0, str); + CheckExit("up", 'u', Exits.Contains("up") || Exits.Contains("(up)"), Exits.Contains("(up)"), RoomInfoExits.ContainsKey('u') ? RoomInfoExits['u'] : 0, str); + CheckExit("down", 'd', Exits.Contains("down") || Exits.Contains("(down)"), Exits.Contains("(down)"), RoomInfoExits.ContainsKey('d') ? RoomInfoExits['d'] : 0, str); + + if(r != null) + { + bool hadCustom = false; + foreach(Exit e in r.exits) + { + if(PathfindResult.IsDirectionCommand(e.Command) != 'x') + continue; + + hadCustom = true; + if(str.Length > 0) + str.Append(" "); + str.Append("@w'@C" + e.Command + "@w'"); + } + + if(!hadCustom && Exits.Contains("custom")) + { + if(str.Length > 0) + str.Append(" "); + str.Append("@Rcustom"); + } + } + + if(str.Length == 0) + str.Append("@Gnone"); + t.Msg.Msg = "@g[Exits: " + str.ToString() + "@g]"; + return false; + } + + private void CheckExit(string Word, char Dir, bool HasExits, bool IsClosed, uint LeadTo, StringBuilder str) + { + Room r = GetRoom(CurrentRoomId); + if(r == null) + { + if(!HasExits) + return; + + if(str.Length > 0) + str.Append(" "); + if(LeadTo == uint.MaxValue) + str.Append("@Y"); + else + str.Append("@G"); + str.Append(IsClosed ? ("(" + Word + ")") : Word); + return; + } + + if(LeadTo == uint.MaxValue) + { + if(str.Length > 0) + str.Append(" "); + str.Append("@Y"); + str.Append(IsClosed ? ("(" + Word + ")") : Word); + return; + } + + Exit e = r.GetExit(Dir); + if(e == null) + return; + + if(!HasExits) + { + if(e.HasFlag("hidden")) + { + if(str.Length > 0) + str.Append(" "); + str.Append("@y(" + Word + ")"); + return; + } + if(str.Length > 0) + str.Append(" "); + str.Append("@D(" + Word + ")"); + return; + } + + if(str.Length > 0) + str.Append(" "); + if(e.To.Area.Entry == uint.MaxValue) + str.Append("@R"); + else if(!e.To.HasCustomFlag("reconed") && Config.GetInt32("Tags.Exits.Recon", 0) != 0) + str.Append("@r"); + else + str.Append("@G"); + + if(IsClosed) + str.Append("(" + Word + ")"); + else + str.Append(Word); + } + + private bool TriggerNoRecall(TriggerData t) + { + Room r = GetRoom(CurrentRoomId); + if(r != null) + r.AddFlag("norecall"); + return false; + } + + private bool TriggerPrison(TriggerData t) + { + Room r = GetRoom(CurrentRoomId); + if(r != null) + r.AddFlag("prison"); + return false; + } + + private bool TriggerReconArea(TriggerData t) + { + Room r = GetRoom(CurrentRoomId); + if(r == null) + return false; + string msg = Colors.RemoveColors(t.Match.Groups[1].Value, false); + string name = msg.Substring(0, msg.LastIndexOf('(')).Trim(); + msg = msg.Substring(msg.LastIndexOf('(') + 1); + + r.Area.Name = name; + try + { + int min, max; + if(int.TryParse(msg.Substring(0, msg.IndexOf(' ')), out min)) + r.Area.MinLevel = min; + msg = msg.Substring(msg.IndexOf("to ") + 3); + if(int.TryParse(msg.Substring(0, msg.IndexOf(' ')), out max)) + r.Area.MaxLevel = max; + } + catch + { + } + r.AddCustomFlag("reconed"); + return false; + } + + private bool TriggerReconSector(TriggerData t) + { + Room r = GetRoom(CurrentRoomId); + if(r == null) + return false; + + r.Sector = Colors.RemoveColors(t.Match.Groups[1].Value, false); + return false; + } + + private bool TriggerReconHealRate(TriggerData t) + { + Room r = GetRoom(CurrentRoomId); + if(r == null) + return false; + + int rate; + if(int.TryParse(t.Match.Groups[1].Value, out rate)) + r.HealRate = rate; + return false; + } + + private bool TriggerReconManaRate(TriggerData t) + { + Room r = GetRoom(CurrentRoomId); + if(r == null) + return false; + + int rate; + if(int.TryParse(t.Match.Groups[1].Value, out rate)) + r.ManaRate = rate; + return false; + } + + private bool TriggerReconFlags(TriggerData t) + { + Room r = GetRoom(CurrentRoomId); + if(r == null) + return false; + + string[] fl = Colors.RemoveColors(t.Match.Groups[1].Value, false).Trim().ToLower().Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries); + if(r.IFlags != null) + r.IFlags.Clear(); + foreach(string x in fl) + r.AddFlag(x.Trim()); + return false; + } + + private bool TriggerAreasStart(TriggerData t) + { + ListenArea = true; + return false; + } + + private bool TriggerAreasEnd(TriggerData t) + { + ListenArea = false; + return false; + } + + private bool TriggerAreasEntry(TriggerData t) + { + if(!ListenArea) + return false; + + int minLevel, maxLevel, levelLock = 0; + + if(!int.TryParse(t.Match.Groups[1].Value, out minLevel) || + !int.TryParse(t.Match.Groups[2].Value, out maxLevel)) + return false; + + if(t.Match.Groups[3].Length != 0) + { + if(!int.TryParse(t.Match.Groups[3].Value, out levelLock)) + levelLock = 0; + } + + string keyWord = t.Match.Groups[4].Value; + string areaName = t.Match.Groups[5].Value.Trim(); + + Area a = GetArea(keyWord); + if(a == null) + { + a = new Area(++_guidArea); + IAreas[a.Entry] = a; + } + + a.Keyword = keyWord; + a.LevelLock = levelLock; + a.MaxLevel = maxLevel; + a.MinLevel = minLevel; + if(string.IsNullOrEmpty(a.Name) || a.Name.Length <= areaName.Length || !a.Name.StartsWith(areaName)) + a.Name = areaName; + return false; + } + + private bool TriggerWhereLevel(TriggerData t) + { + int minLevel, maxLevel; + if(!int.TryParse(t.Match.Groups[1].Value, out minLevel) || + !int.TryParse(t.Match.Groups[2].Value, out maxLevel)) + return false; + + Room cur = GetRoom(CurrentRoomId); + if(cur != null) + { + cur.Area.MinLevel = minLevel; + cur.Area.MaxLevel = maxLevel; + } + return false; + } + + private bool TriggerWhereName(TriggerData t) + { + string aName = Colors.RemoveColors(t.Match.Groups[1].Value, false).Trim(); + Room cur = GetRoom(CurrentRoomId); + if(cur != null) + cur.Area.Name = aName; + return false; + } + + private bool TriggerJoinedGQ(TriggerData t) + { + HasGQ = true; + return false; + } + + private bool TriggerLeftGQ(TriggerData t) + { + HasGQ = false; + return false; + } + + private bool TriggerCharStatusLevel(TriggerData t) + { + int i; + if(int.TryParse(t.Match.Groups[1].Value, out i)) + Level = i; + return false; + } + + private bool TriggerCharBaseTier(TriggerData t) + { + int i; + if(int.TryParse(t.Match.Groups[1].Value, out i)) + Tier = i; + return false; + } + + private bool TriggerCharBaseRemorts(TriggerData t) + { + int i; + if(int.TryParse(t.Match.Groups[1].Value, out i)) + Remorts = i; + return false; + } + + private bool TriggerRoomInfoNum(TriggerData t) + { + RoomInfoPrevious = RoomInfoEntry; + RoomInfoListen = true; + RoomInfoExits.Clear(); + uint i; + if(!uint.TryParse(t.Match.Groups[1].Value, out i)) + { + RoomInfoEntry = uint.MaxValue; + return false; + } + + RoomInfoEntry = i; + return false; + } + + private bool TriggerRoomInfoName(TriggerData t) + { + RoomInfoName = Colors.RemoveColors(t.Match.Groups[1].Value, true).Trim(); + return false; + } + + private bool TriggerRoomInfoArea(TriggerData t) + { + RoomInfoArea = t.Match.Groups[1].Value.Trim(); + return false; + } + + private bool TriggerRoomInfoExits(TriggerData t) + { + uint exitId; + RoomInfoExits[t.Match.Groups[1].Value.ToLower()[0]] = !uint.TryParse(t.Match.Groups[2].Value, out exitId) + ? uint.MaxValue + : exitId; + return false; + } + + private bool TriggerRoomInfoFinish(TriggerData t) + { + if(!RoomInfoListen) + return false; + + RoomInfoListen = false; + UpdateRoom(); + return false; + } + + #endregion + + #region Data + internal Dictionary IAreas = new Dictionary(); + internal Dictionary IRooms = new Dictionary(); + internal Dictionary IExits = new Dictionary(); + internal Dictionary IPortals = new Dictionary(); + + /// + /// Collection of all areas. + /// + public IEnumerable Areas + { + get + { + return IAreas.Values; + } + } + + /// + /// Collection of all rooms. + /// + public IEnumerable Rooms + { + get + { + return IRooms.Values; + } + } + + /// + /// Collection of all exits. + /// + public IEnumerable Exits + { + get + { + return IExits.Values; + } + } + + /// + /// Collection of all portals. + /// + public IEnumerable Portals + { + get + { + return IPortals.Values; + } + } + + private uint _guidArea = 0; + private uint _guidExit = 0; + + private void UpdateRoom() + { + CurrentRoomId = RoomInfoEntry; + + if(RoomInfoEntry == uint.MaxValue) + { + if(CurrentRoomId != RoomInfoPrevious) + { + Room prev = GetRoom(RoomInfoPrevious); + if(prev != null) + { + GetScript(prev).OnLeaveRoom(prev, null); + GetScript(prev).OnLeaveArea(prev.Area, null); + } + } + return; + } + + Room r = null; + Area a = null; + if(!IRooms.ContainsKey(CurrentRoomId)) + { + r = new Room(CurrentRoomId); + IRooms[r.Entry] = r; + } + else + r = IRooms[CurrentRoomId]; + + a = GetArea(RoomInfoArea); + if(a == null) + { + a = new Area(++_guidArea); + IAreas[a.Entry] = a; + a.Keyword = RoomInfoArea; + } + + if(r.Area != a) + r.Area = a; + + r.Name = RoomInfoName; + bool u = false; + foreach(KeyValuePair e in RoomInfoExits) + { + UpdateRoom(e.Value); + if(e.Value == uint.MaxValue) + continue; + Exit prev = r.GetExit(e.Key); + if(prev != null && prev.ToRoom == e.Value) + continue; + if(prev != null) + r.exits.Remove(prev); + Exit newExit = new Exit(++_guidExit); + newExit.To = GetRoom(e.Value); + newExit.Command = e.Key.ToString(); + newExit.From = r; + r.exits.Add(newExit); + IExits[newExit.Entry] = newExit; + u = true; + } + + if(u) + r.UpdateExits(); + + if(CurrentRoomId != RoomInfoPrevious) + { + Room prev = GetRoom(RoomInfoPrevious); + if(prev != null) + { + GetScript(prev).OnLeaveRoom(prev, r); + GetScript(prev).OnLeaveArea(prev.Area, r.Area); + } + GetScript(r).OnEnterArea(r.Area, prev != null ? prev.Area : null); + GetScript(r).OnEnterRoom(r, prev); + } + } + + private void UpdateRoom(uint Entry) + { + if(Entry == uint.MaxValue) + return; + + Room r = GetRoom(Entry); + if(r == null) + { + r = new Room(Entry); + IRooms[r.Entry] = r; + r.Area = GetArea(uint.MaxValue); + } + } + + internal uint CurrentRoomId; + private uint RoomInfoPrevious = uint.MaxValue; + private uint RoomInfoEntry = uint.MaxValue; + private string RoomInfoName; + private string RoomInfoArea; + private bool RoomInfoListen; + private Dictionary RoomInfoExits = new Dictionary(); + + /// + /// Get room by ID. + /// + /// ID of the room to get. + /// + public Room GetRoom(uint Entry) + { + return IRooms.ContainsKey(Entry) ? IRooms[Entry] : null; + } + + /// + /// Get exit by ID. + /// + /// ID of the exit to get. + /// + public Exit GetExit(uint Entry) + { + return IExits.ContainsKey(Entry) ? IExits[Entry] : null; + } + + /// + /// Get area by ID. + /// + /// ID of the area to get. + /// + public Area GetArea(uint Entry) + { + return IAreas.ContainsKey(Entry) ? IAreas[Entry] : null; + } + + /// + /// Get area by keyword. + /// + /// Keyword of area to get. + /// + public Area GetArea(string Keyword) + { + foreach(KeyValuePair x in IAreas) + { + if(x.Value.Keyword == Keyword) + return x.Value; + } + return null; + } + #endregion + + public override void Shutdown() + { + base.Shutdown(); + + Save(DBFileName); + } + + /// + /// Use mapper to go to the end of pathresult. + /// + /// + public void Goto(PathfindResult pr) + { + string sw = PathfindResult.Speedwalk(pr.Path); + if(string.IsNullOrEmpty(sw)) + sw = ""; + + if(Config.GetInt32("Speedwalk.Echo", 0) != 0) + { + World.Instance.SendMessage("@w{mapperpath}" + sw, Config.GetUInt64("Speedwalk.Echo.AuthMask", ulong.MaxValue)); + } + else if(!string.IsNullOrEmpty(sw)) + { + string[] swp = sw.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries); + foreach(string x in swp) + World.Instance.Execute(x, true); + } + else + World.Instance.SendMessage("@wTrying to execute an empty path. Using goto when you are already at target?"); + } + + #region Saving + private void Load() + { + StreamReader f; + try + { + f = new StreamReader(DBFileName); + } + catch + { + // No database exists or we aren't allowed to read it. Make a new database. + return; + } + + Area[] data; + try + { + DataContractSerializer x = new DataContractSerializer(typeof(Area[])); + data = x.ReadObject(f.BaseStream) as Area[]; + } + catch + { + f.Close(); + Log.Error("Failed loading mapper database! File corrupted?"); + return; + } + + f.Close(); + + if(data == null) + return; + + foreach(Area a in data) + { + if(a == null) + continue; + + IAreas[a.Entry] = a; + if(a.Entry > _guidArea && a.Entry != uint.MaxValue) + _guidArea = a.Entry; + foreach(Room r in a.rooms) + { + if(r == null) + continue; + r.Area = a; + IRooms[r.Entry] = r; + foreach(Exit e in r.exits) + { + if(e == null) + continue; + e.From = r; + IExits[e.Entry] = e; + if(e.Entry > _guidExit) + _guidExit = e.Entry; + } + r.UpdateExits(); + } + foreach(Exit p in a.Portals) + { + p.To = GetRoom(p.ToRoom); + IPortals[p.Entry] = p; + if(p.Entry > _guidExit) + _guidExit = p.Entry; + } + } + + foreach(KeyValuePair e in IExits) + { + if(IPortals.ContainsKey(e.Key)) + { + IPortals[e.Key].To.Area.Portals.Remove(IPortals[e.Key]); + IPortals.Remove(e.Key); + } + } + + List toDelete = new List(); + foreach(KeyValuePair e in IExits) + { + e.Value.To = IRooms.ContainsKey(e.Value.ToRoom) ? IRooms[e.Value.ToRoom] : null; + if(e.Value.To == null) + toDelete.Add(e.Value); + } + + foreach(Exit e in toDelete) + { + IExits.Remove(e.Entry); + e.From.exits.Remove(e); + } + + // Successfully loaded a database. Now make a backup because we have a working copy at the moment. + File.Delete(DBFileBackup); + File.Copy(DBFileName, DBFileBackup); + } + + private void Save(string fileName) + { + if(IAreas.Count == 0) + return; + StreamWriter f = new StreamWriter(fileName, false); + + try + { + DataContractSerializer x = new DataContractSerializer(typeof(Area[])); + x.WriteObject(f.BaseStream, IAreas.Values.ToArray()); + } + catch(Exception e) + { + f.Close(); + throw e; + } + + f.Close(); + if(Config.GetInt32("AutoSave", 0) != 0) + WhenSave = World.Instance.MSTime + Config.GetInt32("AutoSave", 0) * 1000; + } + #endregion + + public override void Update(long msTime) + { + base.Update(msTime); + + if(WhenSave == 0 && Config.GetInt32("AutoSave", 0) != 0) + WhenSave = Config.GetInt32("AutoSave", 0) * 1000 + msTime; + else if(WhenSave > 0 && WhenSave <= msTime) + Save(DBFileName); + } + } + + public class MapperConfig : ConfigFile + { + protected override void OnCreated() + { + base.OnCreated(); + + CreateSetting("Tags.Exits", 1, "Display extra information about exits using {exits} tag. You need to have \"tags exits on\"."); + CreateSetting("Tags.Exits.Recon", 0, "Display exits that lead to rooms that haven't been reconed yet in dark red."); + CreateSetting("Speedwalk.Echo", 0, "Echo speedwalk to clients instead of executing the command when using goto. This is useful if you like your MUD client to process it instead of mapper just sending to MUD, for example portal alias etc."); + CreateSetting("Speedwalk.Echo.AuthMask", ulong.MaxValue, "Security mask of who to echo the commands if you set Echo to 1."); + CreateSetting("AutoSave", 0, "Save mapper database every X seconds. For example enter 600 to save mapper database every 10 minutes. Enter 0 to disable this feature. The map is also saved on shutdown of program. You can also type \"map save\" to manually save the database."); + } + } +} diff --git a/Mapper/.svn/text-base/Mapper.csproj.svn-base b/Mapper/.svn/text-base/Mapper.csproj.svn-base new file mode 100644 index 0000000..fd66328 --- /dev/null +++ b/Mapper/.svn/text-base/Mapper.csproj.svn-base @@ -0,0 +1,77 @@ + + + + Debug + AnyCPU + 9.0.30729 + 2.0 + {9D34EF7A-07C1-43C5-9DAA-B1DE9F8EAA7D} + Library + Properties + Mapper + Mapper + v3.5 + 512 + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + False + ..\ProxyCore\bin\ProxyCore.dll + + + + 3.5 + + + 3.0 + + + 3.5 + + + 3.5 + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Mapper/.svn/text-base/Pathfind.cs.svn-base b/Mapper/.svn/text-base/Pathfind.cs.svn-base new file mode 100644 index 0000000..1a81593 --- /dev/null +++ b/Mapper/.svn/text-base/Pathfind.cs.svn-base @@ -0,0 +1,451 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Mapper.Scripting; + +namespace Mapper +{ + public partial class Mapper + { + private List[] _pGrid = new List[4096]; + private uint _pGridMax = 0; + private List[] _pExits = new[] { new List(), new List() }; + + private void Path_Init() + { + for(int i = 0; i < _pGrid.Length; i++) + _pGrid[i] = new List(512); + } + + private bool CanUsePortal(Exit p, Pathfinder x) + { + if(!p.HasFlag("recallmechanic")) + { + if(!x.CanUsePortals) + return false; + } + else + { + if(!x.CanUseRecalls) + return false; + } + + if(p.MinLevel > x.CharacterLevel + x.CharacterTier * 10 || + p.MaxLevel < x.CharacterLevel) + return false; + + if(p.HasFlag("nogq") && x.IsGlobalQuest) + return false; + + if(x.SkipPortals != null && x.SkipPortals.Contains(p)) + return false; + + return true; + } + + internal static AreaScript GetScript(Room r) + { + return AreaScriptMgr.GetScript(r.Area.Entry); + } + + public PathfindResult Get(Pathfinder p) + { + if(p.StartRooms != null) + p.StartRooms = p.StartRooms.Where(val => val != null).ToArray(); + if(p.StartRooms == null || p.StartRooms.Length == 0) + return new PathfindResult() { Success = false }; + + for(int i = 0; i < _pGridMax; i++) + _pGrid[i].Clear(); + _pExits[0].Clear(); + _pExits[1].Clear(); + _pGridMax = 0; + foreach(KeyValuePair x in IRooms) + { + x.Value.Mapper_OpenBy = null; + x.Value.Mapper_OpenCost = 0; + } + + p.OnStartedPathfind(); + + if(p.OverridePortals == null) + { + foreach(KeyValuePair x in IPortals) + { + if(!x.Value.HasFlag("disabled") && CanUsePortal(x.Value, p)) + _pExits[!x.Value.HasFlag("recallmechanic") ? 0 : 1].Add(x.Value); + } + } + else + { + foreach(Exit x in p.OverridePortals) + { + if(!x.HasFlag("disabled") && CanUsePortal(x, p)) + _pExits[!x.HasFlag("recallmechanic") ? 0 : 1].Add(x); + } + } + + Room Finish = null; + if(p.StartRooms != null) + { + foreach(Room r in p.StartRooms) + { + r.Mapper_OpenCost = uint.MaxValue; + if(OpenRoom(r, null, 0, p)) + { + Finish = r; + break; + } + } + } + + int itr1 = 0, itr2 = 0; + if(Finish == null) + { + while(itr1 < _pGrid.Length && itr1 < _pGridMax) + { + if(itr2 >= _pGrid[itr1].Count) + { + itr2 = 0; + itr1++; + continue; + } + + if(OpenRoom(_pGrid[itr1][itr2].To, _pGrid[itr1][itr2], (uint)itr1, p)) + { + Finish = _pGrid[itr1][itr2].To; + break; + } + + itr2++; + } + } + + PathfindResult pr = new PathfindResult(); + pr.Success = Finish != null; + pr.Cost = itr1; + pr.Target = Finish; + while(Finish != null && Finish.Mapper_OpenBy != null) + { + pr.Path.Insert(0, Finish.Mapper_OpenBy); + Finish = Finish.Mapper_OpenBy.From; + } + pr.Start = pr.Path.Count != 0 ? pr.Path[0].From : Finish; + + p.OnEndedPathFind(pr); + return pr; + } + + private bool OpenRoom(Room r, Exit from, uint cost, Pathfinder p) + { + if(r.Mapper_OpenBy != null || (from != null && p.StartRooms.Contains(r)) || r.Area.Entry == uint.MaxValue) + return false; + + r.Mapper_OpenBy = from; + r.Mapper_OpenCost = cost; + + if(p.IsTargetRoom(r)) + return true; + + if(_pExits[0].Count > 0 && !r.HasFlag("prison")) + { + for(int i = _pExits[0].Count - 1; i >= 0; i--) + { + if(_pExits[0][i].To.Mapper_OpenBy != null) + _pExits[0].RemoveAt(i); + else if(GetScript(r).CanUsePortal(_pExits[0][i], r) && p.CanUsePortal(_pExits[0][i], r)) + { + _pExits[0][i].From = r; + AddExit(_pExits[0][i], p, true); + _pExits[0].RemoveAt(i); + } + } + } + if(_pExits[1].Count > 0 && !r.HasFlag("norecall")) + { + for(int i = _pExits[1].Count - 1; i >= 0; i--) + { + if(_pExits[1][i].To.Mapper_OpenBy != null) + _pExits[1].RemoveAt(i); + else if(GetScript(r).CanUsePortal(_pExits[1][i], r) && p.CanUsePortal(_pExits[1][i], r)) + { + _pExits[1][i].From = r; + AddExit(_pExits[1][i], p, true); + _pExits[1].RemoveAt(i); + } + } + } + foreach(Exit e in r.exits) + { + if(e.To.Mapper_OpenBy != null) + continue; + if(e.To.Area.Entry == uint.MaxValue) + continue; + if(e.HasFlag("disabled")) + continue; + if(!GetScript(r).CanUseExit(e)) + continue; + if(e.MinLevel > p.CharacterLevel) + continue; + if(e.MaxLevel < p.CharacterLevel) + continue; + if(!p.CanUseExit(e)) + continue; + AddExit(e, p, false); + } + + return false; + } + + private void AddExit(Exit e, Pathfinder p, bool isPortal) + { + uint cost = e.From.Mapper_OpenCost + GetScript(e.From).GetLeaveRoomCost(e.From, e) + + (!isPortal ? GetScript(e.From).GetExitCost(e) : GetScript(e.From).GetPortalCost(e)) + GetScript(e.To).GetEnterRoomCost(e.To, e) + + p.GetLeaveRoomCost(e.From, e) + + (!isPortal ? p.GetExitCost(e) : p.GetPortalCost(e)) + p.GetEnterRoomCost(e.To, e); + + uint o = p.GetOverrideCost(e, isPortal); + if(o != uint.MaxValue) + cost = e.From.Mapper_OpenCost + o; + + if(cost >= _pGrid.Length) + return; + _pGrid[cost].Add(e); + cost++; + if(cost > _pGridMax) + _pGridMax = cost; + } + } + + public class PathfindResult + { + internal PathfindResult() + { + } + + public List Path = new List(); + public int Cost = 0; + public bool Success = false; + public Room Target; + public Room Start; + + /// + /// Generate a speedwalk from exit list. + /// + /// List of exits to generate a speedwalk from. + /// + public static string Speedwalk(IEnumerable Exits) + { + List sPath = new List(); + + foreach(Exit x in Exits) + { + string Door = Mapper.GetScript(x.From).GetDoorCommand(x); + string Command = Mapper.GetScript(x.From).GetExitCommand(x); + if(!string.IsNullOrEmpty(Door)) + sPath.AddRange(Door.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries)); + if(Command == null) + break; + sPath.AddRange(Command.Split(new[] {';'}, StringSplitOptions.RemoveEmptyEntries)); + } + + StringBuilder strSW = new StringBuilder(); + StringBuilder strCur = new StringBuilder(); + foreach(string x in sPath) + { + if(IsDirectionCommand(x) != 'x') + { + strCur.Append(char.ToLower(x[0])); + } + else + { + if(strCur.Length > 0) + { + if(strSW.Length > 0) + strSW.Append(';'); + if(strCur.Length > 1) + strSW.Append("run "); + strSW.Append(CompressPath(strCur.ToString())); + strCur.Remove(0, strCur.Length); + } + + if(strSW.Length > 0) + strSW.Append(';'); + + strSW.Append(x); + } + } + + if(strCur.Length > 0) + { + if(strSW.Length > 0) + strSW.Append(';'); + if(strCur.Length > 1) + strSW.Append("run "); + strSW.Append(CompressPath(strCur.ToString())); + strCur.Remove(0, strCur.Length); + } + + return strSW.ToString(); + } + + /// + /// Check if command is direction command. For example "west" -> 'w'. If it's not a direction + /// then return 'x'. + /// + /// Command to check. + /// + public static char IsDirectionCommand(string cmd) + { + cmd = cmd.ToLower().Trim(); + + if(cmd.Length == 0) + return 'x'; + + if(cmd.Length <= "north".Length && "north".StartsWith(cmd)) + return 'n'; + if(cmd.Length <= "west".Length && "west".StartsWith(cmd)) + return 'w'; + if(cmd.Length <= "south".Length && "south".StartsWith(cmd)) + return 's'; + if(cmd.Length <= "east".Length && "east".StartsWith(cmd)) + return 'e'; + if(cmd.Length <= "down".Length && "down".StartsWith(cmd)) + return 'd'; + if(cmd.Length <= "up".Length && "up".StartsWith(cmd)) + return 'u'; + return 'x'; + } + + /// + /// Compresses "wwssse" into "2w3se". + /// + /// Path to compress. + /// + public static string CompressPath(string path) + { + char dir = 'x'; + int c = 0; + StringBuilder str = new StringBuilder(); + for(int i = 0; i < path.Length; i++) + { + if(path[i] == dir) + { + c++; + continue; + } + + if(dir == 'x') + { + dir = path[i]; + c = 1; + continue; + } + + if(c > 1) + str.Append(c.ToString()); + str.Append(dir.ToString()); + dir = path[i]; + c = 1; + } + + if(dir != 'x') + { + if(c > 1) + str.Append(c.ToString()); + str.Append(dir.ToString()); + } + + return str.ToString(); + } + } + + public class Pathfinder + { + protected Pathfinder() + { + } + + /// + /// Set the character level for this path find. It is used in level lock areas and portals. + /// + public int CharacterLevel = 1; + public int CharacterTier = 0; + public bool IsGlobalQuest = false; + public bool CanUsePortals = true; + public bool CanUseRecalls = true; + public bool IsSingleClassTier0 = false; + public Room[] SkipRooms; + public Exit[] SkipExits; + public Exit[] SkipPortals; + public Room[] StartRooms; + public Exit[] OverridePortals; + + public virtual void CopyFrom(Pathfinder pf) + { + if(pf == null) + return; + + CharacterLevel = pf.CharacterLevel; + CharacterTier = pf.CharacterTier; + IsGlobalQuest = pf.IsGlobalQuest; + CanUsePortals = pf.CanUsePortals; + CanUseRecalls = pf.CanUseRecalls; + IsSingleClassTier0 = pf.IsSingleClassTier0; + SkipRooms = pf.SkipRooms; + SkipExits = pf.SkipExits; + SkipPortals = pf.SkipPortals; + StartRooms = pf.StartRooms; + OverridePortals = pf.OverridePortals; + } + + public virtual uint GetOverrideCost(Exit e, bool isPortal) + { + return uint.MaxValue; + } + + public virtual void OnStartedPathfind() + { + } + + public virtual bool IsTargetRoom(Room r) + { + return false; + } + + public virtual void OnEndedPathFind(PathfindResult pr) + { + } + + public virtual bool CanUseExit(Exit e) + { + return true; + } + + public virtual bool CanUsePortal(Exit p, Room r) + { + return true; + } + + public virtual uint GetLeaveRoomCost(Room r, Exit e) + { + return 0; + } + + public virtual uint GetExitCost(Exit e) + { + return 0; + } + + public virtual uint GetPortalCost(Exit e) + { + return 0; + } + + public virtual uint GetEnterRoomCost(Room r, Exit e) + { + return 0; + } + } +} diff --git a/Mapper/.svn/text-base/Room.cs.svn-base b/Mapper/.svn/text-base/Room.cs.svn-base new file mode 100644 index 0000000..fd98160 --- /dev/null +++ b/Mapper/.svn/text-base/Room.cs.svn-base @@ -0,0 +1,256 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Runtime.Serialization; + +namespace Mapper +{ + [DataContract] + public class Room + { + public Room(uint entry) + { + Entry = entry; + } + + [DataMember] + public readonly uint Entry; + + [DataMember] + public string Name + { + get; + internal set; + } + + [DataMember] + public string Sector + { + get; + internal set; + } + + [DataMember] + internal List IFlags = null; + + public IEnumerable Flags + { + get + { + return IFlags; + } + } + + /// + /// Check if room has a flag. These are actual flags that you get from recon and not custom flags. + /// + /// Flag to check for. + /// + public bool HasFlag(string flag) + { + return IFlags != null && IFlags.Contains(flag.ToLower().Trim()); + } + + /// + /// Add a flag to room. These are actual flags that you get from recon and not custom flags. + /// + /// Flag to add. + public void AddFlag(string flag) + { + flag = flag != null ? flag.ToLower().Trim() : ""; + if(IFlags == null) + IFlags = new List(); + if(!string.IsNullOrEmpty(flag) && !IFlags.Contains(flag)) + IFlags.Add(flag); + } + + /// + /// Remove a flag from room. These are actual flags that you get from recon and not custom flags. + /// + /// Flag to remove. + /// + public bool RemoveFlag(string flag) + { + flag = flag != null ? flag.ToLower().Trim() : ""; + if(IFlags != null && IFlags.Contains(flag)) + { + IFlags.Remove(flag); + return true; + } + return false; + } + + [DataMember] + internal List CFlags = null; + + public IEnumerable CustomFlags + { + get + { + return CFlags; + } + } + + [DataMember] + public uint EntryCost + { + get; + internal set; + } + + [DataMember] + public uint LeaveCost + { + get; + internal set; + } + + /// + /// Check if room has a flag. These are custom flags and not actual flags like norecall which you get from recon. + /// + /// Flag to check for. + /// + public bool HasCustomFlag(string flag) + { + return CFlags != null && CFlags.Contains(flag.ToLower().Trim()); + } + + /// + /// Add a flag to room. These are custom flags and not actual flags like norecall which you get from recon. + /// + /// Flag to add. + public void AddCustomFlag(string flag) + { + flag = flag != null ? flag.ToLower().Trim() : ""; + if(CFlags == null) + CFlags = new List(); + if(!string.IsNullOrEmpty(flag) && !CFlags.Contains(flag)) + CFlags.Add(flag); + } + + /// + /// Remove a flag from room. These are custom flags and not actual flags like norecall which you get from recon. + /// + /// Flag to remove. + /// + public bool RemoveCustomFlag(string flag) + { + flag = flag != null ? flag.ToLower().Trim() : ""; + if(CFlags != null && CFlags.Contains(flag)) + { + CFlags.Remove(flag); + return true; + } + return false; + } + + [DataMember] + public int HealRate + { + get; + internal set; + } + + [DataMember] + public int ManaRate + { + get; + internal set; + } + + [DataMember] + internal List exits = new List(); + + internal uint Mapper_OpenCost = 0; + internal Exit Mapper_OpenBy = null; + + public Exit[] Exits + { + get + { + return exits.ToArray(); + } + } + + private Area _area; + + public Area Area + { + get + { + return _area; + } + internal set + { + if(_area != null) + _area.rooms.Remove(this); + _area = value; + if(!_area.rooms.Contains(this)) + _area.rooms.Add(this); + } + } + + public Exit GetExit(char Direction) + { + foreach(Exit e in exits) + { + if(!string.IsNullOrEmpty(e.Command) && e.Command.Length == 1 && e.Command[0] == Direction) + return e; + } + + return null; + } + + public Exit GetExit(string Command) + { + foreach(Exit e in exits) + { + if(!string.IsNullOrEmpty(e.Command) && e.Command == Command) + return e; + } + + return null; + } + + public Exit GetExit(uint Entry) + { + foreach(Exit e in exits) + { + if(e.Entry == Entry) + return e; + } + + return null; + } + + internal void UpdateExits() + { + SortedDictionary> x = new SortedDictionary>(); + foreach(Exit e in exits) + { + string cmd; + if(string.IsNullOrEmpty(e.Command) || string.IsNullOrEmpty(cmd = e.Command.ToLower().Trim())) + continue; + + e.Command = cmd; + if(!x.ContainsKey(e.Command)) + x[e.Command] = new List(); + x[e.Command].Add(e); + } + + exits.Clear(); + + foreach(KeyValuePair> i in x) + { + foreach(Exit j in i.Value) + exits.Add(j); + } + } + + public override string ToString() + { + return "Room '" + (Name ?? "NULL") + "' [" + Entry + "]"; + } + } +} diff --git a/Mapper/.svn/text-base/desktop.ini b/Mapper/.svn/text-base/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/Mapper/.svn/text-base/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/Mapper/.svn/tmp/desktop.ini b/Mapper/.svn/tmp/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/Mapper/.svn/tmp/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/Mapper/.svn/tmp/prop-base/desktop.ini b/Mapper/.svn/tmp/prop-base/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/Mapper/.svn/tmp/prop-base/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/Mapper/.svn/tmp/props/desktop.ini b/Mapper/.svn/tmp/props/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/Mapper/.svn/tmp/props/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/Mapper/.svn/tmp/text-base/desktop.ini b/Mapper/.svn/tmp/text-base/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/Mapper/.svn/tmp/text-base/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/Mapper/Area.cs b/Mapper/Area.cs new file mode 100644 index 0000000..806ed53 --- /dev/null +++ b/Mapper/Area.cs @@ -0,0 +1,147 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.Serialization; +using System.Text; + +namespace Mapper +{ + [DataContract] + public class Area + { + public Area(uint entry) + { + Entry = entry; + } + + [DataMember] + public readonly uint Entry; + + [DataMember] + public string Name + { + get; + internal set; + } + + [DataMember] + public string Keyword + { + get; + internal set; + } + + [DataMember] + public int MinLevel + { + get; + internal set; + } + + [DataMember] + public int MaxLevel + { + get; + internal set; + } + + [DataMember] + public int LevelLock + { + get; + internal set; + } + + [DataMember] + public uint StartRoom + { + get; + internal set; + } + + [DataMember] + internal List rooms = new List(); + + [DataMember] + internal List Portals = new List(); + + public Room[] Rooms + { + get + { + return rooms.ToArray(); + } + } + + [DataMember] + public int ExplorableRooms + { + get; + internal set; + } + + /// + /// Get all rooms in area with this name (exact, case sensitive). + /// + /// Name of room. + /// + public List GetRooms(string Name) + { + List r = new List(); + foreach(Room x in rooms) + { + if(x.Name == Name) + r.Add(x); + } + + return r; + } + + [DataMember] + internal List Flags = null; + + /// + /// Check if area has a flag. + /// + /// Flag to check for. + /// + public bool HasFlag(string flag) + { + return Flags != null && Flags.Contains(flag.ToLower().Trim()); + } + + /// + /// Add a flag to area. + /// + /// Flag to add. + public void AddFlag(string flag) + { + flag = flag != null ? flag.ToLower().Trim() : ""; + if(Flags == null) + Flags = new List(); + if(!string.IsNullOrEmpty(flag) && !Flags.Contains(flag)) + Flags.Add(flag); + } + + /// + /// Remove a flag from area. + /// + /// Flag to remove. + /// + public bool RemoveFlag(string flag) + { + flag = flag != null ? flag.ToLower().Trim() : ""; + if(Flags != null && Flags.Contains(flag)) + { + Flags.Remove(flag); + return true; + } + return false; + } + + public override string ToString() + { + return "Area '" + (!string.IsNullOrEmpty(Name) ? Name : "NULL") + "' [" + Entry + "]"; + } + } +} diff --git a/Mapper/Edit.cs b/Mapper/Edit.cs new file mode 100644 index 0000000..9f71d08 --- /dev/null +++ b/Mapper/Edit.cs @@ -0,0 +1,497 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using ProxyCore; +using ProxyCore.Input; + +namespace Mapper +{ + public partial class Mapper + { + private bool CommandExit(InputData i) + { + // 1 2 3 4 + // @"^(help)?(room\s+\d+)?(\d+)?(\s+.+)?" + if(i.Arguments.Groups[1].Length != 0) + { + World.Instance.SendMessage("@wSyntax:", i.ClientMask); + World.Instance.SendMessage(string.Format("{0,-20}", "map exit") + " - show exits in current room.", i.ClientMask); + World.Instance.SendMessage(string.Format("{0,-20}", "map exit help") + " - show this message.", i.ClientMask); + World.Instance.SendMessage(string.Format("{0,-20}", "map exit room ") + " - show exits in room.", i.ClientMask); + World.Instance.SendMessage(string.Format("{0,-20}", "map exit [option] [value]") + " - change exit options / show information by exit ID.", i.ClientMask); + World.Instance.SendMessage("", i.ClientMask); + World.Instance.SendMessage("@wAvailable options for exit:", i.ClientMask); + World.Instance.SendMessage("@W" + string.Format("{0,-15}", "addflag") + " @w- Add a flag to exit.", i.ClientMask); + World.Instance.SendMessage("@W" + string.Format("{0,-15}", "removeflag") + " @w- Remove a flag from exit.", i.ClientMask); + World.Instance.SendMessage("@W" + string.Format("{0,-15}", "command") + " @w- Change command that activates exit.", i.ClientMask); + World.Instance.SendMessage("@W" + string.Format("{0,-15}", "doorcommand") + " @w- Change command that we use to open door, for example '@Wopen altar@w'. Use clear to remove this field.", i.ClientMask); + World.Instance.SendMessage("@W" + string.Format("{0,-15}", "cost") + " @w- Change cost of using exit.", i.ClientMask); + World.Instance.SendMessage("@W" + string.Format("{0,-15}", "minlevel") + " @w- Minimum level required to use exit.", i.ClientMask); + World.Instance.SendMessage("@W" + string.Format("{0,-15}", "maxlevel") + " @w- Maximum level allowed to use exit.", i.ClientMask); + World.Instance.SendMessage("@W" + string.Format("{0,-15}", "delete confirm") + " @w- Delete the exit.", i.ClientMask); + World.Instance.SendMessage("", i.ClientMask); + World.Instance.SendMessage("@wAvailable default flags:", i.ClientMask); + World.Instance.SendMessage("@W" + string.Format("{0,-15}", "recallmechanic") + " @w- This exit uses recall mechanic, can't use in norecall (for portals).", i.ClientMask); + World.Instance.SendMessage("@W" + string.Format("{0,-15}", "door") + " @w- This exit has a door.", i.ClientMask); + World.Instance.SendMessage("@W" + string.Format("{0,-15}", "nogq") + " @w- Don't use this exit on a global quest (for regular chaos portals).", i.ClientMask); + World.Instance.SendMessage("@W" + string.Format("{0,-15}", "disabled") + " @w- Don't use this exit ever.", i.ClientMask); + //World.Instance.SendMessage("@W" + string.Format("{0,-15}", "nopass") + " @w- The door is nopass.", i.ClientMask); + //World.Instance.SendMessage("@W" + string.Format("{0,-15}", "locked") + " @w- The door is locked.", i.ClientMask); + //World.Instance.SendMessage("@W" + string.Format("{0,-15}", "pickable") + " @w- Door can be pick locked or bashdoor.", i.ClientMask); + World.Instance.SendMessage("@wNote: there may be custom flags that are implemented by other plugins / scripts that aren't listed here.", i.ClientMask); + return true; + } + + if(i.Arguments.Groups[2].Length != 0 || (i.Arguments.Groups[2].Length == 0 && i.Arguments.Groups[1].Length == 0 && i.Arguments.Groups[3].Length == 0)) + { + uint roomId; + if(i.Arguments.Groups[2].Length != 0) + { + string str = i.Arguments.Groups[2].Value.Substring(4).Trim(); + if(!uint.TryParse(str, out roomId)) + { + World.Instance.SendMessage("@wInvalid room ID given. Type '@Wmap exit help@w' for syntax.", + i.ClientMask); + return true; + } + } + else + { + roomId = CurrentRoomId; + if(roomId == uint.MaxValue) + { + World.Instance.SendMessage("@wYou are in an unknown room.", i.ClientMask); + return true; + } + } + + Room r = GetRoom(roomId); + if(r == null) + { + World.Instance.SendMessage("@wNo such room in database (@R" + roomId + "@w).", i.ClientMask); + return true; + } + + World.Instance.SendMessage("@wExits in '@G" + r.Name + "@w' [@Y" + r.Entry + "@w]:", i.ClientMask); + if(r.exits.Count == 0) + World.Instance.SendMessage("@wNo exits found.", i.ClientMask); + else + { + World.Instance.SendMessage("@WEntry Command To", i.ClientMask); + World.Instance.SendMessage("@G====== ==================== ========================", i.ClientMask); + foreach(Exit e in r.exits) + World.Instance.SendMessage("@Y" + string.Format("{0,-6}", e.Entry) + " @W" + string.Format("{0,-20}", e.Command) + " @w[@Y" + string.Format("{0,6}", e.To.Entry) + "@w] @G" + e.To.Name, i.ClientMask); + World.Instance.SendMessage("", i.ClientMask); + World.Instance.SendMessage("@wType '@Wmap exit @w' for more information about an exit.", i.ClientMask); + World.Instance.SendMessage("@wOr '@Wmap exit help@w' for syntax.", i.ClientMask); + } + return true; + } + + if(i.Arguments.Groups[3].Length != 0) + { + uint exitId; + if(!uint.TryParse(i.Arguments.Groups[3].Value, out exitId)) + { + World.Instance.SendMessage("@wInvalid exit ID given. Type '@Wmap exit help@w' for syntax.", i.ClientMask); + return true; + } + + Exit e = GetExit(exitId); + if(e == null && IPortals.ContainsKey(exitId)) + e = IPortals[exitId]; + if(e == null) + { + World.Instance.SendMessage("@wNo such exit in database (@R" + exitId + "@w).", i.ClientMask); + return true; + } + + if(i.Arguments.Groups[4].Length != 0) + { + string key, val; + string str = i.Arguments.Groups[4].Value.Trim(); + if(str.Contains(' ')) + { + key = str.Substring(0, str.IndexOf(' ')).ToLower(); + val = str.Substring(key.Length).Trim(); + + switch(key) + { + case "addflag": + e.AddFlag(val); + break; + + case "removeflag": + e.RemoveFlag(val); + break; + + case "command": + val = val.ToLower(); + e.Command = PathfindResult.IsDirectionCommand(val) != 'x' ? + PathfindResult.IsDirectionCommand(val).ToString() : + val; + break; + + case "doorcommand": + val = val.ToLower(); + e.DoorCommand = val != "clear" ? val : null; + break; + + case "cost": + { + uint u; + if(uint.TryParse(val, out u)) + e.Cost = u; + } break; + + case "minlevel": + { + int lvl; + if(int.TryParse(val, out lvl)) + e.MinLevel = lvl; + } break; + + case "maxlevel": + { + int lvl; + if(int.TryParse(val, out lvl)) + e.MaxLevel = lvl; + } break; + + case "delete": + { + if(val == "confirm") + { + if(e.HasFlag("portal")) + { + IPortals.Remove(e.Entry); + e.To.Area.Portals.Remove(e); + } + else + { + IExits.Remove(e.Entry); + e.From.exits.Remove(e); + } + World.Instance.SendMessage("@wDeleted exit or portal (@R" + e.Entry + "@w).", + i.ClientMask); + return true; + } + World.Instance.SendMessage("@wEnter '@Wmap exit delete confirm@w' to remove the exit.", i.ClientMask); + } break; + + default: + World.Instance.SendMessage("@wInvalid key value pair entered '@R" + key + " " + val + "@w'.", i.ClientMask); + World.Instance.SendMessage("@wUse '@Wmap exit help@w' to see syntax.", i.ClientMask); + break; + } + } + } + + World.Instance.SendMessage("@w+----------------------------------------------------------------------+", i.ClientMask); + World.Instance.SendMessage("@w| @WEntry @w: @Y" + string.Format("{0,-55}", e.Entry) + "@w|", i.ClientMask); + if(!e.HasFlag("portal")) + World.Instance.SendMessage("@w| @WFrom @w: @w[@Y" + string.Format("{0,6}", e.From.Entry) + "@w] @G" + Utility.FormatColoredString(!string.IsNullOrEmpty(e.From.Name) ? e.From.Name : "Unknown", -46) + "@w|", i.ClientMask); + World.Instance.SendMessage("@w| @WTo @w: @w[@Y" + string.Format("{0,6}", e.To.Entry) + "@w] @G" + Utility.FormatColoredString(!string.IsNullOrEmpty(e.To.Name) ? e.To.Name : "Unknown", -46) + "@w|", i.ClientMask); + World.Instance.SendMessage("@w| @WCommand @w: @c" + string.Format("{0,-55}", e.Command) + "@w|", i.ClientMask); + World.Instance.SendMessage("@w| @WDoor command@w: @c" + string.Format("{0,-55}", !string.IsNullOrEmpty(e.DoorCommand) ? e.DoorCommand : "none") + "@w|", i.ClientMask); + World.Instance.SendMessage("@w| @WCost @w: @C" + string.Format("{0,-55}", e.Cost) + "@w|", i.ClientMask); + StringBuilder strFlags = new StringBuilder(); + if(e.IFlags != null) + { + foreach(string x in e.IFlags) + { + if(strFlags.Length > 0) + strFlags.Append(", "); + strFlags.Append(x); + } + } + + string[] spl = Utility.WrapColored(strFlags.ToString(), 54, 0); + for(int j = 0; j < spl.Length; j++) + { + if(j == 0) + World.Instance.SendMessage("@w| @WFlags @w: " + string.Format("{0,-55}", spl[j]) + "@w|", i.ClientMask); + else + World.Instance.SendMessage("@w| : " + string.Format("{0,-55}", spl[j]) + "@w|", i.ClientMask); + } + + World.Instance.SendMessage("@w| @WMin level @w: @W" + string.Format("{0,-55}", e.MinLevel) + "@w|", i.ClientMask); + World.Instance.SendMessage("@w| @WMax level @w: @W" + string.Format("{0,-55}", e.MaxLevel) + "@w|", i.ClientMask); + World.Instance.SendMessage("@w+----------------------------------------------------------------------+", i.ClientMask); + if(i.Arguments.Groups[4].Length == 0) + World.Instance.SendMessage("@wSee '@Wmap exit help@w' for information on how to edit this exit.", i.ClientMask); + return true; + } + + World.Instance.SendMessage("0", i.ClientMask); + return true; + } + + private bool CommandPortal(InputData i) + { + if(IPortals.Count == 0) + { + World.Instance.SendMessage("@wYou have no portals set.", i.ClientMask); + return true; + } + + int count = 0; + World.Instance.SendMessage("@WEntry Command To", i.ClientMask); + World.Instance.SendMessage("@G======== ================ =====================================", i.ClientMask); + foreach(KeyValuePair x in IPortals) + { + World.Instance.SendMessage("@w[@Y" + string.Format("{0,6}", x.Key) + "@w] @w" + string.Format("{0,-16}", x.Value.Command) + " @M" + x.Value.To.Area.Name + " @wroom [@Y" + x.Value.To.Entry + "@w]", i.ClientMask); + count++; + } + + World.Instance.SendMessage("@C" + count + " @wportals found.", i.ClientMask); + return true; + } + + private bool CommandCreateExit(InputData i) + { + if(!i.Arguments.Success) + { + World.Instance.SendMessage("@wSyntax: map createexit [from room ID = current] \"\"", i.ClientMask); + return true; + } + + uint fromId; + uint toId; + if(i.Arguments.Groups[2].Length > 0) + { + if(!uint.TryParse(i.Arguments.Groups[1].Value, out fromId) || + !uint.TryParse(i.Arguments.Groups[2].Value.Trim(), out toId)) + { + World.Instance.SendMessage("@wSyntax: map createexit [from room ID = current] \"\"", i.ClientMask); + return true; + } + } + else + { + fromId = CurrentRoomId; + if(!uint.TryParse(i.Arguments.Groups[1].Value, out toId)) + { + World.Instance.SendMessage("@wSyntax: map createexit [from room ID = current] \"\"", i.ClientMask); + return true; + } + } + + Room from = GetRoom(fromId); + Room to = GetRoom(toId); + if(from == null || to == null) + { + World.Instance.SendMessage("@wNo such room exists in mapper database.", i.ClientMask); + return true; + } + + char dir = PathfindResult.IsDirectionCommand(i.Arguments.Groups[3].Value); + Exit e = new Exit(++_guidExit); + e.Command = dir != 'x' ? char.ToLower(dir).ToString() : i.Arguments.Groups[3].Value.ToLower(); + e.From = from; + e.To = to; + e.From.exits.Add(e); + e.From.UpdateExits(); + IExits[e.Entry] = e; + World.Instance.SendMessage("@wCreated a new exit (@R" + e.Entry + "@w).", i.ClientMask); + World.Instance.SendMessage("@wType '@Wmap exit " + e.Entry + "@w' for more information or to edit.", i.ClientMask); + return true; + } + + private bool CommandCreatePortal(InputData i) + { + if(!i.Arguments.Success) + { + World.Instance.SendMessage("@wSyntax: map createportal \"\"", i.ClientMask); + return true; + } + + uint toId; + if(!uint.TryParse(i.Arguments.Groups[1].Value, out toId)) + { + World.Instance.SendMessage("@wSyntax: map createportal \"\"", i.ClientMask); + return true; + } + + Room to = GetRoom(toId); + if(to == null) + { + World.Instance.SendMessage("@wNo such room exists in mapper database.", i.ClientMask); + return true; + } + + Exit e = new Exit(++_guidExit); + e.Command = i.Arguments.Groups[2].Value.ToLower(); + e.To = to; + e.Cost = 5; + if(e.IFlags == null) + e.IFlags = new List(); + e.IFlags.Add("portal"); + IPortals[e.Entry] = e; + to.Area.Portals.Add(e); + World.Instance.SendMessage("@wCreated a new portal (@R" + e.Entry + "@w).", i.ClientMask); + World.Instance.SendMessage("@wType '@Wmap exit " + e.Entry + "@w' for more information or to edit.", i.ClientMask); + return true; + } + + private bool CommandRoomInfo(InputData i) + { + // 1 2 3 + // @"(help)?(\d+)?(\s+.+)?" + if(i.Arguments.Success && i.Arguments.Groups[1].Length != 0) + { + World.Instance.SendMessage("@wSyntax:", i.ClientMask); + World.Instance.SendMessage(string.Format("{0,-20}", "map room") + " - show info about current room.", i.ClientMask); + World.Instance.SendMessage(string.Format("{0,-20}", "map room help") + " - show this message.", i.ClientMask); + World.Instance.SendMessage(string.Format("{0,-20}", "map room [option] [value]") + " - show info about room by ID or change it.", i.ClientMask); + World.Instance.SendMessage("", i.ClientMask); + World.Instance.SendMessage("@wAvailable options for room:", i.ClientMask); + World.Instance.SendMessage("@W" + string.Format("{0,-15}", "addflag") + " @w- Add a flag to room.", i.ClientMask); + World.Instance.SendMessage("@W" + string.Format("{0,-15}", "removeflag") + " @w- Remove a flag from room.", i.ClientMask); + World.Instance.SendMessage("@W" + string.Format("{0,-15}", "addcflag") + " @w- Add a custom flag to room.", i.ClientMask); + World.Instance.SendMessage("@W" + string.Format("{0,-15}", "removecflag") + " @w- Remove a custom flag from room.", i.ClientMask); + World.Instance.SendMessage("@W" + string.Format("{0,-15}", "name") + " @w- Change name of room.", i.ClientMask); + World.Instance.SendMessage("@W" + string.Format("{0,-15}", "entrycost") + " @w- Change cost of entering room.", i.ClientMask); + World.Instance.SendMessage("@W" + string.Format("{0,-15}", "leavecost") + " @w- Change cost of leaving room.", i.ClientMask); + //World.Instance.SendMessage("@W" + string.Format("{0,-15}", "healrate") + " @w- Change heal rate.", i.ClientMask); + //World.Instance.SendMessage("@W" + string.Format("{0,-15}", "manarate") + " @w- Change mana rate.", i.ClientMask); + //World.Instance.SendMessage("@W" + string.Format("{0,-15}", "sector") + " @w- Change sector.", i.ClientMask); + return true; + } + + uint roomId; + if(i.Arguments.Success && i.Arguments.Groups[2].Length != 0) + { + if(!uint.TryParse(i.Arguments.Groups[2].Value, out roomId)) + { + World.Instance.SendMessage("@wInvalid room ID given (@R" + i.Arguments.Groups[2].Value + "@w).", i.ClientMask); + World.Instance.SendMessage("@wUse '@Wmap roominfo help@w' to see syntax.", i.ClientMask); + return true; + } + } + else + { + roomId = CurrentRoomId; + if(roomId == uint.MaxValue) + { + World.Instance.SendMessage("@wYou are in an invalid room.", i.ClientMask); + World.Instance.SendMessage("@wUse '@Wmap roominfo help@w' to see syntax.", i.ClientMask); + return true; + } + } + + Room r = GetRoom(roomId); + if(r == null) + { + World.Instance.SendMessage("@wNo such room in database (@R" + roomId + "@w).", i.ClientMask); + return true; + } + + if(i.Arguments.Success && i.Arguments.Groups[2].Length != 0 && i.Arguments.Groups[3].Length != 0) + { + string key, val; + string str = i.Arguments.Groups[3].Value.Trim(); + if(str.Contains(' ')) + { + key = str.Substring(0, str.IndexOf(' ')).ToLower(); + val = str.Substring(key.Length).Trim(); + + switch(key) + { + case "addflag": + r.AddFlag(val); + break; + + case "removeflag": + r.RemoveFlag(val); + break; + + case "addcflag": + r.AddCustomFlag(val); + break; + + case "removecflag": + r.RemoveCustomFlag(val); + break; + + case "name": + r.Name = val; + break; + + case "entrycost": + { + uint u; + if(uint.TryParse(val, out u)) + r.EntryCost = u; + } break; + + case "leavecost": + { + uint u; + if(uint.TryParse(val, out u)) + r.LeaveCost = u; + } break; + } + } + } + + World.Instance.SendMessage("@w+----------------------------------------------------------------------+", i.ClientMask); + World.Instance.SendMessage("@w| @WEntry @w: @Y" + string.Format("{0,-55}", r.Entry) + "@w|", i.ClientMask); + World.Instance.SendMessage("@w| @WName @w: @G" + Utility.FormatColoredString(!string.IsNullOrEmpty(r.Name) ? r.Name : "Unknown", -55) + "@w|", i.ClientMask); + World.Instance.SendMessage("@w| @WArea @w: @M" + string.Format("{0,-55}", !string.IsNullOrEmpty(r.Area.Name) ? r.Area.Name : "Unknown") + "@w|", i.ClientMask); + { + StringBuilder strFlags = new StringBuilder(); + if(r.IFlags != null) + { + foreach(string x in r.IFlags) + { + if(strFlags.Length > 0) + strFlags.Append(", "); + strFlags.Append(x); + } + } + + string[] spl = Utility.WrapColored(strFlags.ToString(), 54, 0); + for(int j = 0; j < spl.Length; j++) + { + if(j == 0) + World.Instance.SendMessage("@w| @WFlags @w: " + string.Format("{0,-55}", spl[j]) + "@w|", + i.ClientMask); + else + World.Instance.SendMessage("@w| : " + string.Format("{0,-55}", spl[j]) + "@w|", + i.ClientMask); + } + } + + { + StringBuilder strFlags = new StringBuilder(); + if(r.CFlags != null) + { + foreach(string x in r.CFlags) + { + if(strFlags.Length > 0) + strFlags.Append(", "); + strFlags.Append(x); + } + } + + string[] spl = Utility.WrapColored(strFlags.ToString(), 54, 0); + for(int j = 0; j < spl.Length; j++) + { + if(j == 0) + World.Instance.SendMessage("@w| @WCustom flags@w: " + string.Format("{0,-55}", spl[j]) + "@w|", i.ClientMask); + else + World.Instance.SendMessage("@w| : " + string.Format("{0,-55}", spl[j]) + "@w|", i.ClientMask); + } + } + + // Healrate, manarate, sector + + World.Instance.SendMessage("@w+----------------------------------------------------------------------+", i.ClientMask); + if(!i.Arguments.Success || (i.Arguments.Groups[1].Length == 0 && i.Arguments.Groups[2].Length == 0 && i.Arguments.Groups[3].Length == 0)) + World.Instance.SendMessage("@wUse '@Wmap roominfo help@w' to see syntax.", i.ClientMask); + return true; + } + } +} diff --git a/Mapper/Exit.cs b/Mapper/Exit.cs new file mode 100644 index 0000000..e36b754 --- /dev/null +++ b/Mapper/Exit.cs @@ -0,0 +1,136 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.Serialization; +using System.Text; + +namespace Mapper +{ + [DataContract] + public class Exit + { + public Exit(uint entry) + { + Entry = entry; + MinLevel = 0; + MaxLevel = 210; + Cost = 1; + } + + [DataMember] + public readonly uint Entry; + + [DataMember] + public int MinLevel + { + get; + internal set; + } + + [DataMember] + public int MaxLevel + { + get; + internal set; + } + + public Room From + { + get; + internal set; + } + + public Room To + { + get + { + return _to; + } + internal set + { + _to = value; + ToRoom = value != null ? value.Entry : uint.MaxValue; + } + } + + private Room _to; + + [DataMember] + internal uint ToRoom; + + [DataMember] + public string Command + { + get; + internal set; + } + + [DataMember] + public string DoorCommand + { + get; + internal set; + } + + [DataMember] + internal List IFlags = null; + + public IEnumerable Flags + { + get + { + return IFlags; + } + } + + [DataMember] + public uint Cost + { + get; + internal set; + } + + /// + /// Check if exit has a flag. + /// + /// Flag to check for. + /// + public bool HasFlag(string flag) + { + return IFlags != null && IFlags.Contains(flag.ToLower().Trim()); + } + + /// + /// Add a flag to exit. + /// + /// Flag to add. + public void AddFlag(string flag) + { + flag = flag != null ? flag.ToLower().Trim() : ""; + if(flag == "portal") + return; + if(IFlags == null) + IFlags = new List(); + if(!string.IsNullOrEmpty(flag) && !IFlags.Contains(flag)) + IFlags.Add(flag); + } + + /// + /// Remove a flag from exit. + /// + /// Flag to remove. + /// + public bool RemoveFlag(string flag) + { + flag = flag != null ? flag.ToLower().Trim() : ""; + if(flag == "portal") + return false; + if(IFlags != null && IFlags.Contains(flag)) + { + IFlags.Remove(flag); + return true; + } + return false; + } + } +} diff --git a/Mapper/Finders/.svn/all-wcprops b/Mapper/Finders/.svn/all-wcprops new file mode 100644 index 0000000..4208dea --- /dev/null +++ b/Mapper/Finders/.svn/all-wcprops @@ -0,0 +1,35 @@ +K 25 +svn:wc:ra_dav:version-url +V 37 +/svn/!svn/ver/44/trunk/Mapper/Finders +END +Name.cs +K 25 +svn:wc:ra_dav:version-url +V 44 +/svn/!svn/ver/2/trunk/Mapper/Finders/Name.cs +END +Entry.cs +K 25 +svn:wc:ra_dav:version-url +V 45 +/svn/!svn/ver/2/trunk/Mapper/Finders/Entry.cs +END +VisitAll.cs +K 25 +svn:wc:ra_dav:version-url +V 49 +/svn/!svn/ver/44/trunk/Mapper/Finders/VisitAll.cs +END +Area.cs +K 25 +svn:wc:ra_dav:version-url +V 44 +/svn/!svn/ver/2/trunk/Mapper/Finders/Area.cs +END +Unmapped.cs +K 25 +svn:wc:ra_dav:version-url +V 48 +/svn/!svn/ver/2/trunk/Mapper/Finders/Unmapped.cs +END diff --git a/Mapper/Finders/.svn/desktop.ini b/Mapper/Finders/.svn/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/Mapper/Finders/.svn/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/Mapper/Finders/.svn/dir-prop-base b/Mapper/Finders/.svn/dir-prop-base new file mode 100644 index 0000000..f1b96ea --- /dev/null +++ b/Mapper/Finders/.svn/dir-prop-base @@ -0,0 +1,5 @@ +K 14 +bugtraq:number +V 4 +true +END diff --git a/Mapper/Finders/.svn/entries b/Mapper/Finders/.svn/entries new file mode 100644 index 0000000..fdb2c4c --- /dev/null +++ b/Mapper/Finders/.svn/entries @@ -0,0 +1,198 @@ +10 + +dir +58 +http://proxymud.googlecode.com/svn/trunk/Mapper/Finders +http://proxymud.googlecode.com/svn + + + +2012-01-29T09:57:36.978045Z +44 +default8p@gmail.com +has-props + + + + + + + + + + + + + +8a6e9f07-fe1d-2472-fcf8-0b435762827a + +Unmapped.cs +file + + + + +2016-03-25T22:18:43.048137Z +3184f09287a1efa19af1f9e79499a15a +2012-01-17T10:55:35.805502Z +2 +default8p@gmail.com + + + + + + + + + + + + + + + + + + + + + +1343 + +Name.cs +file + + + + +2016-03-25T22:18:43.048137Z +b0b7b02f4e344ad61cd3ae2b0433ff8e +2012-01-17T10:55:35.805502Z +2 +default8p@gmail.com + + + + + + + + + + + + + + + + + + + + + +3188 + +Entry.cs +file + + + + +2016-03-25T22:18:43.048137Z +3c5604f9f58dcd4dc52b100067cec01c +2012-01-17T10:55:35.805502Z +2 +default8p@gmail.com + + + + + + + + + + + + + + + + + + + + + +516 + +VisitAll.cs +file + + + + +2016-03-25T22:18:43.048137Z +212272af6341079b4576c8afb1128661 +2012-01-29T09:57:36.978045Z +44 +default8p@gmail.com + + + + + + + + + + + + + + + + + + + + + +6028 + +Area.cs +file + + + + +2016-03-25T22:18:43.048137Z +6a503a15d8656341f4e3525b25973d51 +2012-01-17T10:55:35.805502Z +2 +default8p@gmail.com + + + + + + + + + + + + + + + + + + + + + +477 + diff --git a/Mapper/Finders/.svn/prop-base/desktop.ini b/Mapper/Finders/.svn/prop-base/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/Mapper/Finders/.svn/prop-base/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/Mapper/Finders/.svn/props/desktop.ini b/Mapper/Finders/.svn/props/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/Mapper/Finders/.svn/props/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/Mapper/Finders/.svn/text-base/Area.cs.svn-base b/Mapper/Finders/.svn/text-base/Area.cs.svn-base new file mode 100644 index 0000000..4570a20 --- /dev/null +++ b/Mapper/Finders/.svn/text-base/Area.cs.svn-base @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Mapper +{ + public class Pathfinder_Area : Pathfinder + { + public Pathfinder_Area(params uint[] AreaID) + : base() + { + AreaId = AreaID; + } + + private readonly uint[] AreaId; + + public override bool IsTargetRoom(Room r) + { + return AreaId.Contains(r.Area.Entry); + } + } +} diff --git a/Mapper/Finders/.svn/text-base/Entry.cs.svn-base b/Mapper/Finders/.svn/text-base/Entry.cs.svn-base new file mode 100644 index 0000000..cb5e0ee --- /dev/null +++ b/Mapper/Finders/.svn/text-base/Entry.cs.svn-base @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Mapper +{ + public class Pathfinder_Entry : Pathfinder + { + public Pathfinder_Entry(params uint[] roomEntries) + : base() + { + TargetRoomEntries = roomEntries; + } + + public readonly uint[] TargetRoomEntries; + + public override bool IsTargetRoom(Room r) + { + return TargetRoomEntries.Contains(r.Entry); + } + } +} diff --git a/Mapper/Finders/.svn/text-base/Name.cs.svn-base b/Mapper/Finders/.svn/text-base/Name.cs.svn-base new file mode 100644 index 0000000..c0d80f3 --- /dev/null +++ b/Mapper/Finders/.svn/text-base/Name.cs.svn-base @@ -0,0 +1,105 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; + +namespace Mapper +{ + public class Pathfinder_Name : Pathfinder + { + public Pathfinder_Name(NameTypes t, params string[] Names) + : base() + { + nt = t; + _names = Names; + if((t & NameTypes.Regex) != NameTypes.None) + { + _regexString = new Regex[Names.Length]; + for(int i = 0; i < Names.Length; i++) + { + if(string.IsNullOrEmpty(Names[i])) + continue; + + try + { + _regexString[i] = new Regex(Names[i], (t & NameTypes.CaseInsensitive) != NameTypes.None ? RegexOptions.IgnoreCase : RegexOptions.None); + } + catch + { + // User entered invalid regex pattern + } + } + } + else if((t & NameTypes.CaseInsensitive) != NameTypes.None) + { + for(int i = 0; i < _names.Length; i++) + _names[i] = _names[i].ToLower(); + } + } + + private readonly Regex[] _regexString; + private readonly string[] _names; + private readonly NameTypes nt; + + public override bool IsTargetRoom(Room r) + { + if(string.IsNullOrEmpty(r.Name)) + return false; + + if((nt & NameTypes.Regex) != NameTypes.None) + { + foreach(Regex x in _regexString) + { + if(x == null) + continue; + + if(x.Match(r.Name).Success) + return true; + } + } + else + { + string rname = r.Name; + if((nt & NameTypes.CaseInsensitive) != NameTypes.None) + rname = rname.ToLower(); + foreach(string x in _names) + { + if((nt & NameTypes.Partial) != NameTypes.None) + { + if(rname.Contains(x)) + return true; + } + else if(rname == x) + return true; + } + } + + return false; + } + } + + [Flags] + public enum NameTypes + { + /// + /// Exact name search. Room name must match what you entered and case sensitive. + /// + None = 0, + + /// + /// Room name must contain the string you entered. This setting is ignored if you set regex option. + /// + Partial = 1, + + /// + /// Room name vs. what you entered is not case sensitive. + /// + CaseInsensitive = 2, + + /// + /// You entered a regex string which must match room name. + /// + Regex = 4, + } +} diff --git a/Mapper/Finders/.svn/text-base/Unmapped.cs.svn-base b/Mapper/Finders/.svn/text-base/Unmapped.cs.svn-base new file mode 100644 index 0000000..26b5ce7 --- /dev/null +++ b/Mapper/Finders/.svn/text-base/Unmapped.cs.svn-base @@ -0,0 +1,55 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Mapper +{ + public class Pathfinder_Unmapped : Pathfinder + { + public Pathfinder_Unmapped(bool unReconed) + : base() + { + UnReconed = unReconed; + } + + private bool UnReconed; + private uint[] AllowedAreas; + + public override void OnStartedPathfind() + { + base.OnStartedPathfind(); + + List a = new List(); + foreach(Room r in StartRooms) + { + if(r.Area.Entry == uint.MaxValue) + continue; + if(!a.Contains(r.Area.Entry)) + a.Add(r.Area.Entry); + } + + AllowedAreas = a.ToArray(); + } + + public override bool IsTargetRoom(Room r) + { + if(!AllowedAreas.Contains(r.Area.Entry)) + return false; + + foreach(Exit e in r.exits) + { + if(e.To.Area.Entry == uint.MaxValue) + return true; + } + + if(UnReconed) + { + if(!r.HasCustomFlag("reconed")) + return true; + } + + return base.IsTargetRoom(r); + } + } +} diff --git a/Mapper/Finders/.svn/text-base/VisitAll.cs.svn-base b/Mapper/Finders/.svn/text-base/VisitAll.cs.svn-base new file mode 100644 index 0000000..b251444 --- /dev/null +++ b/Mapper/Finders/.svn/text-base/VisitAll.cs.svn-base @@ -0,0 +1,189 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Mapper +{ + public class PathFinder_VisitAll : Pathfinder + { + public PathFinder_VisitAll(Mapper mapper, params Room[] roomId) + : base() + { + map = mapper; + foreach(Room u in roomId) + { + if(!AllRooms.Contains(u)) + AllRooms.Add(u); + } + + if(_grid[0] == null) + { + for(int i = 0; i < _grid.Length; i++) + _grid[i] = new List(512); + } + + for(int i = 0; i < _grid.Length; i++) + _grid[i].Clear(); + } + + private readonly Mapper map; + private readonly List AllRooms = new List(); + private readonly Dictionary> Costs = new Dictionary>(); + private static List[] _grid = new List[1024]; + + public override bool IsTargetRoom(Room r) + { + return true; + } + + public override void OnStartedPathfind() + { + base.OnStartedPathfind(); + + foreach(Room x in StartRooms) + AllRooms.Remove(x); + } + + public override void OnEndedPathFind(PathfindResult pr) + { + base.OnEndedPathFind(pr); + + foreach(Room x in StartRooms) + AllRooms.Add(x); + + foreach(Room u in AllRooms) + { + _Internal_PathFinder_VisitAll pf = new _Internal_PathFinder_VisitAll((from val in AllRooms where val != u select val).ToArray()); + pf.CanUsePortals = CanUsePortals; + pf.CanUseRecalls = CanUseRecalls; + pf.CharacterLevel = CharacterLevel; + pf.CharacterTier = CharacterTier; + pf.IsGlobalQuest = IsGlobalQuest; + pf.IsSingleClassTier0 = IsSingleClassTier0; + pf.OverridePortals = OverridePortals; + pf.SkipExits = SkipExits; + pf.SkipPortals = SkipPortals; + pf.SkipRooms = SkipRooms; + pf.StartRooms = new[] { u }; + + PathfindResult p = map.Get(pf); + if(!p.Success) + { + pr.Success = false; + return; + } + + Costs[u.Entry] = new Dictionary(); + foreach(Room x in AllRooms) + { + if(x == u) + continue; + + if(x.Mapper_OpenBy != null) + Costs[u.Entry][x.Entry] = x.Mapper_OpenCost; + else + { + pr.Success = false; + return; + } + } + } + + OpenRoom(new[] { StartRooms[0].Entry }, 0); + + uint[] Finish = null; + int itr1 = 0, itr2 = 0; + while(itr1 < _grid.Length) + { + if(itr2 >= _grid[itr1].Count) + { + itr2 = 0; + _grid[itr1].Clear(); + itr1++; + continue; + } + + if(OpenRoom(_grid[itr1][itr2], (uint)itr1)) + { + Finish = _grid[itr1][itr2]; + break; + } + + itr2++; + } + + if(Finish == null) + pr.Success = false; + else + { + pr.Cost = itr1; + pr.Path.Clear(); + pr.Target = map.GetRoom(Finish[Finish.Length - 1]); + Room u = map.GetRoom(Finish[0]); + int j = 1; + while(u != null && j < Finish.Length) + { + Pathfinder_Entry pf = new Pathfinder_Entry(Finish[j]); + pf.StartRooms = new[] { u }; + pf.CanUsePortals = CanUsePortals; + pf.CanUseRecalls = CanUseRecalls; + pf.CharacterLevel = CharacterLevel; + pf.CharacterTier = CharacterTier; + pf.IsGlobalQuest = IsGlobalQuest; + pf.IsSingleClassTier0 = IsSingleClassTier0; + pf.OverridePortals = OverridePortals; + pf.SkipExits = SkipExits; + pf.SkipPortals = SkipPortals; + pf.SkipRooms = SkipRooms; + + PathfindResult p = map.Get(pf); + if(!p.Success) + { + pr.Success = false; + return; + } + + pr.Path.AddRange(p.Path); + u = map.GetRoom(Finish[j]); + j++; + } + } + } + + private bool OpenRoom(uint[] r, uint cost) + { + if(r.Length == AllRooms.Count) + return true; + + foreach(KeyValuePair x in Costs[r[r.Length - 1]]) + { + if(r.Contains(x.Key)) + continue; + + uint[] z = r.Concat(new[] { x.Key }).ToArray(); + uint c = cost + x.Value; + if(c < _grid.Length) + _grid[(int)c].Add(z); + } + + return false; + } + } + + public class _Internal_PathFinder_VisitAll : Pathfinder + { + public _Internal_PathFinder_VisitAll(params Room[] roomId) + { + AllRooms.AddRange(roomId); + } + + private readonly List AllRooms = new List(); + + public override bool IsTargetRoom(Room r) + { + AllRooms.Remove(r); + return AllRooms.Count == 0; + } + } +} diff --git a/Mapper/Finders/.svn/text-base/desktop.ini b/Mapper/Finders/.svn/text-base/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/Mapper/Finders/.svn/text-base/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/Mapper/Finders/.svn/tmp/desktop.ini b/Mapper/Finders/.svn/tmp/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/Mapper/Finders/.svn/tmp/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/Mapper/Finders/.svn/tmp/prop-base/desktop.ini b/Mapper/Finders/.svn/tmp/prop-base/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/Mapper/Finders/.svn/tmp/prop-base/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/Mapper/Finders/.svn/tmp/props/desktop.ini b/Mapper/Finders/.svn/tmp/props/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/Mapper/Finders/.svn/tmp/props/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/Mapper/Finders/.svn/tmp/text-base/desktop.ini b/Mapper/Finders/.svn/tmp/text-base/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/Mapper/Finders/.svn/tmp/text-base/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/Mapper/Finders/Area.cs b/Mapper/Finders/Area.cs new file mode 100644 index 0000000..4570a20 --- /dev/null +++ b/Mapper/Finders/Area.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Mapper +{ + public class Pathfinder_Area : Pathfinder + { + public Pathfinder_Area(params uint[] AreaID) + : base() + { + AreaId = AreaID; + } + + private readonly uint[] AreaId; + + public override bool IsTargetRoom(Room r) + { + return AreaId.Contains(r.Area.Entry); + } + } +} diff --git a/Mapper/Finders/Entry.cs b/Mapper/Finders/Entry.cs new file mode 100644 index 0000000..cb5e0ee --- /dev/null +++ b/Mapper/Finders/Entry.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Mapper +{ + public class Pathfinder_Entry : Pathfinder + { + public Pathfinder_Entry(params uint[] roomEntries) + : base() + { + TargetRoomEntries = roomEntries; + } + + public readonly uint[] TargetRoomEntries; + + public override bool IsTargetRoom(Room r) + { + return TargetRoomEntries.Contains(r.Entry); + } + } +} diff --git a/Mapper/Finders/Name.cs b/Mapper/Finders/Name.cs new file mode 100644 index 0000000..c0d80f3 --- /dev/null +++ b/Mapper/Finders/Name.cs @@ -0,0 +1,105 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; + +namespace Mapper +{ + public class Pathfinder_Name : Pathfinder + { + public Pathfinder_Name(NameTypes t, params string[] Names) + : base() + { + nt = t; + _names = Names; + if((t & NameTypes.Regex) != NameTypes.None) + { + _regexString = new Regex[Names.Length]; + for(int i = 0; i < Names.Length; i++) + { + if(string.IsNullOrEmpty(Names[i])) + continue; + + try + { + _regexString[i] = new Regex(Names[i], (t & NameTypes.CaseInsensitive) != NameTypes.None ? RegexOptions.IgnoreCase : RegexOptions.None); + } + catch + { + // User entered invalid regex pattern + } + } + } + else if((t & NameTypes.CaseInsensitive) != NameTypes.None) + { + for(int i = 0; i < _names.Length; i++) + _names[i] = _names[i].ToLower(); + } + } + + private readonly Regex[] _regexString; + private readonly string[] _names; + private readonly NameTypes nt; + + public override bool IsTargetRoom(Room r) + { + if(string.IsNullOrEmpty(r.Name)) + return false; + + if((nt & NameTypes.Regex) != NameTypes.None) + { + foreach(Regex x in _regexString) + { + if(x == null) + continue; + + if(x.Match(r.Name).Success) + return true; + } + } + else + { + string rname = r.Name; + if((nt & NameTypes.CaseInsensitive) != NameTypes.None) + rname = rname.ToLower(); + foreach(string x in _names) + { + if((nt & NameTypes.Partial) != NameTypes.None) + { + if(rname.Contains(x)) + return true; + } + else if(rname == x) + return true; + } + } + + return false; + } + } + + [Flags] + public enum NameTypes + { + /// + /// Exact name search. Room name must match what you entered and case sensitive. + /// + None = 0, + + /// + /// Room name must contain the string you entered. This setting is ignored if you set regex option. + /// + Partial = 1, + + /// + /// Room name vs. what you entered is not case sensitive. + /// + CaseInsensitive = 2, + + /// + /// You entered a regex string which must match room name. + /// + Regex = 4, + } +} diff --git a/Mapper/Finders/Unmapped.cs b/Mapper/Finders/Unmapped.cs new file mode 100644 index 0000000..26b5ce7 --- /dev/null +++ b/Mapper/Finders/Unmapped.cs @@ -0,0 +1,55 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Mapper +{ + public class Pathfinder_Unmapped : Pathfinder + { + public Pathfinder_Unmapped(bool unReconed) + : base() + { + UnReconed = unReconed; + } + + private bool UnReconed; + private uint[] AllowedAreas; + + public override void OnStartedPathfind() + { + base.OnStartedPathfind(); + + List a = new List(); + foreach(Room r in StartRooms) + { + if(r.Area.Entry == uint.MaxValue) + continue; + if(!a.Contains(r.Area.Entry)) + a.Add(r.Area.Entry); + } + + AllowedAreas = a.ToArray(); + } + + public override bool IsTargetRoom(Room r) + { + if(!AllowedAreas.Contains(r.Area.Entry)) + return false; + + foreach(Exit e in r.exits) + { + if(e.To.Area.Entry == uint.MaxValue) + return true; + } + + if(UnReconed) + { + if(!r.HasCustomFlag("reconed")) + return true; + } + + return base.IsTargetRoom(r); + } + } +} diff --git a/Mapper/Finders/VisitAll.cs b/Mapper/Finders/VisitAll.cs new file mode 100644 index 0000000..b251444 --- /dev/null +++ b/Mapper/Finders/VisitAll.cs @@ -0,0 +1,189 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Mapper +{ + public class PathFinder_VisitAll : Pathfinder + { + public PathFinder_VisitAll(Mapper mapper, params Room[] roomId) + : base() + { + map = mapper; + foreach(Room u in roomId) + { + if(!AllRooms.Contains(u)) + AllRooms.Add(u); + } + + if(_grid[0] == null) + { + for(int i = 0; i < _grid.Length; i++) + _grid[i] = new List(512); + } + + for(int i = 0; i < _grid.Length; i++) + _grid[i].Clear(); + } + + private readonly Mapper map; + private readonly List AllRooms = new List(); + private readonly Dictionary> Costs = new Dictionary>(); + private static List[] _grid = new List[1024]; + + public override bool IsTargetRoom(Room r) + { + return true; + } + + public override void OnStartedPathfind() + { + base.OnStartedPathfind(); + + foreach(Room x in StartRooms) + AllRooms.Remove(x); + } + + public override void OnEndedPathFind(PathfindResult pr) + { + base.OnEndedPathFind(pr); + + foreach(Room x in StartRooms) + AllRooms.Add(x); + + foreach(Room u in AllRooms) + { + _Internal_PathFinder_VisitAll pf = new _Internal_PathFinder_VisitAll((from val in AllRooms where val != u select val).ToArray()); + pf.CanUsePortals = CanUsePortals; + pf.CanUseRecalls = CanUseRecalls; + pf.CharacterLevel = CharacterLevel; + pf.CharacterTier = CharacterTier; + pf.IsGlobalQuest = IsGlobalQuest; + pf.IsSingleClassTier0 = IsSingleClassTier0; + pf.OverridePortals = OverridePortals; + pf.SkipExits = SkipExits; + pf.SkipPortals = SkipPortals; + pf.SkipRooms = SkipRooms; + pf.StartRooms = new[] { u }; + + PathfindResult p = map.Get(pf); + if(!p.Success) + { + pr.Success = false; + return; + } + + Costs[u.Entry] = new Dictionary(); + foreach(Room x in AllRooms) + { + if(x == u) + continue; + + if(x.Mapper_OpenBy != null) + Costs[u.Entry][x.Entry] = x.Mapper_OpenCost; + else + { + pr.Success = false; + return; + } + } + } + + OpenRoom(new[] { StartRooms[0].Entry }, 0); + + uint[] Finish = null; + int itr1 = 0, itr2 = 0; + while(itr1 < _grid.Length) + { + if(itr2 >= _grid[itr1].Count) + { + itr2 = 0; + _grid[itr1].Clear(); + itr1++; + continue; + } + + if(OpenRoom(_grid[itr1][itr2], (uint)itr1)) + { + Finish = _grid[itr1][itr2]; + break; + } + + itr2++; + } + + if(Finish == null) + pr.Success = false; + else + { + pr.Cost = itr1; + pr.Path.Clear(); + pr.Target = map.GetRoom(Finish[Finish.Length - 1]); + Room u = map.GetRoom(Finish[0]); + int j = 1; + while(u != null && j < Finish.Length) + { + Pathfinder_Entry pf = new Pathfinder_Entry(Finish[j]); + pf.StartRooms = new[] { u }; + pf.CanUsePortals = CanUsePortals; + pf.CanUseRecalls = CanUseRecalls; + pf.CharacterLevel = CharacterLevel; + pf.CharacterTier = CharacterTier; + pf.IsGlobalQuest = IsGlobalQuest; + pf.IsSingleClassTier0 = IsSingleClassTier0; + pf.OverridePortals = OverridePortals; + pf.SkipExits = SkipExits; + pf.SkipPortals = SkipPortals; + pf.SkipRooms = SkipRooms; + + PathfindResult p = map.Get(pf); + if(!p.Success) + { + pr.Success = false; + return; + } + + pr.Path.AddRange(p.Path); + u = map.GetRoom(Finish[j]); + j++; + } + } + } + + private bool OpenRoom(uint[] r, uint cost) + { + if(r.Length == AllRooms.Count) + return true; + + foreach(KeyValuePair x in Costs[r[r.Length - 1]]) + { + if(r.Contains(x.Key)) + continue; + + uint[] z = r.Concat(new[] { x.Key }).ToArray(); + uint c = cost + x.Value; + if(c < _grid.Length) + _grid[(int)c].Add(z); + } + + return false; + } + } + + public class _Internal_PathFinder_VisitAll : Pathfinder + { + public _Internal_PathFinder_VisitAll(params Room[] roomId) + { + AllRooms.AddRange(roomId); + } + + private readonly List AllRooms = new List(); + + public override bool IsTargetRoom(Room r) + { + AllRooms.Remove(r); + return AllRooms.Count == 0; + } + } +} diff --git a/Mapper/Finders/desktop.ini b/Mapper/Finders/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/Mapper/Finders/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/Mapper/Mapper.cs b/Mapper/Mapper.cs new file mode 100644 index 0000000..dfedf9c --- /dev/null +++ b/Mapper/Mapper.cs @@ -0,0 +1,1607 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; +using Mapper.Scripting; +using ProxyCore; +using ProxyCore.Input; +using ProxyCore.Output; +using ProxyCore.Scripting; +using System.IO; +using System.Runtime.Serialization; + +namespace Mapper +{ + public partial class Mapper : Plugin + { + public Mapper() + : base("mapper", "Mapper") + { + Author = "Duckbat"; + Version = 15; + Description = "This plugin will record what rooms you have been in and from that can generate speedwalks for you to easily move around the world of Aardwolf."; + UpdateUrl = "www.duckbat.com/plugins/update.mapper.txt"; + Website = "code.google.com/p/proxymud/"; + + Config = new MapperConfig(); + + RegisterCommand("pm", "", CommandMapper); + RegisterCommand("all", @"(.+)", CommandAll, 0, CMDFlags.None, "pm"); + RegisterCommand("count", "", CommandCount, 0, CMDFlags.None, "pm"); + RegisterCommand("createexit", "^(\\d+)(\\s+\\d+)?\\s+\"(.+)\"$", CommandCreateExit, 0, CMDFlags.None, "pm"); + RegisterCommand("createportal", "^(\\d+)\\s+\"(.+)\"$", CommandCreatePortal, 0, CMDFlags.None, "pm"); + RegisterCommand("delete", @"^(area|room|exit|portal)\s+(\d+)", CommandDelete, 3, CMDFlags.None, "pm"); + RegisterCommand("exits", @"^(help)?(room\s+\d+)?(\d+)?(\s+.+)?", CommandExit, 4, CMDFlags.None, "pm"); + RegisterCommand("find", @"^(room|area)(\s+exact)?(\s+case)?\s+(.+)", CommandFind, 1, CMDFlags.None, "pm"); + RegisterCommand("portals", "", CommandPortal, 4, CMDFlags.None, "pm"); + RegisterCommand("goto", @"(.+)", CommandGoto, 2, CMDFlags.None, "pm"); + RegisterCommand("import", @"(.+)", CommandImport, 0, CMDFlags.None, "pm"); + RegisterCommand("roominfo", @"^(help)?(\d+)?(\s+.+)?", CommandRoomInfo, 4, CMDFlags.None, "pm"); + RegisterCommand("save", @"(.+)", CommandSave, 4, CMDFlags.None, "pm"); + RegisterCommand("unmapped", @"^(go|all)$", CommandUnmapped, 2, CMDFlags.None, "pm"); + RegisterCommand("unreconed", @"^(go|all)$", CommandUnreconed, 3, CMDFlags.None, "pm"); + + RegisterTrigger("room.id", @"^\$gmcp\.room\.info\.num (-?\d+)$", TriggerRoomInfoNum); + RegisterTrigger("room.name", @"^\$gmcp\.room\.info\.name (.*)$", TriggerRoomInfoName); + RegisterTrigger("room.area", @"^\$gmcp\.room\.info\.zone (.*)$", TriggerRoomInfoArea); + RegisterTrigger("room.exit", @"^\$gmcp\.room\.info\.exits\.(\w) (-?\d+)$", TriggerRoomInfoExits); + RegisterTrigger("room.finish", @"^\$gmcp\.room\.info\.coords?\.", TriggerRoomInfoFinish); + RegisterTrigger("char.level", @"^\$gmcp\.char\.status\.level (\d+)$", TriggerCharStatusLevel); + RegisterTrigger("char.tier", @"^\$gmcp\.char\.base\.tier (\d+)$", TriggerCharBaseTier); + RegisterTrigger("char.remorts", @"^\$gmcp\.char\.base\.remorts (\d+)$", TriggerCharBaseRemorts); + RegisterTrigger("gq.join", @"@wYou have now joined the quest. See 'help gquest' for available commands.", + TriggerJoinedGQ, TriggerFlags.NotRegex); + RegisterTrigger("gq.left", @"@wYou are no longer part of the current quest.", TriggerLeftGQ, + TriggerFlags.NotRegex); + RegisterTrigger("gq.win", + @"^@RGlobal Quest@Y: @wThe global quest has been won by @Y\w+ @w- @Y\d+.. @wwin\.$", + TriggerLeftGQ); + RegisterTrigger("gq.quit", @"@wYou are no longer part of the current quest.", TriggerLeftGQ, TriggerFlags.NotRegex); + RegisterTrigger("where.name", @"^@GYou are in area : (.+)", TriggerWhereName); + RegisterTrigger("where.level", @"^@GLevel range is : @R(\d+) to (\d+)", TriggerWhereLevel); + RegisterTrigger("areas.start", @"^@WFrom To Lock Keyword Area Name", TriggerAreasStart); + RegisterTrigger("areas.end", @"@w---------------------------------------------------------------", TriggerAreasEnd, TriggerFlags.NotRegex); + RegisterTrigger("areas.entry", @"^\s+@w(\d+)\s+(\d+)\s+(@R\d+\s+)?@g([\d\w]+)\s+@c(.+)", TriggerAreasEntry); + RegisterTrigger("home", @"@wYou cannot return home from this room.", TriggerNoRecall, TriggerFlags.NotRegex); + RegisterTrigger("recall", @"@wYou cannot recall from this room.", TriggerNoRecall, TriggerFlags.NotRegex); + RegisterTrigger("portal", @"@wMagic walls bounce you back.", TriggerPrison, TriggerFlags.NotRegex); + RegisterTrigger("recon.area", @"^@wArea Name : (.+)", TriggerReconArea); + RegisterTrigger("recon.sector", @"^@wSector type is : (.+)", TriggerReconSector); + RegisterTrigger("recon.flags", @"^@wBase flags :(.*)", TriggerReconFlags); + RegisterTrigger("recon.healrate", @"^@wHeal rate : @c(-?\d+)", TriggerReconHealRate); + RegisterTrigger("recon.manarate", @"^@wMana rate : @c(-?\d+)", TriggerReconManaRate); + RegisterTrigger("recon.unable", "@wYou cannot perform reconnaissance in this room.", TriggerNoRecon, TriggerFlags.NotRegex); + RegisterTrigger("tags.exits", @"^(@w)?\{exits\}(.*)", TriggerTagsExits); + + Load(); + + // If we don't have this unmapped area set then create it, just so we can save rooms we haven't explored yet + if(GetArea(uint.MaxValue) == null) + { + Area a = new Area(uint.MaxValue); + a.Keyword = "mapper_unmapped"; + a.Name = "Mapper unmapped rooms"; + IAreas[a.Entry] = a; + } + + Path_Init(); + } + + private const string DBFileName = "mapperdb.xml"; + private const string DBFileBackup = "mapperdb_backup.xml"; + + private int Level = 1; + private int Tier = 0; + private bool ListenArea = false; + private int Remorts = 1; + private bool HasGQ = false; + private long WhenSave = 0; + + private void OnDeleted(Room r) + { + List del = new List(); + foreach(KeyValuePair x in IExits) + { + if(x.Key == uint.MaxValue || x.Key == 0) + continue; + if(!IRooms.ContainsKey(x.Value.ToRoom)) + del.Add(x.Key); + } + + foreach(uint x in del) + { + IExits[x].From.exits.Remove(IExits[x]); + IExits.Remove(x); + } + } + + /// + /// Fill a pathfinder with our current character values and return if we were successful in doing that. + /// + /// + public bool FillPathFinder(Pathfinder p) + { + Room r; + if(CurrentRoomId == uint.MaxValue || (r = GetRoom(CurrentRoomId)) == null || r.Area.Entry == uint.MaxValue) + return false; + p.CharacterLevel = Level; + p.CharacterTier = Tier; + p.CanUseRecalls = true; + p.CanUsePortals = true; + p.IsGlobalQuest = HasGQ; + p.IsSingleClassTier0 = Tier == 0 && Remorts == 1; + p.StartRooms = new[] { r }; + return true; + } + + #region Commands + private bool CommandAll(InputData i) + { + string[] spl; + if(!i.Arguments.Success || (spl = i.Arguments.Groups[1].Value.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries)).Length == 0) + { + World.Instance.SendMessage("@wSyntax: map all [room id] ...", i.ClientMask); + return true; + } + + List rooms = new List(); + bool hadConfirm = false; + foreach(string x in spl) + { + uint u; + if(uint.TryParse(x, out u)) + { + Room r = GetRoom(u); + if(r != null && !rooms.Contains(r)) + rooms.Add(r); + } + else if(x.ToLower() == "confirm") + hadConfirm = true; + } + + if(rooms.Count < 2) + { + World.Instance.SendMessage("@wSyntax: map all [room id] ...", i.ClientMask); + return true; + } + + if(rooms.Count > 10 && !hadConfirm) + { + World.Instance.SendMessage("@RWarning! @wEntered more than 10 rooms. This may be too slow to finish. Enter confirm at the end if you are sure you wish to do this pathfind.", i.ClientMask); + return true; + } + + int ms = Environment.TickCount; + PathFinder_VisitAll pf = new PathFinder_VisitAll(this, rooms.ToArray()); + FillPathFinder(pf); + PathfindResult pr = Get(pf); + ms = Environment.TickCount - ms; + + World.Instance.SendMessage("@wPathfind took @W" + ms + " @wms.", i.ClientMask); + if(!pr.Success) + { + World.Instance.SendMessage("@wPathfind failed.", i.ClientMask); + return true; + } + + string sw = PathfindResult.Speedwalk(pr.Path); + World.Instance.SendMessage("@wCost: @W" + pr.Cost, i.ClientMask); + World.Instance.SendMessage("@wSW: " + sw, i.ClientMask); + return true; + } + + private bool CommandImport(InputData i) + { + if(!i.Arguments.Success) + { + World.Instance.SendMessage("@wSyntax: map import ", i.ClientMask); + return true; + } + + StreamReader f; + try + { + f = new StreamReader(i.Arguments.Groups[1].Value); + } + catch + { + World.Instance.SendMessage("@wFailed opening file. Make sure it is in the same folder as ProxyMud.exe and make sure you entered the file extension too.", i.ClientMask); + return true; + } + + string l; + while((l = f.ReadLine()) != null) + { + if(l.StartsWith("{area}")) + { + l = l.Substring(6); + string key = l.Substring(0, l.IndexOf('\t')).Trim().ToLower(); + l = l.Substring(l.IndexOf('\t') + 1); + + if(string.IsNullOrEmpty(key)) + continue; + + if(GetArea(key) == null) + { + Area a = new Area(++_guidArea); + a.Name = l; + a.Keyword = key; + IAreas[a.Entry] = a; + } + else if(string.IsNullOrEmpty(GetArea(key).Name)) + GetArea(key).Name = l; + } + else if(l.StartsWith("{room}")) + { + l = l.Substring(6); + string key = l.Substring(0, l.IndexOf('\t')); + uint k; + if(!uint.TryParse(key, out k)) + continue; + + l = l.Substring(l.IndexOf('\t') + 1); + string name = l.Substring(0, l.IndexOf('\t')); + + l = l.Substring(l.IndexOf('\t') + 1).Trim().ToLower(); + Area a = GetArea(l); + if(a == null) + { + a = new Area(++_guidArea); + a.Keyword = l; + IAreas[a.Entry] = a; + } + + Room r = GetRoom(k); + if(r == null) + { + r = new Room(k); + IRooms[k] = r; + r.Name = name; + r.Area = a; + } + else + { + if(r.Area != a) + r.Area = a; + r.Name = name; + } + } + else if(l.StartsWith("{exit}")) + { + l = l.Substring(6); + string cmd = l.Substring(0, l.IndexOf('\t')); + l = l.Substring(l.IndexOf('\t') + 1); + + string fr = l.Substring(0, l.IndexOf('\t')); + l = l.Substring(l.IndexOf('\t') + 1); + + string tr = l.Substring(0, l.IndexOf('\t')); + l = l.Substring(l.IndexOf('\t') + 1); + + uint from; + uint to; + int minLevel; + + if(!uint.TryParse(fr, out from) || !uint.TryParse(tr, out to) || !int.TryParse(l, out minLevel)) + continue; + + Room fromroom = GetRoom(from); + Room toroom = GetRoom(to); + if(fromroom == null || toroom == null) + continue; + + string door = ""; + if(cmd.Contains(';')) + { + door = cmd.Substring(0, cmd.IndexOf(';')); + if(!door.StartsWith("open ") && !door.StartsWith("ope ") && !door.StartsWith("op ") && + !door.StartsWith("o ")) + door = ""; + else + { + door = door.Substring(door.IndexOf(' ') + 1).Trim(); + char dir = PathfindResult.IsDirectionCommand(door); + if(dir == 'x') + door = "open " + door; + else + door = "o"; + cmd = cmd.Substring(cmd.IndexOf(';') + 1); + } + } + + Exit e = null; + if(PathfindResult.IsDirectionCommand(cmd) != 'x') + e = fromroom.GetExit(PathfindResult.IsDirectionCommand(cmd)); + else + e = fromroom.GetExit(cmd); + if(e == null) + { + e = new Exit(++_guidExit); + e.Command = PathfindResult.IsDirectionCommand(cmd) != 'x' ? PathfindResult.IsDirectionCommand(cmd).ToString() : cmd; + e.From = fromroom; + e.To = toroom; + e.From.exits.Add(e); + e.From.UpdateExits(); + IExits[e.Entry] = e; + + if(door == "o") + e.AddFlag("door"); + else if(!string.IsNullOrEmpty(door)) + e.DoorCommand = door; + } + } + else if(l.Length == 0) + continue; + else + { + f.Close(); + World.Instance.SendMessage("@wInvalid mapper format. You must convert it to readable format with the converter.", i.ClientMask); + return true; + } + } + + f.Close(); + World.Instance.SendMessage("@wDone importing missing rooms / areas / exits from MUSH database.", i.ClientMask); + return true; + } + + private bool CommandSave(InputData i) + { + string fileName = DBFileName; + if(i.Arguments.Success) + fileName = i.Arguments.Groups[0].Value; + + Save(fileName); + World.Instance.SendMessage("@wSaved mapper database to '@W" + fileName + "@w'.", i.ClientMask); + return true; + } + + private bool CommandUnmapped(InputData i) + { + if(!i.Arguments.Success) + { + Room r = GetRoom(CurrentRoomId); + if(r == null) + { + World.Instance.SendMessage("@wYou are in an unkown room.", i.ClientMask); + return true; + } + + uint c = 0; + foreach(KeyValuePair x in IRooms) + { + if(x.Value.Area.Entry != r.Area.Entry) + continue; + + bool f = false; + foreach(Exit e in x.Value.exits) + { + if(e.To.Area.Entry == uint.MaxValue) + { + f = true; + break; + } + } + + if(f) + c++; + } + + if(c == 0) + { + World.Instance.SendMessage("@wDidn't find any rooms with exits to unmapped rooms in this area.", + i.ClientMask); + } + else + { + World.Instance.SendMessage( + "@wFound @C" + c + " @wroom" + (c != 1 ? "s" : "") + + " in this area that have exits to unmapped rooms.", i.ClientMask); + } + World.Instance.SendMessage("@wUse '@Wmap unmapped all@w' to see areas where exits to unmapped rooms are found.", i.ClientMask); + World.Instance.SendMessage("@wUse '@Wmap unmapped go@w' to go to the closest room where an exit to unmapped room is found (in current area only).", i.ClientMask); + return true; + } + + if(i.Arguments.Groups[1].Value.ToLower() == "all") + { + SortedDictionary> Unmapped = new SortedDictionary>(); + foreach(KeyValuePair x in IRooms) + { + bool f = false; + foreach(Exit e in x.Value.exits) + { + if(e.To.Area.Entry == uint.MaxValue) + { + f = true; + break; + } + } + + if(f) + { + string n = x.Value.Area.Name; + if(string.IsNullOrEmpty(n)) + n = x.Value.Area.Keyword; + if(!Unmapped.ContainsKey(n)) + Unmapped[n] = new Dictionary(); + if(!Unmapped[n].ContainsKey(x.Value.Area)) + Unmapped[n][x.Value.Area] = 1; + else + Unmapped[n][x.Value.Area]++; + } + } + + if(Unmapped.Count == 0) + World.Instance.SendMessage("@wDidn't find any rooms in any area that have exits to unmapped rooms.", i.ClientMask); + else + { + World.Instance.SendMessage("@WEntry Area Unmapped rooms", i.ClientMask); + World.Instance.SendMessage("@G===== ============================================ ==============", i.ClientMask); + int c = 0; + foreach(KeyValuePair> x in Unmapped) + { + foreach(KeyValuePair y in x.Value) + { + c++; + World.Instance.SendMessage("@Y" + string.Format("{0,-5}", y.Key.Entry) + " @M" + string.Format("{0,-" + "============================================".Length + "}", (!string.IsNullOrEmpty(y.Key.Name) ? y.Key.Name : y.Key.Keyword)) + " @C" + y.Value, i.ClientMask); + } + } + + World.Instance.SendMessage("@wFound @C" + c + " @warea" + (c != 1 ? "s" : "") + " with exits to unmapped rooms.", i.ClientMask); + } + return true; + } + + if(GetRoom(CurrentRoomId) == null) + { + World.Instance.SendMessage("@wYou are in an invalid room.", i.ClientMask); + return true; + } + + Pathfinder_Unmapped p = new Pathfinder_Unmapped(false); + FillPathFinder(p); + PathfindResult pr = Get(p); + if(!pr.Success) + { + World.Instance.SendMessage("@wCouldn't find a path or there weren't any rooms in this area with exits that lead to unmapped rooms.", i.ClientMask); + return true; + } + Goto(pr); + return true; + } + + private bool CommandUnreconed(InputData i) + { + if(!i.Arguments.Success) + { + Room r = GetRoom(CurrentRoomId); + if(r == null) + { + World.Instance.SendMessage("@wYou are in an unknown room.", i.ClientMask); + return true; + } + + uint c = 0; + foreach(KeyValuePair x in IRooms) + { + if(x.Value.Area.Entry != r.Area.Entry) + continue; + + bool f = false; + foreach(Exit e in x.Value.exits) + { + if(e.To.Area.Entry == uint.MaxValue) + { + f = true; + break; + } + } + if(!f && !x.Value.HasCustomFlag("reconed")) + f = true; + + if(f) + c++; + } + + if(c == 0) + { + World.Instance.SendMessage("@wDidn't find any rooms with exits to unmapped rooms or unreconed in this area.", + i.ClientMask); + } + else + { + World.Instance.SendMessage( + "@wFound @C" + c + " @wroom" + (c != 1 ? "s" : "") + + " in this area that have exits to unmapped rooms or aren't reconed.", i.ClientMask); + } + World.Instance.SendMessage("@wUse '@Wmap unreconed all@w' to see areas where exits to unmapped rooms or rooms that aren't reconed are found.", i.ClientMask); + World.Instance.SendMessage("@wUse '@Wmap unreconed go@w' to go to the closest room where an exit to unmapped room is found or that isn't reconed (in current area only).", i.ClientMask); + return true; + } + + if(i.Arguments.Groups[1].Value.ToLower() == "all") + { + SortedDictionary> Unmapped = new SortedDictionary>(); + foreach(KeyValuePair x in IRooms) + { + bool f = false; + foreach(Exit e in x.Value.exits) + { + if(e.To.Area.Entry == uint.MaxValue) + { + f = true; + break; + } + } + if(!f && !x.Value.HasCustomFlag("reconed")) + f = true; + + if(f) + { + string n = x.Value.Area.Name; + if(string.IsNullOrEmpty(n)) + n = x.Value.Area.Keyword; + if(!Unmapped.ContainsKey(n)) + Unmapped[n] = new Dictionary(); + if(!Unmapped[n].ContainsKey(x.Value.Area)) + Unmapped[n][x.Value.Area] = 1; + else + Unmapped[n][x.Value.Area]++; + } + } + + if(Unmapped.Count == 0) + World.Instance.SendMessage("@wDidn't find any rooms in any area that have exits to unmapped rooms or that aren't reconed.", i.ClientMask); + else + { + World.Instance.SendMessage("@WEntry Area Unmapped/Unreconed rooms", i.ClientMask); + World.Instance.SendMessage("@G===== ============================================ ========================", i.ClientMask); + int c = 0; + foreach(KeyValuePair> x in Unmapped) + { + foreach(KeyValuePair y in x.Value) + { + c++; + World.Instance.SendMessage("@Y" + string.Format("{0,-5}", y.Key.Entry) + " @M" + string.Format("{0,-" + "============================================".Length + "}", (!string.IsNullOrEmpty(y.Key.Name) ? y.Key.Name : y.Key.Keyword)) + " @C" + y.Value, i.ClientMask); + } + } + + World.Instance.SendMessage("@wFound @C" + c + " @warea" + (c != 1 ? "s" : "") + " with exits to unmapped rooms or unreconed rooms.", i.ClientMask); + } + return true; + } + + if(GetRoom(CurrentRoomId) == null) + { + World.Instance.SendMessage("@wYou are in an invalid room.", i.ClientMask); + return true; + } + + Pathfinder_Unmapped p = new Pathfinder_Unmapped(true); + FillPathFinder(p); + PathfindResult pr = Get(p); + if(!pr.Success) + { + World.Instance.SendMessage("@wCouldn't find a path or there weren't any rooms in this area with exits that lead to unmapped rooms or that aren't reconed.", i.ClientMask); + return true; + } + Goto(pr); + return true; + } + + private bool CommandDelete(InputData i) + { + // @"^(area|room|exit|portal)\s+(\d+)" + uint id; + if(!i.Arguments.Success || !uint.TryParse(i.Arguments.Groups[2].Value, out id) || id == uint.MaxValue) + { + World.Instance.SendMessage("@wSyntax: map delete area ", i.ClientMask); + World.Instance.SendMessage(" @wmap delete exit ", i.ClientMask); + World.Instance.SendMessage(" @wmap delete portal ", i.ClientMask); + World.Instance.SendMessage(" @wmap delete room ", i.ClientMask); + return true; + } + + string w = i.Arguments.Groups[1].Value.ToLower(); + + switch(w) + { + case "area": + { + Area a = GetArea(id); + if(a == null) + { + World.Instance.SendMessage("@wNo such area (@R" + id + "@w).", i.ClientMask); + return true; + } + + IAreas.Remove(a.Entry); + foreach(Room r in a.rooms) + { + IRooms.Remove(r.Entry); + foreach(Exit e in r.exits) + IExits.Remove(e.Entry); + OnDeleted(r); + } + + if(!string.IsNullOrEmpty(a.Name)) + World.Instance.SendMessage("@wDeleted area '@M" + a.Name + "@w'.", i.ClientMask); + else + World.Instance.SendMessage("@wDeleted area '@w" + a.Keyword + "@w'.", i.ClientMask); + } break; + + case "exit": + case "portal": + { + Exit e = GetExit(id); + if(e == null) + e = IPortals.ContainsKey(id) ? IPortals[id] : null; + if(e == null) + { + World.Instance.SendMessage("@wNo such exit or portal (@R" + id + "@w).", i.ClientMask); + return true; + } + + IExits.Remove(e.Entry); + IPortals.Remove(e.Entry); + if(!e.HasFlag("portal")) + e.From.exits.Remove(e); + else + e.To.Area.Portals.Remove(e); + + World.Instance.SendMessage("@wDeleted exit '@Y" + e.Entry + "@w'.", i.ClientMask); + } break; + + case "room": + { + Room r = GetRoom(id); + if(r == null) + { + World.Instance.SendMessage("@wNo such room (@R" + id + "@w).", i.ClientMask); + return true; + } + + IRooms.Remove(r.Entry); + r.Area.rooms.Remove(r); + OnDeleted(r); + World.Instance.SendMessage("@wDeleted room '@G" + r.Name + "@w'.", i.ClientMask); + } break; + } + + return true; + } + + private bool CommandFind(InputData i) + { + // @"^(room|area)(\s+exact)?(\s+case)?\s+(.+)" + if(!i.Arguments.Success) + { + World.Instance.SendMessage("@wSyntax: map find room [exact] [case] ", i.ClientMask); + World.Instance.SendMessage(" @wmap find area [exact] [case] ", i.ClientMask); + return true; + } + + if(i.Arguments.Groups[1].Value.ToLower() == "room") + { + string Str = i.Arguments.Groups[4].Value; + if(i.Arguments.Groups[3].Length == 0) + Str = Str.ToLower(); + List Found = new List(); + foreach(KeyValuePair x in IRooms) + { + string Name = x.Value.Name; + if(string.IsNullOrEmpty(Name)) + continue; + if(i.Arguments.Groups[3].Length == 0) + Name = Name.ToLower(); + + if(i.Arguments.Groups[2].Length != 0) + { + if(Name == Str) + Found.Add(x.Value); + } + else if(Name.Contains(Str)) + Found.Add(x.Value); + } + + if(Found.Count == 0) + World.Instance.SendMessage("@wFound nothing!", i.ClientMask); + else + { + World.Instance.SendMessage("@WEntry Name Area", i.ClientMask); + World.Instance.SendMessage("@G====== ================================ ===============================", i.ClientMask); + foreach(Room f in Found) + { + World.Instance.SendMessage("@Y" + string.Format("{0,6}", f.Entry) + " @G" + Utility.FormatColoredString(f.Name, -"================================".Length) + " " + (!string.IsNullOrEmpty(f.Area.Name) ? ("@M" + f.Area.Name) : ("@w" + f.Area.Keyword)), i.ClientMask); + } + World.Instance.SendMessage("@wFound @C" + Found.Count + " @wroom" + (Found.Count != 1 ? "s" : "") + ".", i.ClientMask); + } + } + else + { + string Str = i.Arguments.Groups[4].Value; + if(i.Arguments.Groups[3].Length == 0) + Str = Str.ToLower(); + List Found = new List(); + foreach(KeyValuePair x in IAreas) + { + string Name = x.Value.Name; + if(string.IsNullOrEmpty(Name)) + continue; + if(i.Arguments.Groups[3].Length == 0) + Name = Name.ToLower(); + + if(i.Arguments.Groups[2].Length != 0) + { + if(Name == Str) + Found.Add(x.Value); + } + else if(Name.Contains(Str)) + Found.Add(x.Value); + } + + if(Found.Count == 0) + World.Instance.SendMessage("@wFound nothing!", i.ClientMask); + else + { + World.Instance.SendMessage("@WEntry Keyword Name", i.ClientMask); + World.Instance.SendMessage("@G====== ========== ========================================", i.ClientMask); + foreach(Area f in Found) + { + World.Instance.SendMessage("@Y" + string.Format("{0,6}", f.Entry) + " @w" + Utility.FormatColoredString(f.Keyword, -10) + " @M" + f.Name, i.ClientMask); + } + World.Instance.SendMessage("@wFound @C" + Found.Count + " @warea" + (Found.Count != 1 ? "s" : "") + ".", i.ClientMask); + } + } + return true; + } + + private bool CommandMapper(InputData i) + { + World.Instance.SendMessage("@wAvailable mapper commands:", i.ClientMask); + World.Instance.SendMessage("@Y" + string.Format("{0,-20}", "map all") + " @w- Shows speedwalk that runs through all the rooms (IDs) you entered starting from your current location.", i.ClientMask); + World.Instance.SendMessage("@Y" + string.Format("{0,-20}", "map count") + " @w- Shows how many rooms you have mapped.", i.ClientMask); + World.Instance.SendMessage("@Y" + string.Format("{0,-20}", "map createexit") + " @w- Create a new exit.", i.ClientMask); + World.Instance.SendMessage("@Y" + string.Format("{0,-20}", "map createportal") + " @w- Create a new portal.", i.ClientMask); + World.Instance.SendMessage("@Y" + string.Format("{0,-20}", "map delete") + " @w- Delete a room, area or an exit.", i.ClientMask); + World.Instance.SendMessage("@Y" + string.Format("{0,-20}", "map exits") + " @w- Show exits information or edit them.", i.ClientMask); + World.Instance.SendMessage("@Y" + string.Format("{0,-20}", "map find") + " @w- Find rooms or areas in mapper.", i.ClientMask); + World.Instance.SendMessage("@Y" + string.Format("{0,-20}", "map goto") + " @w- Goto a room or an area.", i.ClientMask); + World.Instance.SendMessage("@Y" + string.Format("{0,-20}", "map import") + " @w- Import data file converted from mush mapper.", i.ClientMask); + World.Instance.SendMessage("@Y" + string.Format("{0,-20}", "map portals") + " @w- List all portals.", i.ClientMask); + World.Instance.SendMessage("@Y" + string.Format("{0,-20}", "map roominfo") + " @w- Show more information about a room or edit it.", i.ClientMask); + World.Instance.SendMessage("@Y" + string.Format("{0,-20}", "map save") + " @w- Save the mapper database now. Enter argument to save to another file.", i.ClientMask); + World.Instance.SendMessage("@Y" + string.Format("{0,-20}", "map unmapped") + " @w- Find unmapped rooms.", i.ClientMask); + World.Instance.SendMessage("@Y" + string.Format("{0,-20}", "map unreconed") + " @w- Find unmapped or unreconed rooms.", i.ClientMask); + return true; + } + + private bool CommandGoto(InputData i) + { + if(!i.Arguments.Success || i.Arguments.Groups[1].Value.Trim().Length == 0) + { + World.Instance.SendMessage("@wGo to the closest room entered.", i.ClientMask); + World.Instance.SendMessage("@wSyntax: map goto [room id] [room id]", i.ClientMask); + World.Instance.SendMessage(" @wmap goto ", i.ClientMask); + World.Instance.SendMessage(" @wmap goto ", i.ClientMask); + return true; + } + + if(CurrentRoomId == uint.MaxValue || GetRoom(CurrentRoomId) == null) + { + World.Instance.SendMessage("@wWe are in an unknown room.", i.ClientMask); + return true; + } + + List roomId = new List(); + Area aTarget = null; + string[] testIds = i.Arguments.Groups[1].Value.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); + foreach(string x in testIds) + { + uint u; + if(uint.TryParse(x, out u)) + { + if(GetRoom(u) == null) + { + World.Instance.SendMessage("@wNo such room (@R" + u + "@w)!", i.ClientMask); + continue; + } + if(!roomId.Contains(u)) + roomId.Add(u); + } + else + { + roomId = null; + break; + } + } + + if(roomId == null) + aTarget = GetArea(i.Arguments.Groups[1].Value); + + Pathfinder e; + if(roomId != null) + e = new Pathfinder_Entry(roomId.ToArray()); + else if(aTarget != null) + { + if(aTarget.StartRoom != 0) + e = new Pathfinder_Entry(aTarget.StartRoom); + else + e = new Pathfinder_Area(aTarget.Entry); + } + else + e = new Pathfinder_Name(NameTypes.Partial | NameTypes.CaseInsensitive, i.Arguments.Groups[1].Value); + + FillPathFinder(e); + PathfindResult pr = Get(e); + if(!pr.Success) + { + World.Instance.SendMessage("@wCouldn't find a path to any of the rooms entered.", i.ClientMask); + return true; + } + + if(aTarget != null) + World.Instance.SendMessage("@wGoing to area '@C" + pr.Target.Area.Name + "@w'...", i.ClientMask); + else + World.Instance.SendMessage("@wGoing to room '@G" + pr.Target.Name + "@w'...", i.ClientMask); + + Goto(pr); + return true; + } + + private bool CommandCount(InputData i) + { + int thisArea = 0; + int total = 0; + foreach(KeyValuePair x in IRooms) + { + if(x.Value.Area.Keyword == RoomInfoArea) + thisArea++; + if(x.Value.Area.Entry != uint.MaxValue) + total++; + } + World.Instance.SendMessage("@wYou have mapped @G" + thisArea + " @wrooms in this area.", i.ClientMask); + World.Instance.SendMessage("@wYou have @G" + (IAreas.Count - 1) + " @wareas in mapper.", i.ClientMask); + World.Instance.SendMessage("@wYou have mapped @G" + total + " @wrooms of Aardwolf.", i.ClientMask); + return true; + } + + #endregion + + #region Triggers + private bool TriggerNoRecon(TriggerData t) + { + Room r = GetRoom(CurrentRoomId); + if(r != null) + { + r.AddCustomFlag("reconed"); + r.AddCustomFlag("norecon"); + } + return false; + } + + private bool TriggerTagsExits(TriggerData t) + { + if(Config.GetInt32("Tags.Exits", 1) == 0) + return false; + + Room r = GetRoom(CurrentRoomId); + + StringBuilder str = new StringBuilder(); + string[] Exits = t.Match.Groups[2].Value.ToLower().Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); + CheckExit("north", 'n', Exits.Contains("north") || Exits.Contains("(north)"), Exits.Contains("(north)"), RoomInfoExits.ContainsKey('n') ? RoomInfoExits['n'] : 0, str); + CheckExit("east", 'e', Exits.Contains("east") || Exits.Contains("(east)"), Exits.Contains("(east)"), RoomInfoExits.ContainsKey('e') ? RoomInfoExits['e'] : 0, str); + CheckExit("south", 's', Exits.Contains("south") || Exits.Contains("(south)"), Exits.Contains("(south)"), RoomInfoExits.ContainsKey('s') ? RoomInfoExits['s'] : 0, str); + CheckExit("west", 'w', Exits.Contains("west") || Exits.Contains("(west)"), Exits.Contains("(west)"), RoomInfoExits.ContainsKey('w') ? RoomInfoExits['w'] : 0, str); + CheckExit("up", 'u', Exits.Contains("up") || Exits.Contains("(up)"), Exits.Contains("(up)"), RoomInfoExits.ContainsKey('u') ? RoomInfoExits['u'] : 0, str); + CheckExit("down", 'd', Exits.Contains("down") || Exits.Contains("(down)"), Exits.Contains("(down)"), RoomInfoExits.ContainsKey('d') ? RoomInfoExits['d'] : 0, str); + + if(r != null) + { + bool hadCustom = false; + foreach(Exit e in r.exits) + { + if(PathfindResult.IsDirectionCommand(e.Command) != 'x') + continue; + + hadCustom = true; + if(str.Length > 0) + str.Append(" "); + str.Append("@w'@C" + e.Command + "@w'"); + } + + if(!hadCustom && Exits.Contains("custom")) + { + if(str.Length > 0) + str.Append(" "); + str.Append("@Rcustom"); + } + } + + if(str.Length == 0) + str.Append("@Gnone"); + t.Msg.Msg = "@g[Exits: " + str.ToString() + "@g]"; + return false; + } + + private void CheckExit(string Word, char Dir, bool HasExits, bool IsClosed, uint LeadTo, StringBuilder str) + { + Room r = GetRoom(CurrentRoomId); + if(r == null) + { + if(!HasExits) + return; + + if(str.Length > 0) + str.Append(" "); + if(LeadTo == uint.MaxValue) + str.Append("@Y"); + else + str.Append("@G"); + str.Append(IsClosed ? ("(" + Word + ")") : Word); + return; + } + + if(LeadTo == uint.MaxValue) + { + if(str.Length > 0) + str.Append(" "); + str.Append("@Y"); + str.Append(IsClosed ? ("(" + Word + ")") : Word); + return; + } + + Exit e = r.GetExit(Dir); + if(e == null) + return; + + if(!HasExits) + { + if(e.HasFlag("hidden")) + { + if(str.Length > 0) + str.Append(" "); + str.Append("@y(" + Word + ")"); + return; + } + if(str.Length > 0) + str.Append(" "); + str.Append("@D(" + Word + ")"); + return; + } + + if(str.Length > 0) + str.Append(" "); + if(e.To.Area.Entry == uint.MaxValue) + str.Append("@R"); + else if(!e.To.HasCustomFlag("reconed") && Config.GetInt32("Tags.Exits.Recon", 0) != 0) + str.Append("@r"); + else + str.Append("@G"); + + if(IsClosed) + str.Append("(" + Word + ")"); + else + str.Append(Word); + } + + private bool TriggerNoRecall(TriggerData t) + { + Room r = GetRoom(CurrentRoomId); + if(r != null) + r.AddFlag("norecall"); + return false; + } + + private bool TriggerPrison(TriggerData t) + { + Room r = GetRoom(CurrentRoomId); + if(r != null) + r.AddFlag("prison"); + return false; + } + + private bool TriggerReconArea(TriggerData t) + { + Room r = GetRoom(CurrentRoomId); + if(r == null) + return false; + string msg = Colors.RemoveColors(t.Match.Groups[1].Value, false); + string name = msg.Substring(0, msg.LastIndexOf('(')).Trim(); + msg = msg.Substring(msg.LastIndexOf('(') + 1); + + r.Area.Name = name; + try + { + int min, max; + if(int.TryParse(msg.Substring(0, msg.IndexOf(' ')), out min)) + r.Area.MinLevel = min; + msg = msg.Substring(msg.IndexOf("to ") + 3); + if(int.TryParse(msg.Substring(0, msg.IndexOf(' ')), out max)) + r.Area.MaxLevel = max; + } + catch + { + } + r.AddCustomFlag("reconed"); + return false; + } + + private bool TriggerReconSector(TriggerData t) + { + Room r = GetRoom(CurrentRoomId); + if(r == null) + return false; + + r.Sector = Colors.RemoveColors(t.Match.Groups[1].Value, false); + return false; + } + + private bool TriggerReconHealRate(TriggerData t) + { + Room r = GetRoom(CurrentRoomId); + if(r == null) + return false; + + int rate; + if(int.TryParse(t.Match.Groups[1].Value, out rate)) + r.HealRate = rate; + return false; + } + + private bool TriggerReconManaRate(TriggerData t) + { + Room r = GetRoom(CurrentRoomId); + if(r == null) + return false; + + int rate; + if(int.TryParse(t.Match.Groups[1].Value, out rate)) + r.ManaRate = rate; + return false; + } + + private bool TriggerReconFlags(TriggerData t) + { + Room r = GetRoom(CurrentRoomId); + if(r == null) + return false; + + string[] fl = Colors.RemoveColors(t.Match.Groups[1].Value, false).Trim().ToLower().Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries); + if(r.IFlags != null) + r.IFlags.Clear(); + foreach(string x in fl) + r.AddFlag(x.Trim()); + return false; + } + + private bool TriggerAreasStart(TriggerData t) + { + ListenArea = true; + return false; + } + + private bool TriggerAreasEnd(TriggerData t) + { + ListenArea = false; + return false; + } + + private bool TriggerAreasEntry(TriggerData t) + { + if(!ListenArea) + return false; + + int minLevel, maxLevel, levelLock = 0; + + if(!int.TryParse(t.Match.Groups[1].Value, out minLevel) || + !int.TryParse(t.Match.Groups[2].Value, out maxLevel)) + return false; + + if(t.Match.Groups[3].Length != 0) + { + if(!int.TryParse(t.Match.Groups[3].Value, out levelLock)) + levelLock = 0; + } + + string keyWord = t.Match.Groups[4].Value; + string areaName = t.Match.Groups[5].Value.Trim(); + + Area a = GetArea(keyWord); + if(a == null) + { + a = new Area(++_guidArea); + IAreas[a.Entry] = a; + } + + a.Keyword = keyWord; + a.LevelLock = levelLock; + a.MaxLevel = maxLevel; + a.MinLevel = minLevel; + if(string.IsNullOrEmpty(a.Name) || a.Name.Length <= areaName.Length || !a.Name.StartsWith(areaName)) + a.Name = areaName; + return false; + } + + private bool TriggerWhereLevel(TriggerData t) + { + int minLevel, maxLevel; + if(!int.TryParse(t.Match.Groups[1].Value, out minLevel) || + !int.TryParse(t.Match.Groups[2].Value, out maxLevel)) + return false; + + Room cur = GetRoom(CurrentRoomId); + if(cur != null) + { + cur.Area.MinLevel = minLevel; + cur.Area.MaxLevel = maxLevel; + } + return false; + } + + private bool TriggerWhereName(TriggerData t) + { + string aName = Colors.RemoveColors(t.Match.Groups[1].Value, false).Trim(); + Room cur = GetRoom(CurrentRoomId); + if(cur != null) + cur.Area.Name = aName; + return false; + } + + private bool TriggerJoinedGQ(TriggerData t) + { + HasGQ = true; + return false; + } + + private bool TriggerLeftGQ(TriggerData t) + { + HasGQ = false; + return false; + } + + private bool TriggerCharStatusLevel(TriggerData t) + { + int i; + if(int.TryParse(t.Match.Groups[1].Value, out i)) + Level = i; + return false; + } + + private bool TriggerCharBaseTier(TriggerData t) + { + int i; + if(int.TryParse(t.Match.Groups[1].Value, out i)) + Tier = i; + return false; + } + + private bool TriggerCharBaseRemorts(TriggerData t) + { + int i; + if(int.TryParse(t.Match.Groups[1].Value, out i)) + Remorts = i; + return false; + } + + private bool TriggerRoomInfoNum(TriggerData t) + { + RoomInfoPrevious = RoomInfoEntry; + RoomInfoListen = true; + RoomInfoExits.Clear(); + uint i; + if(!uint.TryParse(t.Match.Groups[1].Value, out i)) + { + RoomInfoEntry = uint.MaxValue; + return false; + } + + RoomInfoEntry = i; + return false; + } + + private bool TriggerRoomInfoName(TriggerData t) + { + RoomInfoName = Colors.RemoveColors(t.Match.Groups[1].Value, true).Trim(); + return false; + } + + private bool TriggerRoomInfoArea(TriggerData t) + { + RoomInfoArea = t.Match.Groups[1].Value.Trim(); + return false; + } + + private bool TriggerRoomInfoExits(TriggerData t) + { + uint exitId; + RoomInfoExits[t.Match.Groups[1].Value.ToLower()[0]] = !uint.TryParse(t.Match.Groups[2].Value, out exitId) + ? uint.MaxValue + : exitId; + return false; + } + + private bool TriggerRoomInfoFinish(TriggerData t) + { + if(!RoomInfoListen) + return false; + + RoomInfoListen = false; + UpdateRoom(); + return false; + } + + #endregion + + #region Data + internal Dictionary IAreas = new Dictionary(); + internal Dictionary IRooms = new Dictionary(); + internal Dictionary IExits = new Dictionary(); + internal Dictionary IPortals = new Dictionary(); + + /// + /// Collection of all areas. + /// + public IEnumerable Areas + { + get + { + return IAreas.Values; + } + } + + /// + /// Collection of all rooms. + /// + public IEnumerable Rooms + { + get + { + return IRooms.Values; + } + } + + /// + /// Collection of all exits. + /// + public IEnumerable Exits + { + get + { + return IExits.Values; + } + } + + /// + /// Collection of all portals. + /// + public IEnumerable Portals + { + get + { + return IPortals.Values; + } + } + + private uint _guidArea = 0; + private uint _guidExit = 0; + + private void UpdateRoom() + { + CurrentRoomId = RoomInfoEntry; + + if(RoomInfoEntry == uint.MaxValue) + { + if(CurrentRoomId != RoomInfoPrevious) + { + Room prev = GetRoom(RoomInfoPrevious); + if(prev != null) + { + GetScript(prev).OnLeaveRoom(prev, null); + GetScript(prev).OnLeaveArea(prev.Area, null); + } + } + return; + } + + Room r = null; + Area a = null; + if(!IRooms.ContainsKey(CurrentRoomId)) + { + r = new Room(CurrentRoomId); + IRooms[r.Entry] = r; + } + else + r = IRooms[CurrentRoomId]; + + a = GetArea(RoomInfoArea); + if(a == null) + { + a = new Area(++_guidArea); + IAreas[a.Entry] = a; + a.Keyword = RoomInfoArea; + } + + if(r.Area != a) + r.Area = a; + + r.Name = RoomInfoName; + bool u = false; + foreach(KeyValuePair e in RoomInfoExits) + { + UpdateRoom(e.Value); + if(e.Value == uint.MaxValue) + continue; + Exit prev = r.GetExit(e.Key); + if(prev != null && prev.ToRoom == e.Value) + continue; + if(prev != null) + r.exits.Remove(prev); + Exit newExit = new Exit(++_guidExit); + newExit.To = GetRoom(e.Value); + newExit.Command = e.Key.ToString(); + newExit.From = r; + r.exits.Add(newExit); + IExits[newExit.Entry] = newExit; + u = true; + } + + if(u) + r.UpdateExits(); + + if(CurrentRoomId != RoomInfoPrevious) + { + Room prev = GetRoom(RoomInfoPrevious); + if(prev != null) + { + GetScript(prev).OnLeaveRoom(prev, r); + GetScript(prev).OnLeaveArea(prev.Area, r.Area); + } + GetScript(r).OnEnterArea(r.Area, prev != null ? prev.Area : null); + GetScript(r).OnEnterRoom(r, prev); + } + } + + private void UpdateRoom(uint Entry) + { + if(Entry == uint.MaxValue) + return; + + Room r = GetRoom(Entry); + if(r == null) + { + r = new Room(Entry); + IRooms[r.Entry] = r; + r.Area = GetArea(uint.MaxValue); + } + } + + internal uint CurrentRoomId; + private uint RoomInfoPrevious = uint.MaxValue; + private uint RoomInfoEntry = uint.MaxValue; + private string RoomInfoName; + private string RoomInfoArea; + private bool RoomInfoListen; + private Dictionary RoomInfoExits = new Dictionary(); + + /// + /// Get room by ID. + /// + /// ID of the room to get. + /// + public Room GetRoom(uint Entry) + { + return IRooms.ContainsKey(Entry) ? IRooms[Entry] : null; + } + + /// + /// Get exit by ID. + /// + /// ID of the exit to get. + /// + public Exit GetExit(uint Entry) + { + return IExits.ContainsKey(Entry) ? IExits[Entry] : null; + } + + /// + /// Get area by ID. + /// + /// ID of the area to get. + /// + public Area GetArea(uint Entry) + { + return IAreas.ContainsKey(Entry) ? IAreas[Entry] : null; + } + + /// + /// Get area by keyword. + /// + /// Keyword of area to get. + /// + public Area GetArea(string Keyword) + { + foreach(KeyValuePair x in IAreas) + { + if(x.Value.Keyword == Keyword) + return x.Value; + } + return null; + } + #endregion + + public override void Shutdown() + { + base.Shutdown(); + + Save(DBFileName); + } + + /// + /// Use mapper to go to the end of pathresult. + /// + /// + public void Goto(PathfindResult pr) + { + string sw = PathfindResult.Speedwalk(pr.Path); + if(string.IsNullOrEmpty(sw)) + sw = ""; + + if(Config.GetInt32("Speedwalk.Echo", 0) != 0) + { + World.Instance.SendMessage("@w{mapperpath}" + sw, Config.GetUInt64("Speedwalk.Echo.AuthMask", ulong.MaxValue)); + } + else if(!string.IsNullOrEmpty(sw)) + { + string[] swp = sw.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries); + foreach(string x in swp) + World.Instance.Execute(x, true); + } + else + World.Instance.SendMessage("@wTrying to execute an empty path. Using goto when you are already at target?"); + } + + #region Saving + private void Load() + { + StreamReader f; + try + { + f = new StreamReader(DBFileName); + } + catch + { + // No database exists or we aren't allowed to read it. Make a new database. + return; + } + + Area[] data; + try + { + DataContractSerializer x = new DataContractSerializer(typeof(Area[])); + data = x.ReadObject(f.BaseStream) as Area[]; + } + catch + { + f.Close(); + Log.Error("Failed loading mapper database! File corrupted?"); + return; + } + + f.Close(); + + if(data == null) + return; + + foreach(Area a in data) + { + if(a == null) + continue; + + IAreas[a.Entry] = a; + if(a.Entry > _guidArea && a.Entry != uint.MaxValue) + _guidArea = a.Entry; + foreach(Room r in a.rooms) + { + if(r == null) + continue; + r.Area = a; + IRooms[r.Entry] = r; + foreach(Exit e in r.exits) + { + if(e == null) + continue; + e.From = r; + IExits[e.Entry] = e; + if(e.Entry > _guidExit) + _guidExit = e.Entry; + } + r.UpdateExits(); + } + foreach(Exit p in a.Portals) + { + p.To = GetRoom(p.ToRoom); + IPortals[p.Entry] = p; + if(p.Entry > _guidExit) + _guidExit = p.Entry; + } + } + + foreach(KeyValuePair e in IExits) + { + if(IPortals.ContainsKey(e.Key)) + { + IPortals[e.Key].To.Area.Portals.Remove(IPortals[e.Key]); + IPortals.Remove(e.Key); + } + } + + List toDelete = new List(); + foreach(KeyValuePair e in IExits) + { + e.Value.To = IRooms.ContainsKey(e.Value.ToRoom) ? IRooms[e.Value.ToRoom] : null; + if(e.Value.To == null) + toDelete.Add(e.Value); + } + + foreach(Exit e in toDelete) + { + IExits.Remove(e.Entry); + e.From.exits.Remove(e); + } + + // Successfully loaded a database. Now make a backup because we have a working copy at the moment. + File.Delete(DBFileBackup); + File.Copy(DBFileName, DBFileBackup); + } + + private void Save(string fileName) + { + if(IAreas.Count == 0) + return; + StreamWriter f = new StreamWriter(fileName, false); + + try + { + DataContractSerializer x = new DataContractSerializer(typeof(Area[])); + x.WriteObject(f.BaseStream, IAreas.Values.ToArray()); + } + catch(Exception e) + { + f.Close(); + throw e; + } + + f.Close(); + if(Config.GetInt32("AutoSave", 0) != 0) + WhenSave = World.Instance.MSTime + Config.GetInt32("AutoSave", 0) * 1000; + } + #endregion + + public override void Update(long msTime) + { + base.Update(msTime); + + if(WhenSave == 0 && Config.GetInt32("AutoSave", 0) != 0) + WhenSave = Config.GetInt32("AutoSave", 0) * 1000 + msTime; + else if(WhenSave > 0 && WhenSave <= msTime) + Save(DBFileName); + } + } + + public class MapperConfig : ConfigFile + { + protected override void OnCreated() + { + base.OnCreated(); + + CreateSetting("Tags.Exits", 1, "Display extra information about exits using {exits} tag. You need to have \"tags exits on\"."); + CreateSetting("Tags.Exits.Recon", 0, "Display exits that lead to rooms that haven't been reconed yet in dark red."); + CreateSetting("Speedwalk.Echo", 0, "Echo speedwalk to clients instead of executing the command when using goto. This is useful if you like your MUD client to process it instead of mapper just sending to MUD, for example portal alias etc."); + CreateSetting("Speedwalk.Echo.AuthMask", ulong.MaxValue, "Security mask of who to echo the commands if you set Echo to 1."); + CreateSetting("AutoSave", 0, "Save mapper database every X seconds. For example enter 600 to save mapper database every 10 minutes. Enter 0 to disable this feature. The map is also saved on shutdown of program. You can also type \"map save\" to manually save the database."); + } + } +} diff --git a/Mapper/Mapper.csproj b/Mapper/Mapper.csproj new file mode 100644 index 0000000..d7aaeb2 --- /dev/null +++ b/Mapper/Mapper.csproj @@ -0,0 +1,104 @@ + + + + Debug + AnyCPU + 9.0.30729 + 2.0 + {9D34EF7A-07C1-43C5-9DAA-B1DE9F8EAA7D} + Library + Properties + Mapper + Mapper + v3.5 + 512 + + + + + 3.5 + publish\ + true + Disk + false + Foreground + 7 + Days + false + false + true + 0 + 1.0.0.%2a + false + false + true + + + true + full + false + ..\..\..\..\Desktop\MushProxy-Build\Plugins\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + ..\..\..\..\Desktop\MushProxy-Build\Plugins\ + TRACE + prompt + 4 + + + + False + ..\ProxyCore\bin\ProxyCore.dll + + + + 3.5 + + + 3.0 + + + 3.5 + + + 3.5 + + + + + + + + + + + + + + + + + + + + + + False + .NET Framework 3.5 SP1 + true + + + + + \ No newline at end of file diff --git a/Mapper/Pathfind.cs b/Mapper/Pathfind.cs new file mode 100644 index 0000000..1a81593 --- /dev/null +++ b/Mapper/Pathfind.cs @@ -0,0 +1,451 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Mapper.Scripting; + +namespace Mapper +{ + public partial class Mapper + { + private List[] _pGrid = new List[4096]; + private uint _pGridMax = 0; + private List[] _pExits = new[] { new List(), new List() }; + + private void Path_Init() + { + for(int i = 0; i < _pGrid.Length; i++) + _pGrid[i] = new List(512); + } + + private bool CanUsePortal(Exit p, Pathfinder x) + { + if(!p.HasFlag("recallmechanic")) + { + if(!x.CanUsePortals) + return false; + } + else + { + if(!x.CanUseRecalls) + return false; + } + + if(p.MinLevel > x.CharacterLevel + x.CharacterTier * 10 || + p.MaxLevel < x.CharacterLevel) + return false; + + if(p.HasFlag("nogq") && x.IsGlobalQuest) + return false; + + if(x.SkipPortals != null && x.SkipPortals.Contains(p)) + return false; + + return true; + } + + internal static AreaScript GetScript(Room r) + { + return AreaScriptMgr.GetScript(r.Area.Entry); + } + + public PathfindResult Get(Pathfinder p) + { + if(p.StartRooms != null) + p.StartRooms = p.StartRooms.Where(val => val != null).ToArray(); + if(p.StartRooms == null || p.StartRooms.Length == 0) + return new PathfindResult() { Success = false }; + + for(int i = 0; i < _pGridMax; i++) + _pGrid[i].Clear(); + _pExits[0].Clear(); + _pExits[1].Clear(); + _pGridMax = 0; + foreach(KeyValuePair x in IRooms) + { + x.Value.Mapper_OpenBy = null; + x.Value.Mapper_OpenCost = 0; + } + + p.OnStartedPathfind(); + + if(p.OverridePortals == null) + { + foreach(KeyValuePair x in IPortals) + { + if(!x.Value.HasFlag("disabled") && CanUsePortal(x.Value, p)) + _pExits[!x.Value.HasFlag("recallmechanic") ? 0 : 1].Add(x.Value); + } + } + else + { + foreach(Exit x in p.OverridePortals) + { + if(!x.HasFlag("disabled") && CanUsePortal(x, p)) + _pExits[!x.HasFlag("recallmechanic") ? 0 : 1].Add(x); + } + } + + Room Finish = null; + if(p.StartRooms != null) + { + foreach(Room r in p.StartRooms) + { + r.Mapper_OpenCost = uint.MaxValue; + if(OpenRoom(r, null, 0, p)) + { + Finish = r; + break; + } + } + } + + int itr1 = 0, itr2 = 0; + if(Finish == null) + { + while(itr1 < _pGrid.Length && itr1 < _pGridMax) + { + if(itr2 >= _pGrid[itr1].Count) + { + itr2 = 0; + itr1++; + continue; + } + + if(OpenRoom(_pGrid[itr1][itr2].To, _pGrid[itr1][itr2], (uint)itr1, p)) + { + Finish = _pGrid[itr1][itr2].To; + break; + } + + itr2++; + } + } + + PathfindResult pr = new PathfindResult(); + pr.Success = Finish != null; + pr.Cost = itr1; + pr.Target = Finish; + while(Finish != null && Finish.Mapper_OpenBy != null) + { + pr.Path.Insert(0, Finish.Mapper_OpenBy); + Finish = Finish.Mapper_OpenBy.From; + } + pr.Start = pr.Path.Count != 0 ? pr.Path[0].From : Finish; + + p.OnEndedPathFind(pr); + return pr; + } + + private bool OpenRoom(Room r, Exit from, uint cost, Pathfinder p) + { + if(r.Mapper_OpenBy != null || (from != null && p.StartRooms.Contains(r)) || r.Area.Entry == uint.MaxValue) + return false; + + r.Mapper_OpenBy = from; + r.Mapper_OpenCost = cost; + + if(p.IsTargetRoom(r)) + return true; + + if(_pExits[0].Count > 0 && !r.HasFlag("prison")) + { + for(int i = _pExits[0].Count - 1; i >= 0; i--) + { + if(_pExits[0][i].To.Mapper_OpenBy != null) + _pExits[0].RemoveAt(i); + else if(GetScript(r).CanUsePortal(_pExits[0][i], r) && p.CanUsePortal(_pExits[0][i], r)) + { + _pExits[0][i].From = r; + AddExit(_pExits[0][i], p, true); + _pExits[0].RemoveAt(i); + } + } + } + if(_pExits[1].Count > 0 && !r.HasFlag("norecall")) + { + for(int i = _pExits[1].Count - 1; i >= 0; i--) + { + if(_pExits[1][i].To.Mapper_OpenBy != null) + _pExits[1].RemoveAt(i); + else if(GetScript(r).CanUsePortal(_pExits[1][i], r) && p.CanUsePortal(_pExits[1][i], r)) + { + _pExits[1][i].From = r; + AddExit(_pExits[1][i], p, true); + _pExits[1].RemoveAt(i); + } + } + } + foreach(Exit e in r.exits) + { + if(e.To.Mapper_OpenBy != null) + continue; + if(e.To.Area.Entry == uint.MaxValue) + continue; + if(e.HasFlag("disabled")) + continue; + if(!GetScript(r).CanUseExit(e)) + continue; + if(e.MinLevel > p.CharacterLevel) + continue; + if(e.MaxLevel < p.CharacterLevel) + continue; + if(!p.CanUseExit(e)) + continue; + AddExit(e, p, false); + } + + return false; + } + + private void AddExit(Exit e, Pathfinder p, bool isPortal) + { + uint cost = e.From.Mapper_OpenCost + GetScript(e.From).GetLeaveRoomCost(e.From, e) + + (!isPortal ? GetScript(e.From).GetExitCost(e) : GetScript(e.From).GetPortalCost(e)) + GetScript(e.To).GetEnterRoomCost(e.To, e) + + p.GetLeaveRoomCost(e.From, e) + + (!isPortal ? p.GetExitCost(e) : p.GetPortalCost(e)) + p.GetEnterRoomCost(e.To, e); + + uint o = p.GetOverrideCost(e, isPortal); + if(o != uint.MaxValue) + cost = e.From.Mapper_OpenCost + o; + + if(cost >= _pGrid.Length) + return; + _pGrid[cost].Add(e); + cost++; + if(cost > _pGridMax) + _pGridMax = cost; + } + } + + public class PathfindResult + { + internal PathfindResult() + { + } + + public List Path = new List(); + public int Cost = 0; + public bool Success = false; + public Room Target; + public Room Start; + + /// + /// Generate a speedwalk from exit list. + /// + /// List of exits to generate a speedwalk from. + /// + public static string Speedwalk(IEnumerable Exits) + { + List sPath = new List(); + + foreach(Exit x in Exits) + { + string Door = Mapper.GetScript(x.From).GetDoorCommand(x); + string Command = Mapper.GetScript(x.From).GetExitCommand(x); + if(!string.IsNullOrEmpty(Door)) + sPath.AddRange(Door.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries)); + if(Command == null) + break; + sPath.AddRange(Command.Split(new[] {';'}, StringSplitOptions.RemoveEmptyEntries)); + } + + StringBuilder strSW = new StringBuilder(); + StringBuilder strCur = new StringBuilder(); + foreach(string x in sPath) + { + if(IsDirectionCommand(x) != 'x') + { + strCur.Append(char.ToLower(x[0])); + } + else + { + if(strCur.Length > 0) + { + if(strSW.Length > 0) + strSW.Append(';'); + if(strCur.Length > 1) + strSW.Append("run "); + strSW.Append(CompressPath(strCur.ToString())); + strCur.Remove(0, strCur.Length); + } + + if(strSW.Length > 0) + strSW.Append(';'); + + strSW.Append(x); + } + } + + if(strCur.Length > 0) + { + if(strSW.Length > 0) + strSW.Append(';'); + if(strCur.Length > 1) + strSW.Append("run "); + strSW.Append(CompressPath(strCur.ToString())); + strCur.Remove(0, strCur.Length); + } + + return strSW.ToString(); + } + + /// + /// Check if command is direction command. For example "west" -> 'w'. If it's not a direction + /// then return 'x'. + /// + /// Command to check. + /// + public static char IsDirectionCommand(string cmd) + { + cmd = cmd.ToLower().Trim(); + + if(cmd.Length == 0) + return 'x'; + + if(cmd.Length <= "north".Length && "north".StartsWith(cmd)) + return 'n'; + if(cmd.Length <= "west".Length && "west".StartsWith(cmd)) + return 'w'; + if(cmd.Length <= "south".Length && "south".StartsWith(cmd)) + return 's'; + if(cmd.Length <= "east".Length && "east".StartsWith(cmd)) + return 'e'; + if(cmd.Length <= "down".Length && "down".StartsWith(cmd)) + return 'd'; + if(cmd.Length <= "up".Length && "up".StartsWith(cmd)) + return 'u'; + return 'x'; + } + + /// + /// Compresses "wwssse" into "2w3se". + /// + /// Path to compress. + /// + public static string CompressPath(string path) + { + char dir = 'x'; + int c = 0; + StringBuilder str = new StringBuilder(); + for(int i = 0; i < path.Length; i++) + { + if(path[i] == dir) + { + c++; + continue; + } + + if(dir == 'x') + { + dir = path[i]; + c = 1; + continue; + } + + if(c > 1) + str.Append(c.ToString()); + str.Append(dir.ToString()); + dir = path[i]; + c = 1; + } + + if(dir != 'x') + { + if(c > 1) + str.Append(c.ToString()); + str.Append(dir.ToString()); + } + + return str.ToString(); + } + } + + public class Pathfinder + { + protected Pathfinder() + { + } + + /// + /// Set the character level for this path find. It is used in level lock areas and portals. + /// + public int CharacterLevel = 1; + public int CharacterTier = 0; + public bool IsGlobalQuest = false; + public bool CanUsePortals = true; + public bool CanUseRecalls = true; + public bool IsSingleClassTier0 = false; + public Room[] SkipRooms; + public Exit[] SkipExits; + public Exit[] SkipPortals; + public Room[] StartRooms; + public Exit[] OverridePortals; + + public virtual void CopyFrom(Pathfinder pf) + { + if(pf == null) + return; + + CharacterLevel = pf.CharacterLevel; + CharacterTier = pf.CharacterTier; + IsGlobalQuest = pf.IsGlobalQuest; + CanUsePortals = pf.CanUsePortals; + CanUseRecalls = pf.CanUseRecalls; + IsSingleClassTier0 = pf.IsSingleClassTier0; + SkipRooms = pf.SkipRooms; + SkipExits = pf.SkipExits; + SkipPortals = pf.SkipPortals; + StartRooms = pf.StartRooms; + OverridePortals = pf.OverridePortals; + } + + public virtual uint GetOverrideCost(Exit e, bool isPortal) + { + return uint.MaxValue; + } + + public virtual void OnStartedPathfind() + { + } + + public virtual bool IsTargetRoom(Room r) + { + return false; + } + + public virtual void OnEndedPathFind(PathfindResult pr) + { + } + + public virtual bool CanUseExit(Exit e) + { + return true; + } + + public virtual bool CanUsePortal(Exit p, Room r) + { + return true; + } + + public virtual uint GetLeaveRoomCost(Room r, Exit e) + { + return 0; + } + + public virtual uint GetExitCost(Exit e) + { + return 0; + } + + public virtual uint GetPortalCost(Exit e) + { + return 0; + } + + public virtual uint GetEnterRoomCost(Room r, Exit e) + { + return 0; + } + } +} diff --git a/Mapper/Properties/.svn/all-wcprops b/Mapper/Properties/.svn/all-wcprops new file mode 100644 index 0000000..649af27 --- /dev/null +++ b/Mapper/Properties/.svn/all-wcprops @@ -0,0 +1,11 @@ +K 25 +svn:wc:ra_dav:version-url +V 39 +/svn/!svn/ver/2/trunk/Mapper/Properties +END +AssemblyInfo.cs +K 25 +svn:wc:ra_dav:version-url +V 55 +/svn/!svn/ver/2/trunk/Mapper/Properties/AssemblyInfo.cs +END diff --git a/Mapper/Properties/.svn/desktop.ini b/Mapper/Properties/.svn/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/Mapper/Properties/.svn/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/Mapper/Properties/.svn/dir-prop-base b/Mapper/Properties/.svn/dir-prop-base new file mode 100644 index 0000000..f1b96ea --- /dev/null +++ b/Mapper/Properties/.svn/dir-prop-base @@ -0,0 +1,5 @@ +K 14 +bugtraq:number +V 4 +true +END diff --git a/Mapper/Properties/.svn/entries b/Mapper/Properties/.svn/entries new file mode 100644 index 0000000..c624b3e --- /dev/null +++ b/Mapper/Properties/.svn/entries @@ -0,0 +1,62 @@ +10 + +dir +58 +http://proxymud.googlecode.com/svn/trunk/Mapper/Properties +http://proxymud.googlecode.com/svn + + + +2012-01-17T10:55:35.805502Z +2 +default8p@gmail.com +has-props + + + + + + + + + + + + + +8a6e9f07-fe1d-2472-fcf8-0b435762827a + +AssemblyInfo.cs +file + + + + +2016-03-25T22:18:43.056138Z +7fb7e0921ad5edd499e2807ccac6b203 +2012-01-17T10:55:35.805502Z +2 +default8p@gmail.com + + + + + + + + + + + + + + + + + + + + + +1424 + diff --git a/Mapper/Properties/.svn/prop-base/desktop.ini b/Mapper/Properties/.svn/prop-base/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/Mapper/Properties/.svn/prop-base/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/Mapper/Properties/.svn/props/desktop.ini b/Mapper/Properties/.svn/props/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/Mapper/Properties/.svn/props/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/Mapper/Properties/.svn/text-base/AssemblyInfo.cs.svn-base b/Mapper/Properties/.svn/text-base/AssemblyInfo.cs.svn-base new file mode 100644 index 0000000..d3fc0d8 --- /dev/null +++ b/Mapper/Properties/.svn/text-base/AssemblyInfo.cs.svn-base @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("Mapper")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("Mapper")] +[assembly: AssemblyCopyright("Copyright © 2012")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("0cd0c5f1-be94-4ef7-bec4-a2f9ac9f7bed")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/Mapper/Properties/.svn/text-base/desktop.ini b/Mapper/Properties/.svn/text-base/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/Mapper/Properties/.svn/text-base/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/Mapper/Properties/.svn/tmp/desktop.ini b/Mapper/Properties/.svn/tmp/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/Mapper/Properties/.svn/tmp/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/Mapper/Properties/.svn/tmp/prop-base/desktop.ini b/Mapper/Properties/.svn/tmp/prop-base/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/Mapper/Properties/.svn/tmp/prop-base/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/Mapper/Properties/.svn/tmp/props/desktop.ini b/Mapper/Properties/.svn/tmp/props/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/Mapper/Properties/.svn/tmp/props/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/Mapper/Properties/.svn/tmp/text-base/desktop.ini b/Mapper/Properties/.svn/tmp/text-base/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/Mapper/Properties/.svn/tmp/text-base/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/Mapper/Properties/AssemblyInfo.cs b/Mapper/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..d3fc0d8 --- /dev/null +++ b/Mapper/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("Mapper")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("Mapper")] +[assembly: AssemblyCopyright("Copyright © 2012")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("0cd0c5f1-be94-4ef7-bec4-a2f9ac9f7bed")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/Mapper/Properties/desktop.ini b/Mapper/Properties/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/Mapper/Properties/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/Mapper/Room.cs b/Mapper/Room.cs new file mode 100644 index 0000000..fd98160 --- /dev/null +++ b/Mapper/Room.cs @@ -0,0 +1,256 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Runtime.Serialization; + +namespace Mapper +{ + [DataContract] + public class Room + { + public Room(uint entry) + { + Entry = entry; + } + + [DataMember] + public readonly uint Entry; + + [DataMember] + public string Name + { + get; + internal set; + } + + [DataMember] + public string Sector + { + get; + internal set; + } + + [DataMember] + internal List IFlags = null; + + public IEnumerable Flags + { + get + { + return IFlags; + } + } + + /// + /// Check if room has a flag. These are actual flags that you get from recon and not custom flags. + /// + /// Flag to check for. + /// + public bool HasFlag(string flag) + { + return IFlags != null && IFlags.Contains(flag.ToLower().Trim()); + } + + /// + /// Add a flag to room. These are actual flags that you get from recon and not custom flags. + /// + /// Flag to add. + public void AddFlag(string flag) + { + flag = flag != null ? flag.ToLower().Trim() : ""; + if(IFlags == null) + IFlags = new List(); + if(!string.IsNullOrEmpty(flag) && !IFlags.Contains(flag)) + IFlags.Add(flag); + } + + /// + /// Remove a flag from room. These are actual flags that you get from recon and not custom flags. + /// + /// Flag to remove. + /// + public bool RemoveFlag(string flag) + { + flag = flag != null ? flag.ToLower().Trim() : ""; + if(IFlags != null && IFlags.Contains(flag)) + { + IFlags.Remove(flag); + return true; + } + return false; + } + + [DataMember] + internal List CFlags = null; + + public IEnumerable CustomFlags + { + get + { + return CFlags; + } + } + + [DataMember] + public uint EntryCost + { + get; + internal set; + } + + [DataMember] + public uint LeaveCost + { + get; + internal set; + } + + /// + /// Check if room has a flag. These are custom flags and not actual flags like norecall which you get from recon. + /// + /// Flag to check for. + /// + public bool HasCustomFlag(string flag) + { + return CFlags != null && CFlags.Contains(flag.ToLower().Trim()); + } + + /// + /// Add a flag to room. These are custom flags and not actual flags like norecall which you get from recon. + /// + /// Flag to add. + public void AddCustomFlag(string flag) + { + flag = flag != null ? flag.ToLower().Trim() : ""; + if(CFlags == null) + CFlags = new List(); + if(!string.IsNullOrEmpty(flag) && !CFlags.Contains(flag)) + CFlags.Add(flag); + } + + /// + /// Remove a flag from room. These are custom flags and not actual flags like norecall which you get from recon. + /// + /// Flag to remove. + /// + public bool RemoveCustomFlag(string flag) + { + flag = flag != null ? flag.ToLower().Trim() : ""; + if(CFlags != null && CFlags.Contains(flag)) + { + CFlags.Remove(flag); + return true; + } + return false; + } + + [DataMember] + public int HealRate + { + get; + internal set; + } + + [DataMember] + public int ManaRate + { + get; + internal set; + } + + [DataMember] + internal List exits = new List(); + + internal uint Mapper_OpenCost = 0; + internal Exit Mapper_OpenBy = null; + + public Exit[] Exits + { + get + { + return exits.ToArray(); + } + } + + private Area _area; + + public Area Area + { + get + { + return _area; + } + internal set + { + if(_area != null) + _area.rooms.Remove(this); + _area = value; + if(!_area.rooms.Contains(this)) + _area.rooms.Add(this); + } + } + + public Exit GetExit(char Direction) + { + foreach(Exit e in exits) + { + if(!string.IsNullOrEmpty(e.Command) && e.Command.Length == 1 && e.Command[0] == Direction) + return e; + } + + return null; + } + + public Exit GetExit(string Command) + { + foreach(Exit e in exits) + { + if(!string.IsNullOrEmpty(e.Command) && e.Command == Command) + return e; + } + + return null; + } + + public Exit GetExit(uint Entry) + { + foreach(Exit e in exits) + { + if(e.Entry == Entry) + return e; + } + + return null; + } + + internal void UpdateExits() + { + SortedDictionary> x = new SortedDictionary>(); + foreach(Exit e in exits) + { + string cmd; + if(string.IsNullOrEmpty(e.Command) || string.IsNullOrEmpty(cmd = e.Command.ToLower().Trim())) + continue; + + e.Command = cmd; + if(!x.ContainsKey(e.Command)) + x[e.Command] = new List(); + x[e.Command].Add(e); + } + + exits.Clear(); + + foreach(KeyValuePair> i in x) + { + foreach(Exit j in i.Value) + exits.Add(j); + } + } + + public override string ToString() + { + return "Room '" + (Name ?? "NULL") + "' [" + Entry + "]"; + } + } +} diff --git a/Mapper/Scripting/.svn/all-wcprops b/Mapper/Scripting/.svn/all-wcprops new file mode 100644 index 0000000..4a8b129 --- /dev/null +++ b/Mapper/Scripting/.svn/all-wcprops @@ -0,0 +1,11 @@ +K 25 +svn:wc:ra_dav:version-url +V 39 +/svn/!svn/ver/38/trunk/Mapper/Scripting +END +AreaScript.cs +K 25 +svn:wc:ra_dav:version-url +V 53 +/svn/!svn/ver/38/trunk/Mapper/Scripting/AreaScript.cs +END diff --git a/Mapper/Scripting/.svn/desktop.ini b/Mapper/Scripting/.svn/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/Mapper/Scripting/.svn/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/Mapper/Scripting/.svn/dir-prop-base b/Mapper/Scripting/.svn/dir-prop-base new file mode 100644 index 0000000..f1b96ea --- /dev/null +++ b/Mapper/Scripting/.svn/dir-prop-base @@ -0,0 +1,5 @@ +K 14 +bugtraq:number +V 4 +true +END diff --git a/Mapper/Scripting/.svn/entries b/Mapper/Scripting/.svn/entries new file mode 100644 index 0000000..4659b19 --- /dev/null +++ b/Mapper/Scripting/.svn/entries @@ -0,0 +1,62 @@ +10 + +dir +58 +http://proxymud.googlecode.com/svn/trunk/Mapper/Scripting +http://proxymud.googlecode.com/svn + + + +2012-01-24T08:55:03.660104Z +38 +default8p@gmail.com +has-props + + + + + + + + + + + + + +8a6e9f07-fe1d-2472-fcf8-0b435762827a + +AreaScript.cs +file + + + + +2016-03-25T22:18:43.032138Z +d94fa1d66f2e719fb836c6d5b2448295 +2012-01-24T08:55:03.660104Z +38 +default8p@gmail.com + + + + + + + + + + + + + + + + + + + + + +2509 + diff --git a/Mapper/Scripting/.svn/prop-base/desktop.ini b/Mapper/Scripting/.svn/prop-base/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/Mapper/Scripting/.svn/prop-base/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/Mapper/Scripting/.svn/props/desktop.ini b/Mapper/Scripting/.svn/props/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/Mapper/Scripting/.svn/props/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/Mapper/Scripting/.svn/text-base/AreaScript.cs.svn-base b/Mapper/Scripting/.svn/text-base/AreaScript.cs.svn-base new file mode 100644 index 0000000..54530fd --- /dev/null +++ b/Mapper/Scripting/.svn/text-base/AreaScript.cs.svn-base @@ -0,0 +1,103 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; +using System.IO; +using ProxyCore; + +namespace Mapper.Scripting +{ + public class AreaScript + { + public AreaScript(params uint[] AreaID) + { + AreaId = AreaID; + } + + public readonly uint[] AreaId; + + public int RequiredMapperVersion + { + get; + protected set; + } + + public virtual bool CanUseExit(Exit e) + { + return true; + } + + public virtual bool CanUsePortal(Exit p, Room r) + { + return true; + } + + public virtual string GetExitCommand(Exit e) + { + return e.Command == "stop" ? null : e.Command; + } + + public virtual string GetDoorCommand(Exit e) + { + if(!string.IsNullOrEmpty(e.DoorCommand)) + return e.DoorCommand; + if(e.HasFlag("door") && PathfindResult.IsDirectionCommand(e.Command) != 'x') + return "open " + e.Command; + return string.Empty; + } + + public virtual uint GetLeaveRoomCost(Room r, Exit e) + { + return r.LeaveCost; + } + + public virtual uint GetExitCost(Exit e) + { + return e.Cost; + } + + public virtual uint GetPortalCost(Exit e) + { + return e.Cost; + } + + public virtual uint GetEnterRoomCost(Room r, Exit e) + { + return r.EntryCost; + } + + public virtual void OnEnterRoom(Room r, Room oldRoom) + { + } + + public virtual void OnLeaveRoom(Room r, Room newRoom) + { + } + + public virtual void OnEnterArea(Area a, Area oldArea) + { + } + + public virtual void OnLeaveArea(Area a, Area newArea) + { + } + } + + public class AreaScriptMgr + { + internal static Dictionary Scripts = new Dictionary(); + internal static AreaScript Default = new AreaScript(); + + public static void RegisterScript(uint AreaId, AreaScript Script) + { + if(Script != null) + Scripts[AreaId] = Script; + } + + internal static AreaScript GetScript(uint AreaId) + { + return Scripts.ContainsKey(AreaId) ? Scripts[AreaId] : Default; + } + } +} diff --git a/Mapper/Scripting/.svn/text-base/desktop.ini b/Mapper/Scripting/.svn/text-base/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/Mapper/Scripting/.svn/text-base/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/Mapper/Scripting/.svn/tmp/desktop.ini b/Mapper/Scripting/.svn/tmp/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/Mapper/Scripting/.svn/tmp/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/Mapper/Scripting/.svn/tmp/prop-base/desktop.ini b/Mapper/Scripting/.svn/tmp/prop-base/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/Mapper/Scripting/.svn/tmp/prop-base/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/Mapper/Scripting/.svn/tmp/props/desktop.ini b/Mapper/Scripting/.svn/tmp/props/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/Mapper/Scripting/.svn/tmp/props/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/Mapper/Scripting/.svn/tmp/text-base/desktop.ini b/Mapper/Scripting/.svn/tmp/text-base/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/Mapper/Scripting/.svn/tmp/text-base/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/Mapper/Scripting/AreaScript.cs b/Mapper/Scripting/AreaScript.cs new file mode 100644 index 0000000..54530fd --- /dev/null +++ b/Mapper/Scripting/AreaScript.cs @@ -0,0 +1,103 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; +using System.IO; +using ProxyCore; + +namespace Mapper.Scripting +{ + public class AreaScript + { + public AreaScript(params uint[] AreaID) + { + AreaId = AreaID; + } + + public readonly uint[] AreaId; + + public int RequiredMapperVersion + { + get; + protected set; + } + + public virtual bool CanUseExit(Exit e) + { + return true; + } + + public virtual bool CanUsePortal(Exit p, Room r) + { + return true; + } + + public virtual string GetExitCommand(Exit e) + { + return e.Command == "stop" ? null : e.Command; + } + + public virtual string GetDoorCommand(Exit e) + { + if(!string.IsNullOrEmpty(e.DoorCommand)) + return e.DoorCommand; + if(e.HasFlag("door") && PathfindResult.IsDirectionCommand(e.Command) != 'x') + return "open " + e.Command; + return string.Empty; + } + + public virtual uint GetLeaveRoomCost(Room r, Exit e) + { + return r.LeaveCost; + } + + public virtual uint GetExitCost(Exit e) + { + return e.Cost; + } + + public virtual uint GetPortalCost(Exit e) + { + return e.Cost; + } + + public virtual uint GetEnterRoomCost(Room r, Exit e) + { + return r.EntryCost; + } + + public virtual void OnEnterRoom(Room r, Room oldRoom) + { + } + + public virtual void OnLeaveRoom(Room r, Room newRoom) + { + } + + public virtual void OnEnterArea(Area a, Area oldArea) + { + } + + public virtual void OnLeaveArea(Area a, Area newArea) + { + } + } + + public class AreaScriptMgr + { + internal static Dictionary Scripts = new Dictionary(); + internal static AreaScript Default = new AreaScript(); + + public static void RegisterScript(uint AreaId, AreaScript Script) + { + if(Script != null) + Scripts[AreaId] = Script; + } + + internal static AreaScript GetScript(uint AreaId) + { + return Scripts.ContainsKey(AreaId) ? Scripts[AreaId] : Default; + } + } +} diff --git a/Mapper/Scripting/desktop.ini b/Mapper/Scripting/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/Mapper/Scripting/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/Mapper/desktop.ini b/Mapper/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/Mapper/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/MobDB/.svn/all-wcprops b/MobDB/.svn/all-wcprops new file mode 100644 index 0000000..ef91fd8 --- /dev/null +++ b/MobDB/.svn/all-wcprops @@ -0,0 +1,23 @@ +K 25 +svn:wc:ra_dav:version-url +V 28 +/svn/!svn/ver/57/trunk/MobDB +END +Mob.cs +K 25 +svn:wc:ra_dav:version-url +V 35 +/svn/!svn/ver/44/trunk/MobDB/Mob.cs +END +MobDB.csproj +K 25 +svn:wc:ra_dav:version-url +V 41 +/svn/!svn/ver/30/trunk/MobDB/MobDB.csproj +END +MobDB.cs +K 25 +svn:wc:ra_dav:version-url +V 37 +/svn/!svn/ver/57/trunk/MobDB/MobDB.cs +END diff --git a/MobDB/.svn/desktop.ini b/MobDB/.svn/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/MobDB/.svn/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/MobDB/.svn/dir-prop-base b/MobDB/.svn/dir-prop-base new file mode 100644 index 0000000..f1b96ea --- /dev/null +++ b/MobDB/.svn/dir-prop-base @@ -0,0 +1,5 @@ +K 14 +bugtraq:number +V 4 +true +END diff --git a/MobDB/.svn/entries b/MobDB/.svn/entries new file mode 100644 index 0000000..d2dd633 --- /dev/null +++ b/MobDB/.svn/entries @@ -0,0 +1,133 @@ +10 + +dir +58 +http://proxymud.googlecode.com/svn/trunk/MobDB +http://proxymud.googlecode.com/svn + + + +2012-02-08T08:41:07.654540Z +57 +default8p@gmail.com +has-props + + + + + + + + + + + + + +8a6e9f07-fe1d-2472-fcf8-0b435762827a + +MobDB.cs +file + + + + +2016-03-25T22:18:43.020138Z +9a5bdafe30e90ab584e89a5b306172db +2012-02-08T08:41:07.654540Z +57 +default8p@gmail.com + + + + + + + + + + + + + + + + + + + + + +47799 + +Properties +dir + +Mob.cs +file + + + + +2016-03-25T22:18:43.020138Z +bd0098124bb23de92ed01bf42623b33e +2012-01-29T09:57:36.978045Z +44 +default8p@gmail.com + + + + + + + + + + + + + + + + + + + + + +5728 + +MobDB.csproj +file + + + + +2016-03-25T22:18:43.020138Z +37f046a6d787788f20284b560615e701 +2012-01-23T07:49:14.623991Z +30 +default8p@gmail.com + + + + + + + + + + + + + + + + + + + + + +2879 + diff --git a/MobDB/.svn/prop-base/desktop.ini b/MobDB/.svn/prop-base/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/MobDB/.svn/prop-base/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/MobDB/.svn/props/desktop.ini b/MobDB/.svn/props/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/MobDB/.svn/props/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/MobDB/.svn/text-base/Mob.cs.svn-base b/MobDB/.svn/text-base/Mob.cs.svn-base new file mode 100644 index 0000000..5206373 --- /dev/null +++ b/MobDB/.svn/text-base/Mob.cs.svn-base @@ -0,0 +1,207 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.Serialization; +using System.Text; + +namespace MobDB +{ + [DataContract] + public class Mob + { + internal Mob(uint e) + { + Entry = e; + } + + /// + /// ID of the mob. + /// + [DataMember] + public readonly uint Entry; + + /// + /// (Short)name of the mob, such as "an ant". This is what we see when fighting the mob. + /// This field is an array because same longname mobs can sometimes have multiple different names. + /// Names here are automatically normalized where first letter of the name is made lower case, rest + /// is left intact. Keep that in mind when comparing names. + /// + public string[] Name + { + get + { + return _name; + } + internal set + { + _name = value ?? new string[0]; + for(int i = 0; i < _name.Length; i++) + { + if(!string.IsNullOrEmpty(_name[i])) + _name[i] = MobDB.NormalizeName(_name[i]); + } + } + } + + [DataMember] + private string[] _name; + + /// + /// Return all names separated by a comma ",". + /// + public string Names + { + get + { + string str = ""; + foreach(string x in Name) + { + if(str.Length > 0) + str += ", "; + str += x; + } + + return str; + } + } + + /// + /// Long name of the mob, this is what we see in room when we type look. + /// + [DataMember] + public string Longname + { + get; + internal set; + } + + /// + /// Keywords of the mob, can be multiple separated with a space. + /// + [DataMember] + public string Keyword + { + get; + internal set; + } + + /// + /// Level of the mob, we get this from lastkills. For non-killable mobs this is -1. + /// + [DataMember] + public int Level + { + get; + internal set; + } + + /// + /// Keywords of areas this mob can be in. Have a keyword "all" if you want mob to be in any area like the Firestorm Phoenix. + /// + [DataMember] + public string[] Areas + { + get; + internal set; + } + + /// + /// Override the default color of mob with this. Set to null or empty string to disable this and use + /// default color from the configuration file instead. + /// + [DataMember] + public string DefaultColor + { + get; + internal set; + } + + [DataMember] + internal List Flags; + + [DataMember] + internal List Locations = new List(); + + /// + /// Calculate chance that mob will be in room with this ID. + /// + /// Room ID to check mob in. + /// + public double GetChance(uint RoomId) + { + foreach(MobLocation ml in Locations) + { + if(ml.RoomEntry != RoomId) + continue; + + return (ml.CountSeen * 100) / (double)(ml.CountSeen - ml.TimesSeen + ml.TimesVisited); + } + + return 0.0; + } + + /// + /// Calculate room ID with best chance of having mob in it. + /// + /// + public uint GetBestRoom() + { + double b = 0.0; + uint c = uint.MaxValue; + foreach(MobLocation ml in Locations) + { + double a = GetChance(ml.RoomEntry); + if(a > b) + { + b = a; + c = ml.RoomEntry; + } + } + + return c; + } + + /// + /// Add a flag to mob. + /// + /// Flag to add. + public void AddFlag(string f) + { + if(f == null) + return; + f = f.ToLower().Trim(); + if(f.Length == 0) + return; + + if(Flags == null) + Flags = new List(); + if(!Flags.Contains(f)) + Flags.Add(f); + } + + /// + /// Remove a flag from mob. + /// + /// Flag to remove. + /// + public bool RemoveFlag(string f) + { + if(f == null || Flags == null) + return false; + f = f.ToLower().Trim(); + if(f.Length == 0) + return false; + return Flags.Remove(f); + } + + public bool HasFlag(string f) + { + if(f == null) + return false; + f = f.ToLower().Trim(); + if(f.Length == 0) + return false; + return Flags != null && Flags.Contains(f); + } + } +} diff --git a/MobDB/.svn/text-base/MobDB.cs.svn-base b/MobDB/.svn/text-base/MobDB.cs.svn-base new file mode 100644 index 0000000..5a1889f --- /dev/null +++ b/MobDB/.svn/text-base/MobDB.cs.svn-base @@ -0,0 +1,1210 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Runtime.Serialization; +using System.Text; +using ProxyCore; +using ProxyCore.Input; +using ProxyCore.Output; +using ProxyCore.Scripting; + +namespace MobDB +{ + public class MobDB : Plugin + { + public MobDB() + : base("mobdb", "Mob database") + { + Author = "Duckbat"; + Version = 5; + Description = + "You can add mobs to database so we can automatically record their locations and later find them when campaigning."; + UpdateUrl = "www.duckbat.com/plugins/update.mobdb.txt"; + Website = "code.google.com/p/proxymud/"; + + RequiredPlayerConfig.Add("tags roomchars on"); + + Config = new MobDBConfig(); + + RegisterCommand("mobdb", "", CommandMobDB); + RegisterCommand("add", @"(.+)", CommandAdd, 0, CMDFlags.None, "mobdb"); + RegisterCommand("count", "", CommandCount, 0, CMDFlags.None, "mobdb"); + RegisterCommand("delete", @"(.+)", CommandDelete, 0, CMDFlags.None, "mobdb"); + RegisterCommand("find", @"(exact\s+)?(case\s+)?(.+)", CommandFind, 0, CMDFlags.None, "mobdb"); + RegisterCommand("mobinfo", @"^\s*(\d+)?(\s+.+)?", CommandMobInfo, 3, CMDFlags.None, "mobdb"); + RegisterCommand("save", @"(.+)", CommandSave, 0, CMDFlags.None, "mobdb"); + RegisterCommand("where", @"(.+)", CommandWhere, 2, CMDFlags.None, "mobdb"); + + RegisterTrigger("room.id", @"^\$gmcp\.room\.info\.num (-?\d+)$", TriggerRoomInfoNum); + RegisterTrigger("room.area", @"^\$gmcp\.room\.info\.zone (.*)$", TriggerRoomInfoArea); + RegisterTrigger("room.chars1", @"^@w\{roomchars\}$", TriggerRoomChars1, TriggerFlags.None, 1500); + RegisterTrigger("room.chars2", @"^@w\{/roomchars\}$", TriggerRoomChars2, TriggerFlags.None, 500); + RegisterTrigger("room.chars3", @"(.*)", TriggerRoomChars3); + RegisterTrigger("lastkills1", "@WName Level Exp From", TriggerLastKills, + TriggerFlags.NotRegex); + RegisterTrigger("lastkills2", @"^@w(.{30})\s+(\d+)\s+\d+\s+(.+)", TriggerLastKills2); + + Load(); + } + + private string AddMobName; + private int AddMobLevel; + private string AddMobKeywords; + private string AddMobArea; + + private uint CurrentTime; + private uint RoomInfoEntry = uint.MaxValue; + private string RoomInfoArea; + private const string DBFileName = "mobdb.xml"; + private const string DBFileBackup = "mobdb_backup.xml"; + private readonly Dictionary IMobs = new Dictionary(); + private uint _guidMob = 0; + private long WhenSave = 0; + private readonly List UnknownMobs = new List(); + private bool ListeningRoomChars = false; + private readonly Dictionary overrideColors = new Dictionary(); + private int ChooseFromUnknown = 0; + private readonly Dictionary> RoomLocations = new Dictionary>(); + + /// + /// A collection of all mobs. + /// + public IEnumerable Mobs + { + get + { + return IMobs.Values; + } + } + + /// + /// Normalize mob name. This means first character of name will be made lower case while others are left as is. + /// + /// Name of mob. + /// + public static string NormalizeName(string mobName) + { + if(mobName == null) + return string.Empty; + + if(mobName.Length > 0) + mobName = mobName.Substring(0, 1).ToLower() + mobName.Substring(1); + return mobName; + } + + /// + /// Override mob colors when replacing with our longname. + /// + /// Mob ID. + /// Color code, for example "@M" + public void SetMobColor(uint Entry, string colorCode) + { + if(string.IsNullOrEmpty(colorCode)) + overrideColors.Remove(Entry); + else + overrideColors[Entry] = colorCode; + } + + /// + /// Clear all overridden mob colors. + /// + public void ClearMobColors() + { + overrideColors.Clear(); + } + + /// + /// Get mob by ID. + /// + /// ID of mob. + /// + public Mob GetMob(uint Id) + { + return IMobs.ContainsKey(Id) ? IMobs[Id] : null; + } + + private Mob GetMob(ref string t) + { + string orig = t; + t = t.Trim(); + + // Mobs can't be afk + if(t.StartsWith("@w[AFK]")) + { + t = orig; + return null; + } + + StringBuilder str = new StringBuilder(); + + // Unit is wounded + if(t.StartsWith("@R(Wounded)")) + { + t = Colors.RemoveDuplicateColors("@R" + t.Substring("@R(Wounded)".Length)).Trim(); + str.Append("@R(Wounded)"); + } + + if(t.StartsWith("@w(Invis)")) + { + t = Colors.RemoveDuplicateColors("@w" + t.Substring("@w(Invis)".Length)).Trim(); + str.Append("@w(Invis) "); + } + else if(t.StartsWith("@w(I)")) + { + t = Colors.RemoveDuplicateColors("@w" + t.Substring("@w(I)".Length)).Trim(); + str.Append("@w(I)"); + } + + if(t.StartsWith("@w(Hidden)")) + { + t = Colors.RemoveDuplicateColors("@w" + t.Substring("@w(Hidden)".Length)).Trim(); + str.Append("@w(Hidden) "); + } + else if(t.StartsWith("@w(H)")) + { + t = Colors.RemoveDuplicateColors("@w" + t.Substring("@w(H)".Length)).Trim(); + str.Append("@w(H)"); + } + + if(t.StartsWith("@W(Translucent)")) + { + t = Colors.RemoveDuplicateColors("@W" + t.Substring("@W(Translucent)".Length)).Trim(); + str.Append("@W(Translucent) "); + } + else if(t.StartsWith("@W(T)")) + { + t = Colors.RemoveDuplicateColors("@W" + t.Substring("@W(T)".Length)).Trim(); + str.Append("@W(T)"); + } + + if(t.StartsWith("@C(Charmed) ")) + { + //t = Colors.RemoveDuplicateColors("@C" + t.Substring("@C(Charmed) ".Length)); + t = orig; + return null; + } + else if(t.StartsWith("@C(C)")) + { + //t = Colors.RemoveDuplicateColors("@C" + t.Substring("@C(C)".Length)); + t = orig; + return null; + } + + if(t.StartsWith("@M(Animated) ")) + { + //t = Colors.RemoveDuplicateColors("@M" + t.Substring("@M(Animated) ".Length)); + t = orig; + return null; + } + else if(t.StartsWith("@M(A)")) + { + //t = Colors.RemoveDuplicateColors("@M" + t.Substring("@M(A)".Length)); + t = orig; + return null; + } + + if(t.StartsWith("@B(Diseased)")) + { + t = Colors.RemoveDuplicateColors("@B" + t.Substring("@B(Diseased)".Length)).Trim(); + str.Append("@B(Diseased) "); + } + else if(t.StartsWith("@B(D)")) + { + t = Colors.RemoveDuplicateColors("@B" + t.Substring("@B(D)".Length)).Trim(); + str.Append("@B(D)"); + } + + if(t.StartsWith("@D(Marked)")) + { + t = Colors.RemoveDuplicateColors("@D" + t.Substring("@D(Marked)".Length)).Trim(); + str.Append("@D(Marked) "); + } + else if(t.StartsWith("@D(X)")) + { + t = Colors.RemoveDuplicateColors("@D" + t.Substring("@D(X)".Length)).Trim(); + str.Append("@D(X)"); + } + + if(t.StartsWith("@r(Red Aura)")) + { + t = Colors.RemoveDuplicateColors("@r" + t.Substring("@r(Red Aura)".Length)).Trim(); + str.Append("@r(Red Aura)"); + } + else if(t.StartsWith("@r(R)")) + { + t = Colors.RemoveDuplicateColors("@r" + t.Substring("@r(R)".Length)).Trim(); + str.Append("@r(R)"); + } + else if(t.StartsWith("@y(Golden Aura)")) + { + t = Colors.RemoveDuplicateColors("@y" + t.Substring("@y(Golden Aura)".Length)).Trim(); + str.Append("@y(Golden Aura) "); + } + else if(t.StartsWith("@y(G)")) + { + t = Colors.RemoveDuplicateColors("@y" + t.Substring("@y(G)".Length)).Trim(); + str.Append("@y(G)"); + } + + if(t.StartsWith("@W(White Aura)")) + { + t = Colors.RemoveDuplicateColors("@W" + t.Substring("@W(White Aura)".Length)).Trim(); + str.Append("@W(White Aura) "); + } + else if(t.StartsWith("@W(W)")) + { + t = Colors.RemoveDuplicateColors("@W" + t.Substring("@W(W)".Length)).Trim(); + str.Append("@W(W)"); + } + + if(t.StartsWith("@R(Angry)")) + { + t = Colors.RemoveDuplicateColors("@R" + t.Substring("@R(Angry)".Length)).Trim(); + str.Append("@R(Angry) "); + } + + if(t.StartsWith("@w(Linkdead)")) + { + t = orig; + return null; + } + + if(t.StartsWith("@R(RAIDER)")) + { + t = orig; + return null; + } + + if(t.StartsWith("@R(TRAITOR)")) + { + t = orig; + return null; + } + + if(t.StartsWith("@G(DEFENDER)")) + { + t = orig; + return null; + } + + if(t.StartsWith("@R(WANTED)")) + { + t = orig; + return null; + } + + if(str.Length != 0 && str[str.Length - 1] != ' ') + str.Append(' '); + str.Append("{MOB}"); + + if(t.EndsWith("[TARGET]")) + { + t = Colors.RemoveDuplicateColors(t.Substring(0, t.LastIndexOf("[TARGET]"))).Trim(); + str.Append(" @R[TARGET]"); + } + + string area = RoomInfoArea.ToLower(); + foreach(KeyValuePair x in IMobs) + { + if(x.Value.Areas == null) + continue; + + if(!x.Value.Areas.Contains("all") && !x.Value.Areas.Contains(RoomInfoArea)) + continue; + + if(x.Value.Longname == t) + { + string n = Config.GetString("Mob.Longname", + "@w[@G$mob.level@w] $mob.color$mob.name @D($mob.keywords)"); + if(string.IsNullOrEmpty(n)) + { + t = orig; + return x.Value; + } + + n = n.Replace("$$", "\nE"); + n = n.Replace("$mob.level", x.Value.Level.ToString()); + n = n.Replace("$mob.keywords", x.Value.Keyword); + if(n.Contains("$mob.name")) + n = n.Replace("$mob.name", x.Value.Names); + n = n.Replace("$mob.color", + overrideColors.ContainsKey(x.Key) + ? overrideColors[x.Key] + : (!string.IsNullOrEmpty(x.Value.DefaultColor) + ? x.Value.DefaultColor + : Config.GetString("Mob.DefaultColor", "@y"))); + n = n.Replace("$mob.longname", x.Value.Longname); + n = n.Replace("$mob.entry", x.Key.ToString()); + n = n.Replace("\nE", "$"); + str.Replace("{MOB}", Colors.RemoveDuplicateColors(n)); + t = str.ToString(); + return x.Value; + } + } + + if(!UnknownMobs.Contains(t)) + UnknownMobs.Add(t); + t = orig; + return null; + } + + public override void OnEnteredCommandBefore(ref string Msg, uint ClientId, int AuthLevel) + { + base.OnEnteredCommandBefore(ref Msg, ClientId, AuthLevel); + + if(ChooseFromUnknown == 2) + { + int i; + if(int.TryParse(Msg, out i) && i >= 1 && i <= UnknownMobs.Count) + { + Msg = null; + i--; + ChooseFromUnknown = 0; + + Mob m = new Mob(++_guidMob); + m.Name = new[] { AddMobName }; + m.Longname = UnknownMobs[i]; + UnknownMobs.RemoveAt(i); + m.Level = AddMobLevel; + m.Keyword = AddMobKeywords; + m.Areas = new[] {AddMobArea}; + IMobs[m.Entry] = m; + + if(RoomInfoEntry != uint.MaxValue) + { + MobLocation ml = new MobLocation(); + ml.CountSeen = 1; + ml.LastVisited = 0; + ml.MobEntry = m.Entry; + ml.RoomEntry = RoomInfoEntry; + ml.TimesSeen = 1; + ml.TimesVisited = 1; + m.Locations.Add(ml); + + if(!RoomLocations.ContainsKey(RoomInfoEntry)) + RoomLocations[RoomInfoEntry] = new List(); + RoomLocations[RoomInfoEntry].Add(ml); + } + + World.Instance.SendMessage("@wAdded a new mob to database '@G" + m.Names + " @w' [@Y" + m.Entry + + "@w] and set location to current room."); + } + } + } + + #region Commands + private bool CommandWhere(InputData i) + { + if(!i.Arguments.Success) + { + World.Instance.SendMessage("@wSyntax: mobdb where ", i.ClientMask); + World.Instance.SendMessage("@wShows up to @W20 @wbest locations for a mob.", i.ClientMask); + World.Instance.SendMessage("", i.ClientMask); + World.Instance.SendMessage(" @wmobdb where ", i.ClientMask); + World.Instance.SendMessage("@wShows up to @W5 @wbest locations for all mobs that match this name in current area.", i.ClientMask); + return true; + } + + uint mobId; + if(uint.TryParse(i.Arguments.Groups[1].Value, out mobId)) + { + Mob m = GetMob(mobId); + if(m == null) + { + World.Instance.SendMessage("@wNo such mob in database (@R" + mobId + "@w).", i.ClientMask); + return true; + } + + if(!ShowLocations(m, 20, i.ClientMask, false)) + World.Instance.SendMessage("@wDon't know where '@G" + m.Names + "@w' [@Y" + m.Entry + "@w] is.", i.ClientMask); + } + else + { + string n = i.Arguments.Groups[1].Value.ToLower(); + bool showed = false; + foreach(KeyValuePair x in IMobs) + { + if(!x.Value.Areas.Contains("all") && !x.Value.Areas.Contains(RoomInfoArea)) + continue; + + bool f = false; + foreach(string z in x.Value.Name) + { + if(!z.ToLower().Contains(n)) + continue; + + f = true; + break; + } + + if(!f) + continue; + + showed = ShowLocations(x.Value, 5, i.ClientMask, showed); + } + + if(!showed) + World.Instance.SendMessage("@wFound no mob locations with that name.", i.ClientMask); + } + + return true; + } + + private bool ShowLocations(Mob m, int count, uint[] cm, bool isMulti) + { + SortedDictionary> bl = new SortedDictionary>(); + foreach(MobLocation ml in m.Locations) + { + double c = m.GetChance(ml.RoomEntry); + if(!bl.ContainsKey(c)) + bl[c] = new List(); + bl[c].Add(ml.RoomEntry); + } + + StringBuilder strRooms = new StringBuilder(); + bool showed = false; + IEnumerable>> x = bl.Reverse(); + foreach(KeyValuePair> y in x) + { + foreach(uint z in y.Value) + { + if(!showed) + { + if(isMulti) + World.Instance.SendMessage("", cm); + World.Instance.SendMessage("@wLocations for '@G" + m.Names + "@w' [@Y" + m.Entry + "@w]:", cm); + showed = true; + } + + World.Instance.SendMessage("@Y" + string.Format("{0,-6}", z) + " @C" + string.Format("{0:0.00}", y.Key) + "%", cm); + if(strRooms.Length > 0) + strRooms.Append(' '); + strRooms.Append(z); + count--; + if(count == 0) + break; + } + + if(count == 0) + break; + } + + if(strRooms.Length > 0) + World.Instance.SendMessage("@wmap goto " + strRooms); + + return showed; + } + + private bool CommandMobDB(InputData i) + { + World.Instance.SendMessage("@wAvailable mob db commands:", i.ClientMask); + World.Instance.SendMessage( + "@Y" + string.Format("{0,-20}", "mobdb add") + " @w- Add a new mob to database.", i.ClientMask); + World.Instance.SendMessage( + "@Y" + string.Format("{0,-20}", "mobdb count") + " @w- Shows how many mobs you have in database.", + i.ClientMask); + World.Instance.SendMessage( + "@Y" + string.Format("{0,-20}", "mobdb delete") + " @w- Delete a mob from database.", i.ClientMask); + World.Instance.SendMessage("@Y" + string.Format("{0,-20}", "mobdb find") + " @w- Find mobs in database.", + i.ClientMask); + World.Instance.SendMessage( + "@Y" + string.Format("{0,-20}", "mobdb mobinfo") + " @w- Show information or edit a mob.", i.ClientMask); + World.Instance.SendMessage( + "@Y" + string.Format("{0,-20}", "mobdb save") + " @w- Save mob database to file.", i.ClientMask); + World.Instance.SendMessage( + "@Y" + string.Format("{0,-20}", "mobdb where") + " @w- Show mob locations.", i.ClientMask); + return true; + } + + private bool CommandAdd(InputData i) + { + string n; + if(!i.Arguments.Success || (n = i.Arguments.Groups[1].Value.Trim()).Length == 0) + { + World.Instance.SendMessage("@wSyntax: mobdb add ", i.ClientMask); + return true; + } + + if(UnknownMobs.Count == 0) + { + World.Instance.SendMessage("@wWe have no mobs with unknown longname in roomlist.", i.ClientMask); + return true; + } + + AddMobKeywords = n; + ChooseFromUnknown = 1; + World.Instance.Execute("lastkills 1", false); + return true; + } + + private bool CommandMobInfo(InputData i) + { + if(!i.Arguments.Success || i.Arguments.Groups[1].Length == 0) + { + World.Instance.SendMessage("@wSyntax: mobdb mobinfo [option] [value]", i.ClientMask); + World.Instance.SendMessage("", i.ClientMask); + World.Instance.SendMessage("@wAvailable options for mob:", i.ClientMask); + World.Instance.SendMessage("@W" + string.Format("{0,-15}", "addflag") + " @w- Add a flag to mob.", + i.ClientMask); + World.Instance.SendMessage( + "@W" + string.Format("{0,-15}", "removeflag") + " @w- Remove a flag from mob.", i.ClientMask); + World.Instance.SendMessage("@W" + string.Format("{0,-15}", "name1") + " @w- Change (short)name of mob.", + i.ClientMask); + World.Instance.SendMessage("@W" + string.Format("{0,-15}", "name2") + " @w- Change second (short)name of mob.", + i.ClientMask); + World.Instance.SendMessage("@W" + string.Format("{0,-15}", "name3") + " @w- Change third (short)name of mob. (This goes all the way up to 999).", + i.ClientMask); + World.Instance.SendMessage( + "@W" + string.Format("{0,-15}", "areas") + + " @w- Set allowed areas for mob. Separate with space, enter all to allow all areas.", i.ClientMask); + World.Instance.SendMessage( + "@W" + string.Format("{0,-15}", "color") + " @w- Change default color of mob name. Enter default as value to set default color from config.", i.ClientMask); + World.Instance.SendMessage( + "@W" + string.Format("{0,-15}", "keywords") + " @w- Change keywords for mob.", i.ClientMask); + World.Instance.SendMessage( + "@W" + string.Format("{0,-15}", "longname") + " @w- Change longname (roomname) of mob.", + i.ClientMask); + World.Instance.SendMessage("@W" + string.Format("{0,-15}", "level") + " @w- Change level of mob.", + i.ClientMask); + World.Instance.SendMessage("@wEnter '@Wclear@w' as a shortname to remove that name from mob.", i.ClientMask); + return true; + } + + uint mobId; + if(!uint.TryParse(i.Arguments.Groups[1].Value, out mobId)) + { + World.Instance.SendMessage("@wInvalid mob ID given (@R" + i.Arguments.Groups[1].Value + "@w).", + i.ClientMask); + return true; + } + + Mob r = GetMob(mobId); + if(r == null) + { + World.Instance.SendMessage("@wNo such mob in database (@R" + mobId + "@w).", i.ClientMask); + return true; + } + + if(i.Arguments.Groups[2].Length != 0) + { + string key, val; + string str = i.Arguments.Groups[2].Value.Trim(); + if(str.Contains(' ')) + { + key = str.Substring(0, str.IndexOf(' ')).ToLower(); + val = str.Substring(key.Length).Trim(); + + switch(key) + { + case "addflag": + r.AddFlag(val); + break; + + case "removeflag": + r.RemoveFlag(val); + break; + + case "name": + if(r.Name.Length == 0) + r.Name = new[] { val }; + else + r.Name[0] = val; + break; + + case "level": + { + int lvl; + if(int.TryParse(val, out lvl)) + r.Level = lvl; + } break; + + case "areas": + { + string[] spl = val.ToLower().Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); + if(spl.Length > 0) + r.Areas = spl; + } break; + + case "keywords": + { + if(val.Length > 0) + r.Keyword = val; + } break; + + case "longname": + { + if(val == "clear") + r.Longname = ""; + else + r.Longname = val; + } break; + + case "color": + { + if(val == "clear" || val == "default" || val == "none") + r.DefaultColor = null; + else if(val.Length > 0) + r.DefaultColor = val; + } break; + } + + if(key.StartsWith("name") && key.Length > 4) + { + key = key.Substring(4); + int nth; + if(int.TryParse(key, out nth) && nth >= 1) + { + nth--; + List Names = r.Name.ToList(); + if(nth >= r.Name.Length) + { + if(val != "clear") + Names.Add(val); + } + else if(val != "clear") + Names[nth] = val; + else + Names.RemoveAt(nth); + + r.Name = Names.ToArray(); + } + } + } + } + + World.Instance.SendMessage("@w+----------------------------------------------------------------------+", + i.ClientMask); + World.Instance.SendMessage("@w| @WEntry @w: @Y" + string.Format("{0,-55}", r.Entry) + "@w|", + i.ClientMask); + int k = 0; + foreach(string z in r.Name) + { + ++k; + string tag = "Name (" + k + ")"; + World.Instance.SendMessage( + "@w| @W" + string.Format("{0,-11}", tag) + " @w: @G" + + string.Format("{0,-55}", !string.IsNullOrEmpty(z) ? z : "Unknown") + "@w|", i.ClientMask); + } + string area = ""; + if(r.Areas != null) + { + foreach(string y in r.Areas) + { + if(area.Length > 0) + area += " "; + area += y; + } + } + World.Instance.SendMessage("@w| @WArea @w: @M" + string.Format("{0,-55}", area) + "@w|", i.ClientMask); + { + StringBuilder strFlags = new StringBuilder(); + if(r.Flags != null) + { + foreach(string x in r.Flags) + { + if(strFlags.Length > 0) + strFlags.Append(", "); + strFlags.Append(x); + } + } + + string[] spl = Utility.WrapColored(strFlags.ToString(), 54, 0); + for(int j = 0; j < spl.Length; j++) + { + if(j == 0) + World.Instance.SendMessage("@w| @WFlags @w: " + string.Format("{0,-55}", spl[j]) + "@w|", + i.ClientMask); + else + World.Instance.SendMessage("@w| : " + string.Format("{0,-55}", spl[j]) + "@w|", + i.ClientMask); + } + } + + World.Instance.SendMessage("@w| @WLongname @w: " + Utility.FormatColoredString(r.Longname, -55) + "@w|", + i.ClientMask); + World.Instance.SendMessage("@w| @WKeywords @w: " + string.Format("{0,-55}", r.Keyword) + "@w|", + i.ClientMask); + World.Instance.SendMessage("@w| @WLevel @w: @Y" + string.Format("{0,-55}", r.Level) + "@w|", + i.ClientMask); + + string defColor = Config.GetString("Mob.DefaultColor", "@y"); + if(string.IsNullOrEmpty(r.DefaultColor)) + defColor += "Default"; + else + defColor = r.DefaultColor + r.DefaultColor.Replace("@", "@@"); + World.Instance.SendMessage("@w| @WColor @w: " + Utility.FormatColoredString(defColor, -55) + "@w|", + i.ClientMask); + + World.Instance.SendMessage("@w+----------------------------------------------------------------------+", + i.ClientMask); + return true; + } + + private bool CommandFind(InputData i) + { + if(!i.Arguments.Success) + { + World.Instance.SendMessage("@wSyntax: mobdb find [exact] [case] ", i.ClientMask); + return true; + } + + string name = i.Arguments.Groups[3].Value; + if(i.Arguments.Groups[2].Length == 0) + name = name.ToLower(); + else if(name.Length >= 1) + name = NormalizeName(name); + + World.Instance.SendMessage("@wSearched for '@W" + name + "@w'.", i.ClientMask); + List Found = new List(); + foreach(KeyValuePair x in IMobs) + { + if(i.Arguments.Groups[1].Length != 0) + { + if(i.Arguments.Groups[2].Length != 0) + { + if(x.Value.Name.Contains(name)) + Found.Add(x.Value); + } + else + { + foreach(string z in x.Value.Name) + { + if(z.ToLower() == name) + { + Found.Add(x.Value); + break; + } + } + } + } + else + { + if(i.Arguments.Groups[2].Length != 0) + { + if(x.Value.Name.Contains(name)) + Found.Add(x.Value); + } + else + { + foreach(string z in x.Value.Name) + { + if(z.ToLower().Contains(name)) + { + Found.Add(x.Value); + break; + } + } + } + } + } + + if(Found.Count != 0) + { + World.Instance.SendMessage("@WEntry Name Area Room", i.ClientMask); + World.Instance.SendMessage("@G====== ============================================= ============ ======", + i.ClientMask); + foreach(Mob x in Found) + { + string area = ""; + if(x.Areas != null) + { + foreach(string y in x.Areas) + { + if(area.Length != 0) + area += " "; + area += y; + } + } + string room = ""; + uint ro = x.GetBestRoom(); + if(ro != uint.MaxValue) + room = ro.ToString(); + World.Instance.SendMessage("@Y" + string.Format("{0,-6}", x.Entry) + " @c" + + string.Format( + "{0,-" + "=============================================".Length + "}", + x.Names) + " @g" + string.Format("{0,-12}", area) + " @Y" + room); + } + } + + World.Instance.SendMessage("@wFound @C" + Found.Count + " @wmob" + (Found.Count != 1 ? "s" : "") + ".", + i.ClientMask); + return true; + } + + private bool CommandDelete(InputData i) + { + if(!i.Arguments.Success) + { + World.Instance.SendMessage("@wSyntax: mobdb delete ", i.ClientMask); + World.Instance.SendMessage(" @wmobdb delete ", i.ClientMask); + World.Instance.SendMessage(" @wmobdb delete locations", i.ClientMask); + World.Instance.SendMessage(" @wmobdb delete all", i.ClientMask); + return true; + } + + if(i.Arguments.Groups[1].Value.ToLower().Trim() == "locations") + { + foreach(KeyValuePair x in IMobs) + { + x.Value.Locations.Clear(); + } + + World.Instance.SendMessage("@wDeleted all mob locations.", i.ClientMask); + return true; + } + + uint id; + if(uint.TryParse(i.Arguments.Groups[1].Value, out id)) + { + if(!IMobs.ContainsKey(id)) + World.Instance.SendMessage("@wNo such mob in database (@R" + id + "@w).", i.ClientMask); + else + { + World.Instance.SendMessage("@wDeleted '@G" + IMobs[id].Names + "@w'.", i.ClientMask); + foreach(MobLocation ml in IMobs[id].Locations) + { + RoomLocations[ml.RoomEntry].Remove(ml); + if(RoomLocations[ml.RoomEntry].Count == 0) + RoomLocations.Remove(ml.RoomEntry); + } + IMobs.Remove(id); + } + } + else + { + string key = i.Arguments.Groups[1].Value.ToLower().Trim(); + bool isConfirm = false; + if(key.Contains(' ')) + { + isConfirm = key.Substring(key.IndexOf(' ') + 1).Trim() == "confirm"; + key = key.Substring(0, key.IndexOf(' ')); + } + + if(key == "all" && !isConfirm) + { + World.Instance.SendMessage("@wAre you sure you wish to delete all mobs? Enter '@Wmobdb delete all confirm@w' to confirm.", i.ClientMask); + return true; + } + + List del = new List(); + foreach(KeyValuePair x in IMobs) + { + if(key == "all" || x.Value.Areas.Contains(key)) + del.Add(x.Key); + } + + foreach(uint x in del) + IMobs.Remove(x); + + World.Instance.SendMessage("@wDeleted @C" + del.Count + " @wmob" + (del.Count != 1 ? "s" : "") + ".", i.ClientMask); + } + return true; + } + + private bool CommandCount(InputData i) + { + int thisArea = 0; + int total = IMobs.Count; + if(!string.IsNullOrEmpty(RoomInfoArea)) + { + foreach(KeyValuePair x in IMobs) + { + if(x.Value.Areas == null || x.Value.Areas.Length == 0) + continue; + if(x.Value.Areas.Contains(RoomInfoArea)) + thisArea++; + } + } + World.Instance.SendMessage("@wYou have added @G" + thisArea + " @wmobs to database in this area.", + i.ClientMask); + World.Instance.SendMessage("@wYou have added @G" + total + " @wmobs to database in all areas.", i.ClientMask); + return true; + } + + private bool CommandSave(InputData i) + { + string fileName = DBFileName; + if(i.Arguments.Success) + fileName = i.Arguments.Groups[0].Value; + + Save(fileName); + World.Instance.SendMessage("@wSaved mob database to '@W" + fileName + "@w'.", i.ClientMask); + return true; + } + + #endregion + + #region Triggers + + private bool TriggerLastKills(TriggerData t) + { + if(ChooseFromUnknown == 1) + ChooseFromUnknown = 2; + return false; + } + + private bool TriggerLastKills2(TriggerData t) + { + if(ChooseFromUnknown == 0) + return false; + + AddMobName = t.Match.Groups[1].Value.Trim(); + if(!int.TryParse(t.Match.Groups[2].Value, out AddMobLevel) || UnknownMobs.Count == 0) + { + ChooseFromUnknown = 0; + return false; + } + AddMobArea = RoomInfoArea; + + int i = 1; + World.Instance.SendMessage("@wSelect mob longname from list (type number):"); + foreach(string x in UnknownMobs) + { + World.Instance.SendMessage("@W" + i + ". " + x); + i++; + } + return false; + } + + private bool TriggerRoomChars1(TriggerData t) + { + foundMobs.Clear(); + UnknownMobs.Clear(); + ListeningRoomChars = true; + if(Config.GetInt32("Tags.Gag", 1) != 0) + t.Msg.AuthMask = 0; + + CurrentTime = (uint)(DateTime.UtcNow - new DateTime(2012, 1, 1)).TotalSeconds; + return false; + } + + private bool TriggerRoomChars2(TriggerData t) + { + ListeningRoomChars = false; + if(Config.GetInt32("Tags.Gag", 1) != 0) + t.Msg.AuthMask = 0; + if(RoomInfoEntry != uint.MaxValue && RoomLocations.ContainsKey(RoomInfoEntry)) + { + foreach(MobLocation x in RoomLocations[RoomInfoEntry]) + { + Mob m = GetMob(x.MobEntry); + if(m != null && CurrentTime - x.LastVisited >= 600) + { + x.TimesVisited++; + if(foundMobs.Contains(m)) + x.TimesSeen++; + x.LastVisited = CurrentTime; + } + } + } + return false; + } + + private List foundMobs = new List(); + private bool TriggerRoomChars3(TriggerData t) + { + if(!ListeningRoomChars) + return false; + + string n = t.Msg.Msg; + Mob m = GetMob(ref n); + t.Msg.Msg = n; + + if(m == null) + return false; + + if(RoomInfoEntry != uint.MaxValue) + { + if(!foundMobs.Contains(m)) + foundMobs.Add(m); + + bool f = false; + foreach(MobLocation x in m.Locations) + { + if(x.RoomEntry != RoomInfoEntry) + continue; + + f = true; + if(CurrentTime - x.LastVisited >= 600) + x.CountSeen++; + break; + } + + if(!f) + { + MobLocation ml = new MobLocation(); + ml.RoomEntry = RoomInfoEntry; + ml.MobEntry = m.Entry; + ml.LastVisited = CurrentTime; + ml.TimesSeen = 0; + ml.TimesVisited = 0; + ml.CountSeen = 1; + m.Locations.Add(ml); + if(!RoomLocations.ContainsKey(RoomInfoEntry)) + RoomLocations[RoomInfoEntry] = new List(); + RoomLocations[RoomInfoEntry].Add(ml); + } + } + return false; + } + + private bool TriggerRoomInfoNum(TriggerData t) + { + if(ChooseFromUnknown != 0) + { + ChooseFromUnknown = 0; + World.Instance.SendMessage("@wChanged room. Mob adding was cancelled."); + } + UnknownMobs.Clear(); + uint i; + if(!uint.TryParse(t.Match.Groups[1].Value, out i)) + { + RoomInfoEntry = uint.MaxValue; + return false; + } + + RoomInfoEntry = i; + return false; + } + + private bool TriggerRoomInfoArea(TriggerData t) + { + RoomInfoArea = t.Match.Groups[1].Value.Trim(); + return false; + } + + #endregion + + #region Saving & Loading + + public override void Shutdown() + { + base.Shutdown(); + + Save(DBFileName); + } + + private void Load() + { + StreamReader f; + try + { + f = new StreamReader(DBFileName); + } + catch + { + // No database exists or we aren't allowed to read it. Make a new database. + return; + } + + Mob[] data; + try + { + DataContractSerializer x = new DataContractSerializer(typeof(Mob[])); + data = x.ReadObject(f.BaseStream) as Mob[]; + } + catch + { + f.Close(); + Log.Error("Failed loading mob database! File corrupted?"); + return; + } + + f.Close(); + + if(data == null) + return; + + foreach(Mob a in data) + { + if(a == null) + continue; + + IMobs[a.Entry] = a; + if(a.Entry > _guidMob && a.Entry != uint.MaxValue) + _guidMob = a.Entry; + + foreach(MobLocation m in a.Locations) + { + if(!RoomLocations.ContainsKey(m.RoomEntry)) + RoomLocations[m.RoomEntry] = new List(); + RoomLocations[m.RoomEntry].Add(m); + } + } + + // Successfully loaded a database. Now make a backup because we have a working copy at the moment. + File.Delete(DBFileBackup); + File.Copy(DBFileName, DBFileBackup); + } + + private void Save(string fileName) + { + if(IMobs.Count == 0) + return; + StreamWriter f = new StreamWriter(fileName, false); + + try + { + DataContractSerializer x = new DataContractSerializer(typeof(Mob[])); + x.WriteObject(f.BaseStream, IMobs.Values.ToArray()); + } + catch(Exception e) + { + f.Close(); + throw e; + } + + f.Close(); + if(Config.GetInt32("AutoSave", 0) != 0) + WhenSave = World.Instance.MSTime + Config.GetInt32("AutoSave", 0) * 1000; + } + + #endregion + + public override void Update(long msTime) + { + base.Update(msTime); + + if(WhenSave == 0 && Config.GetInt32("AutoSave", 0) != 0) + WhenSave = Config.GetInt32("AutoSave", 0) * 1000 + msTime; + else if(WhenSave > 0 && WhenSave <= msTime) + Save(DBFileName); + } + } + + [DataContract] + internal class MobLocation + { + [DataMember] + internal uint MobEntry; + + [DataMember] + internal uint RoomEntry; + + [DataMember] + internal uint TimesSeen; + + [DataMember] + internal uint CountSeen; + + [DataMember] + internal uint TimesVisited; + + [DataMember] + internal uint LastVisited; + } + + public class MobDBConfig : ConfigFile + { + protected override void OnCreated() + { + base.OnCreated(); + + CreateSetting("Mob.DefaultColor", "@y", "Default color for the mob. Color can be changed by other plugins"); + CreateSetting("Mob.Longname", "@w[@G$mob.level@w] $mob.color$mob.name @D($mob.keywords)", "Replace mob room name with this format. Set this to \"\" to disable mob replacing. You can have variables in the name such as:\n$mob.entry - This is the unique ID of mob (our assigned not mud).\n$mob.level - Level of the mob.\n$mob.name - Mob shortname, what appears when you are fighting it.\n$mob.longname - Mob room name.\n$mob.keywords - These are mob keywords.\n$mob.color - This is the color of the mob name. Can be set from other plugins or manually changed.\nEnter $$ to escape the $ character."); + CreateSetting("AutoSave", 0, "Save mob database every X seconds. For example enter 600 to save mob database every 10 minutes. Enter 0 to disable this feature. The database is also saved on shutdown of program. You can also type \"mobdb save\" to manually save the database."); + CreateSetting("Tags.Gag", 1, "Gag {roomchars} tags for clients."); + } + } +} diff --git a/MobDB/.svn/text-base/MobDB.csproj.svn-base b/MobDB/.svn/text-base/MobDB.csproj.svn-base new file mode 100644 index 0000000..8d3480b --- /dev/null +++ b/MobDB/.svn/text-base/MobDB.csproj.svn-base @@ -0,0 +1,67 @@ + + + + Debug + AnyCPU + 9.0.30729 + 2.0 + {8A7FE055-E1B4-4967-9C76-CA46BA854E73} + Library + Properties + MobDB + MobDB + v3.5 + 512 + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + False + ..\ProxyCore\bin\ProxyCore.dll + + + + 3.5 + + + 3.0 + + + 3.5 + + + 3.5 + + + + + + + + + + + + \ No newline at end of file diff --git a/MobDB/.svn/text-base/desktop.ini b/MobDB/.svn/text-base/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/MobDB/.svn/text-base/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/MobDB/.svn/tmp/desktop.ini b/MobDB/.svn/tmp/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/MobDB/.svn/tmp/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/MobDB/.svn/tmp/prop-base/desktop.ini b/MobDB/.svn/tmp/prop-base/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/MobDB/.svn/tmp/prop-base/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/MobDB/.svn/tmp/props/desktop.ini b/MobDB/.svn/tmp/props/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/MobDB/.svn/tmp/props/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/MobDB/.svn/tmp/text-base/desktop.ini b/MobDB/.svn/tmp/text-base/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/MobDB/.svn/tmp/text-base/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/MobDB/Mob.cs b/MobDB/Mob.cs new file mode 100644 index 0000000..5206373 --- /dev/null +++ b/MobDB/Mob.cs @@ -0,0 +1,207 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.Serialization; +using System.Text; + +namespace MobDB +{ + [DataContract] + public class Mob + { + internal Mob(uint e) + { + Entry = e; + } + + /// + /// ID of the mob. + /// + [DataMember] + public readonly uint Entry; + + /// + /// (Short)name of the mob, such as "an ant". This is what we see when fighting the mob. + /// This field is an array because same longname mobs can sometimes have multiple different names. + /// Names here are automatically normalized where first letter of the name is made lower case, rest + /// is left intact. Keep that in mind when comparing names. + /// + public string[] Name + { + get + { + return _name; + } + internal set + { + _name = value ?? new string[0]; + for(int i = 0; i < _name.Length; i++) + { + if(!string.IsNullOrEmpty(_name[i])) + _name[i] = MobDB.NormalizeName(_name[i]); + } + } + } + + [DataMember] + private string[] _name; + + /// + /// Return all names separated by a comma ",". + /// + public string Names + { + get + { + string str = ""; + foreach(string x in Name) + { + if(str.Length > 0) + str += ", "; + str += x; + } + + return str; + } + } + + /// + /// Long name of the mob, this is what we see in room when we type look. + /// + [DataMember] + public string Longname + { + get; + internal set; + } + + /// + /// Keywords of the mob, can be multiple separated with a space. + /// + [DataMember] + public string Keyword + { + get; + internal set; + } + + /// + /// Level of the mob, we get this from lastkills. For non-killable mobs this is -1. + /// + [DataMember] + public int Level + { + get; + internal set; + } + + /// + /// Keywords of areas this mob can be in. Have a keyword "all" if you want mob to be in any area like the Firestorm Phoenix. + /// + [DataMember] + public string[] Areas + { + get; + internal set; + } + + /// + /// Override the default color of mob with this. Set to null or empty string to disable this and use + /// default color from the configuration file instead. + /// + [DataMember] + public string DefaultColor + { + get; + internal set; + } + + [DataMember] + internal List Flags; + + [DataMember] + internal List Locations = new List(); + + /// + /// Calculate chance that mob will be in room with this ID. + /// + /// Room ID to check mob in. + /// + public double GetChance(uint RoomId) + { + foreach(MobLocation ml in Locations) + { + if(ml.RoomEntry != RoomId) + continue; + + return (ml.CountSeen * 100) / (double)(ml.CountSeen - ml.TimesSeen + ml.TimesVisited); + } + + return 0.0; + } + + /// + /// Calculate room ID with best chance of having mob in it. + /// + /// + public uint GetBestRoom() + { + double b = 0.0; + uint c = uint.MaxValue; + foreach(MobLocation ml in Locations) + { + double a = GetChance(ml.RoomEntry); + if(a > b) + { + b = a; + c = ml.RoomEntry; + } + } + + return c; + } + + /// + /// Add a flag to mob. + /// + /// Flag to add. + public void AddFlag(string f) + { + if(f == null) + return; + f = f.ToLower().Trim(); + if(f.Length == 0) + return; + + if(Flags == null) + Flags = new List(); + if(!Flags.Contains(f)) + Flags.Add(f); + } + + /// + /// Remove a flag from mob. + /// + /// Flag to remove. + /// + public bool RemoveFlag(string f) + { + if(f == null || Flags == null) + return false; + f = f.ToLower().Trim(); + if(f.Length == 0) + return false; + return Flags.Remove(f); + } + + public bool HasFlag(string f) + { + if(f == null) + return false; + f = f.ToLower().Trim(); + if(f.Length == 0) + return false; + return Flags != null && Flags.Contains(f); + } + } +} diff --git a/MobDB/MobDB.cs b/MobDB/MobDB.cs new file mode 100644 index 0000000..5a1889f --- /dev/null +++ b/MobDB/MobDB.cs @@ -0,0 +1,1210 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Runtime.Serialization; +using System.Text; +using ProxyCore; +using ProxyCore.Input; +using ProxyCore.Output; +using ProxyCore.Scripting; + +namespace MobDB +{ + public class MobDB : Plugin + { + public MobDB() + : base("mobdb", "Mob database") + { + Author = "Duckbat"; + Version = 5; + Description = + "You can add mobs to database so we can automatically record their locations and later find them when campaigning."; + UpdateUrl = "www.duckbat.com/plugins/update.mobdb.txt"; + Website = "code.google.com/p/proxymud/"; + + RequiredPlayerConfig.Add("tags roomchars on"); + + Config = new MobDBConfig(); + + RegisterCommand("mobdb", "", CommandMobDB); + RegisterCommand("add", @"(.+)", CommandAdd, 0, CMDFlags.None, "mobdb"); + RegisterCommand("count", "", CommandCount, 0, CMDFlags.None, "mobdb"); + RegisterCommand("delete", @"(.+)", CommandDelete, 0, CMDFlags.None, "mobdb"); + RegisterCommand("find", @"(exact\s+)?(case\s+)?(.+)", CommandFind, 0, CMDFlags.None, "mobdb"); + RegisterCommand("mobinfo", @"^\s*(\d+)?(\s+.+)?", CommandMobInfo, 3, CMDFlags.None, "mobdb"); + RegisterCommand("save", @"(.+)", CommandSave, 0, CMDFlags.None, "mobdb"); + RegisterCommand("where", @"(.+)", CommandWhere, 2, CMDFlags.None, "mobdb"); + + RegisterTrigger("room.id", @"^\$gmcp\.room\.info\.num (-?\d+)$", TriggerRoomInfoNum); + RegisterTrigger("room.area", @"^\$gmcp\.room\.info\.zone (.*)$", TriggerRoomInfoArea); + RegisterTrigger("room.chars1", @"^@w\{roomchars\}$", TriggerRoomChars1, TriggerFlags.None, 1500); + RegisterTrigger("room.chars2", @"^@w\{/roomchars\}$", TriggerRoomChars2, TriggerFlags.None, 500); + RegisterTrigger("room.chars3", @"(.*)", TriggerRoomChars3); + RegisterTrigger("lastkills1", "@WName Level Exp From", TriggerLastKills, + TriggerFlags.NotRegex); + RegisterTrigger("lastkills2", @"^@w(.{30})\s+(\d+)\s+\d+\s+(.+)", TriggerLastKills2); + + Load(); + } + + private string AddMobName; + private int AddMobLevel; + private string AddMobKeywords; + private string AddMobArea; + + private uint CurrentTime; + private uint RoomInfoEntry = uint.MaxValue; + private string RoomInfoArea; + private const string DBFileName = "mobdb.xml"; + private const string DBFileBackup = "mobdb_backup.xml"; + private readonly Dictionary IMobs = new Dictionary(); + private uint _guidMob = 0; + private long WhenSave = 0; + private readonly List UnknownMobs = new List(); + private bool ListeningRoomChars = false; + private readonly Dictionary overrideColors = new Dictionary(); + private int ChooseFromUnknown = 0; + private readonly Dictionary> RoomLocations = new Dictionary>(); + + /// + /// A collection of all mobs. + /// + public IEnumerable Mobs + { + get + { + return IMobs.Values; + } + } + + /// + /// Normalize mob name. This means first character of name will be made lower case while others are left as is. + /// + /// Name of mob. + /// + public static string NormalizeName(string mobName) + { + if(mobName == null) + return string.Empty; + + if(mobName.Length > 0) + mobName = mobName.Substring(0, 1).ToLower() + mobName.Substring(1); + return mobName; + } + + /// + /// Override mob colors when replacing with our longname. + /// + /// Mob ID. + /// Color code, for example "@M" + public void SetMobColor(uint Entry, string colorCode) + { + if(string.IsNullOrEmpty(colorCode)) + overrideColors.Remove(Entry); + else + overrideColors[Entry] = colorCode; + } + + /// + /// Clear all overridden mob colors. + /// + public void ClearMobColors() + { + overrideColors.Clear(); + } + + /// + /// Get mob by ID. + /// + /// ID of mob. + /// + public Mob GetMob(uint Id) + { + return IMobs.ContainsKey(Id) ? IMobs[Id] : null; + } + + private Mob GetMob(ref string t) + { + string orig = t; + t = t.Trim(); + + // Mobs can't be afk + if(t.StartsWith("@w[AFK]")) + { + t = orig; + return null; + } + + StringBuilder str = new StringBuilder(); + + // Unit is wounded + if(t.StartsWith("@R(Wounded)")) + { + t = Colors.RemoveDuplicateColors("@R" + t.Substring("@R(Wounded)".Length)).Trim(); + str.Append("@R(Wounded)"); + } + + if(t.StartsWith("@w(Invis)")) + { + t = Colors.RemoveDuplicateColors("@w" + t.Substring("@w(Invis)".Length)).Trim(); + str.Append("@w(Invis) "); + } + else if(t.StartsWith("@w(I)")) + { + t = Colors.RemoveDuplicateColors("@w" + t.Substring("@w(I)".Length)).Trim(); + str.Append("@w(I)"); + } + + if(t.StartsWith("@w(Hidden)")) + { + t = Colors.RemoveDuplicateColors("@w" + t.Substring("@w(Hidden)".Length)).Trim(); + str.Append("@w(Hidden) "); + } + else if(t.StartsWith("@w(H)")) + { + t = Colors.RemoveDuplicateColors("@w" + t.Substring("@w(H)".Length)).Trim(); + str.Append("@w(H)"); + } + + if(t.StartsWith("@W(Translucent)")) + { + t = Colors.RemoveDuplicateColors("@W" + t.Substring("@W(Translucent)".Length)).Trim(); + str.Append("@W(Translucent) "); + } + else if(t.StartsWith("@W(T)")) + { + t = Colors.RemoveDuplicateColors("@W" + t.Substring("@W(T)".Length)).Trim(); + str.Append("@W(T)"); + } + + if(t.StartsWith("@C(Charmed) ")) + { + //t = Colors.RemoveDuplicateColors("@C" + t.Substring("@C(Charmed) ".Length)); + t = orig; + return null; + } + else if(t.StartsWith("@C(C)")) + { + //t = Colors.RemoveDuplicateColors("@C" + t.Substring("@C(C)".Length)); + t = orig; + return null; + } + + if(t.StartsWith("@M(Animated) ")) + { + //t = Colors.RemoveDuplicateColors("@M" + t.Substring("@M(Animated) ".Length)); + t = orig; + return null; + } + else if(t.StartsWith("@M(A)")) + { + //t = Colors.RemoveDuplicateColors("@M" + t.Substring("@M(A)".Length)); + t = orig; + return null; + } + + if(t.StartsWith("@B(Diseased)")) + { + t = Colors.RemoveDuplicateColors("@B" + t.Substring("@B(Diseased)".Length)).Trim(); + str.Append("@B(Diseased) "); + } + else if(t.StartsWith("@B(D)")) + { + t = Colors.RemoveDuplicateColors("@B" + t.Substring("@B(D)".Length)).Trim(); + str.Append("@B(D)"); + } + + if(t.StartsWith("@D(Marked)")) + { + t = Colors.RemoveDuplicateColors("@D" + t.Substring("@D(Marked)".Length)).Trim(); + str.Append("@D(Marked) "); + } + else if(t.StartsWith("@D(X)")) + { + t = Colors.RemoveDuplicateColors("@D" + t.Substring("@D(X)".Length)).Trim(); + str.Append("@D(X)"); + } + + if(t.StartsWith("@r(Red Aura)")) + { + t = Colors.RemoveDuplicateColors("@r" + t.Substring("@r(Red Aura)".Length)).Trim(); + str.Append("@r(Red Aura)"); + } + else if(t.StartsWith("@r(R)")) + { + t = Colors.RemoveDuplicateColors("@r" + t.Substring("@r(R)".Length)).Trim(); + str.Append("@r(R)"); + } + else if(t.StartsWith("@y(Golden Aura)")) + { + t = Colors.RemoveDuplicateColors("@y" + t.Substring("@y(Golden Aura)".Length)).Trim(); + str.Append("@y(Golden Aura) "); + } + else if(t.StartsWith("@y(G)")) + { + t = Colors.RemoveDuplicateColors("@y" + t.Substring("@y(G)".Length)).Trim(); + str.Append("@y(G)"); + } + + if(t.StartsWith("@W(White Aura)")) + { + t = Colors.RemoveDuplicateColors("@W" + t.Substring("@W(White Aura)".Length)).Trim(); + str.Append("@W(White Aura) "); + } + else if(t.StartsWith("@W(W)")) + { + t = Colors.RemoveDuplicateColors("@W" + t.Substring("@W(W)".Length)).Trim(); + str.Append("@W(W)"); + } + + if(t.StartsWith("@R(Angry)")) + { + t = Colors.RemoveDuplicateColors("@R" + t.Substring("@R(Angry)".Length)).Trim(); + str.Append("@R(Angry) "); + } + + if(t.StartsWith("@w(Linkdead)")) + { + t = orig; + return null; + } + + if(t.StartsWith("@R(RAIDER)")) + { + t = orig; + return null; + } + + if(t.StartsWith("@R(TRAITOR)")) + { + t = orig; + return null; + } + + if(t.StartsWith("@G(DEFENDER)")) + { + t = orig; + return null; + } + + if(t.StartsWith("@R(WANTED)")) + { + t = orig; + return null; + } + + if(str.Length != 0 && str[str.Length - 1] != ' ') + str.Append(' '); + str.Append("{MOB}"); + + if(t.EndsWith("[TARGET]")) + { + t = Colors.RemoveDuplicateColors(t.Substring(0, t.LastIndexOf("[TARGET]"))).Trim(); + str.Append(" @R[TARGET]"); + } + + string area = RoomInfoArea.ToLower(); + foreach(KeyValuePair x in IMobs) + { + if(x.Value.Areas == null) + continue; + + if(!x.Value.Areas.Contains("all") && !x.Value.Areas.Contains(RoomInfoArea)) + continue; + + if(x.Value.Longname == t) + { + string n = Config.GetString("Mob.Longname", + "@w[@G$mob.level@w] $mob.color$mob.name @D($mob.keywords)"); + if(string.IsNullOrEmpty(n)) + { + t = orig; + return x.Value; + } + + n = n.Replace("$$", "\nE"); + n = n.Replace("$mob.level", x.Value.Level.ToString()); + n = n.Replace("$mob.keywords", x.Value.Keyword); + if(n.Contains("$mob.name")) + n = n.Replace("$mob.name", x.Value.Names); + n = n.Replace("$mob.color", + overrideColors.ContainsKey(x.Key) + ? overrideColors[x.Key] + : (!string.IsNullOrEmpty(x.Value.DefaultColor) + ? x.Value.DefaultColor + : Config.GetString("Mob.DefaultColor", "@y"))); + n = n.Replace("$mob.longname", x.Value.Longname); + n = n.Replace("$mob.entry", x.Key.ToString()); + n = n.Replace("\nE", "$"); + str.Replace("{MOB}", Colors.RemoveDuplicateColors(n)); + t = str.ToString(); + return x.Value; + } + } + + if(!UnknownMobs.Contains(t)) + UnknownMobs.Add(t); + t = orig; + return null; + } + + public override void OnEnteredCommandBefore(ref string Msg, uint ClientId, int AuthLevel) + { + base.OnEnteredCommandBefore(ref Msg, ClientId, AuthLevel); + + if(ChooseFromUnknown == 2) + { + int i; + if(int.TryParse(Msg, out i) && i >= 1 && i <= UnknownMobs.Count) + { + Msg = null; + i--; + ChooseFromUnknown = 0; + + Mob m = new Mob(++_guidMob); + m.Name = new[] { AddMobName }; + m.Longname = UnknownMobs[i]; + UnknownMobs.RemoveAt(i); + m.Level = AddMobLevel; + m.Keyword = AddMobKeywords; + m.Areas = new[] {AddMobArea}; + IMobs[m.Entry] = m; + + if(RoomInfoEntry != uint.MaxValue) + { + MobLocation ml = new MobLocation(); + ml.CountSeen = 1; + ml.LastVisited = 0; + ml.MobEntry = m.Entry; + ml.RoomEntry = RoomInfoEntry; + ml.TimesSeen = 1; + ml.TimesVisited = 1; + m.Locations.Add(ml); + + if(!RoomLocations.ContainsKey(RoomInfoEntry)) + RoomLocations[RoomInfoEntry] = new List(); + RoomLocations[RoomInfoEntry].Add(ml); + } + + World.Instance.SendMessage("@wAdded a new mob to database '@G" + m.Names + " @w' [@Y" + m.Entry + + "@w] and set location to current room."); + } + } + } + + #region Commands + private bool CommandWhere(InputData i) + { + if(!i.Arguments.Success) + { + World.Instance.SendMessage("@wSyntax: mobdb where ", i.ClientMask); + World.Instance.SendMessage("@wShows up to @W20 @wbest locations for a mob.", i.ClientMask); + World.Instance.SendMessage("", i.ClientMask); + World.Instance.SendMessage(" @wmobdb where ", i.ClientMask); + World.Instance.SendMessage("@wShows up to @W5 @wbest locations for all mobs that match this name in current area.", i.ClientMask); + return true; + } + + uint mobId; + if(uint.TryParse(i.Arguments.Groups[1].Value, out mobId)) + { + Mob m = GetMob(mobId); + if(m == null) + { + World.Instance.SendMessage("@wNo such mob in database (@R" + mobId + "@w).", i.ClientMask); + return true; + } + + if(!ShowLocations(m, 20, i.ClientMask, false)) + World.Instance.SendMessage("@wDon't know where '@G" + m.Names + "@w' [@Y" + m.Entry + "@w] is.", i.ClientMask); + } + else + { + string n = i.Arguments.Groups[1].Value.ToLower(); + bool showed = false; + foreach(KeyValuePair x in IMobs) + { + if(!x.Value.Areas.Contains("all") && !x.Value.Areas.Contains(RoomInfoArea)) + continue; + + bool f = false; + foreach(string z in x.Value.Name) + { + if(!z.ToLower().Contains(n)) + continue; + + f = true; + break; + } + + if(!f) + continue; + + showed = ShowLocations(x.Value, 5, i.ClientMask, showed); + } + + if(!showed) + World.Instance.SendMessage("@wFound no mob locations with that name.", i.ClientMask); + } + + return true; + } + + private bool ShowLocations(Mob m, int count, uint[] cm, bool isMulti) + { + SortedDictionary> bl = new SortedDictionary>(); + foreach(MobLocation ml in m.Locations) + { + double c = m.GetChance(ml.RoomEntry); + if(!bl.ContainsKey(c)) + bl[c] = new List(); + bl[c].Add(ml.RoomEntry); + } + + StringBuilder strRooms = new StringBuilder(); + bool showed = false; + IEnumerable>> x = bl.Reverse(); + foreach(KeyValuePair> y in x) + { + foreach(uint z in y.Value) + { + if(!showed) + { + if(isMulti) + World.Instance.SendMessage("", cm); + World.Instance.SendMessage("@wLocations for '@G" + m.Names + "@w' [@Y" + m.Entry + "@w]:", cm); + showed = true; + } + + World.Instance.SendMessage("@Y" + string.Format("{0,-6}", z) + " @C" + string.Format("{0:0.00}", y.Key) + "%", cm); + if(strRooms.Length > 0) + strRooms.Append(' '); + strRooms.Append(z); + count--; + if(count == 0) + break; + } + + if(count == 0) + break; + } + + if(strRooms.Length > 0) + World.Instance.SendMessage("@wmap goto " + strRooms); + + return showed; + } + + private bool CommandMobDB(InputData i) + { + World.Instance.SendMessage("@wAvailable mob db commands:", i.ClientMask); + World.Instance.SendMessage( + "@Y" + string.Format("{0,-20}", "mobdb add") + " @w- Add a new mob to database.", i.ClientMask); + World.Instance.SendMessage( + "@Y" + string.Format("{0,-20}", "mobdb count") + " @w- Shows how many mobs you have in database.", + i.ClientMask); + World.Instance.SendMessage( + "@Y" + string.Format("{0,-20}", "mobdb delete") + " @w- Delete a mob from database.", i.ClientMask); + World.Instance.SendMessage("@Y" + string.Format("{0,-20}", "mobdb find") + " @w- Find mobs in database.", + i.ClientMask); + World.Instance.SendMessage( + "@Y" + string.Format("{0,-20}", "mobdb mobinfo") + " @w- Show information or edit a mob.", i.ClientMask); + World.Instance.SendMessage( + "@Y" + string.Format("{0,-20}", "mobdb save") + " @w- Save mob database to file.", i.ClientMask); + World.Instance.SendMessage( + "@Y" + string.Format("{0,-20}", "mobdb where") + " @w- Show mob locations.", i.ClientMask); + return true; + } + + private bool CommandAdd(InputData i) + { + string n; + if(!i.Arguments.Success || (n = i.Arguments.Groups[1].Value.Trim()).Length == 0) + { + World.Instance.SendMessage("@wSyntax: mobdb add ", i.ClientMask); + return true; + } + + if(UnknownMobs.Count == 0) + { + World.Instance.SendMessage("@wWe have no mobs with unknown longname in roomlist.", i.ClientMask); + return true; + } + + AddMobKeywords = n; + ChooseFromUnknown = 1; + World.Instance.Execute("lastkills 1", false); + return true; + } + + private bool CommandMobInfo(InputData i) + { + if(!i.Arguments.Success || i.Arguments.Groups[1].Length == 0) + { + World.Instance.SendMessage("@wSyntax: mobdb mobinfo [option] [value]", i.ClientMask); + World.Instance.SendMessage("", i.ClientMask); + World.Instance.SendMessage("@wAvailable options for mob:", i.ClientMask); + World.Instance.SendMessage("@W" + string.Format("{0,-15}", "addflag") + " @w- Add a flag to mob.", + i.ClientMask); + World.Instance.SendMessage( + "@W" + string.Format("{0,-15}", "removeflag") + " @w- Remove a flag from mob.", i.ClientMask); + World.Instance.SendMessage("@W" + string.Format("{0,-15}", "name1") + " @w- Change (short)name of mob.", + i.ClientMask); + World.Instance.SendMessage("@W" + string.Format("{0,-15}", "name2") + " @w- Change second (short)name of mob.", + i.ClientMask); + World.Instance.SendMessage("@W" + string.Format("{0,-15}", "name3") + " @w- Change third (short)name of mob. (This goes all the way up to 999).", + i.ClientMask); + World.Instance.SendMessage( + "@W" + string.Format("{0,-15}", "areas") + + " @w- Set allowed areas for mob. Separate with space, enter all to allow all areas.", i.ClientMask); + World.Instance.SendMessage( + "@W" + string.Format("{0,-15}", "color") + " @w- Change default color of mob name. Enter default as value to set default color from config.", i.ClientMask); + World.Instance.SendMessage( + "@W" + string.Format("{0,-15}", "keywords") + " @w- Change keywords for mob.", i.ClientMask); + World.Instance.SendMessage( + "@W" + string.Format("{0,-15}", "longname") + " @w- Change longname (roomname) of mob.", + i.ClientMask); + World.Instance.SendMessage("@W" + string.Format("{0,-15}", "level") + " @w- Change level of mob.", + i.ClientMask); + World.Instance.SendMessage("@wEnter '@Wclear@w' as a shortname to remove that name from mob.", i.ClientMask); + return true; + } + + uint mobId; + if(!uint.TryParse(i.Arguments.Groups[1].Value, out mobId)) + { + World.Instance.SendMessage("@wInvalid mob ID given (@R" + i.Arguments.Groups[1].Value + "@w).", + i.ClientMask); + return true; + } + + Mob r = GetMob(mobId); + if(r == null) + { + World.Instance.SendMessage("@wNo such mob in database (@R" + mobId + "@w).", i.ClientMask); + return true; + } + + if(i.Arguments.Groups[2].Length != 0) + { + string key, val; + string str = i.Arguments.Groups[2].Value.Trim(); + if(str.Contains(' ')) + { + key = str.Substring(0, str.IndexOf(' ')).ToLower(); + val = str.Substring(key.Length).Trim(); + + switch(key) + { + case "addflag": + r.AddFlag(val); + break; + + case "removeflag": + r.RemoveFlag(val); + break; + + case "name": + if(r.Name.Length == 0) + r.Name = new[] { val }; + else + r.Name[0] = val; + break; + + case "level": + { + int lvl; + if(int.TryParse(val, out lvl)) + r.Level = lvl; + } break; + + case "areas": + { + string[] spl = val.ToLower().Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); + if(spl.Length > 0) + r.Areas = spl; + } break; + + case "keywords": + { + if(val.Length > 0) + r.Keyword = val; + } break; + + case "longname": + { + if(val == "clear") + r.Longname = ""; + else + r.Longname = val; + } break; + + case "color": + { + if(val == "clear" || val == "default" || val == "none") + r.DefaultColor = null; + else if(val.Length > 0) + r.DefaultColor = val; + } break; + } + + if(key.StartsWith("name") && key.Length > 4) + { + key = key.Substring(4); + int nth; + if(int.TryParse(key, out nth) && nth >= 1) + { + nth--; + List Names = r.Name.ToList(); + if(nth >= r.Name.Length) + { + if(val != "clear") + Names.Add(val); + } + else if(val != "clear") + Names[nth] = val; + else + Names.RemoveAt(nth); + + r.Name = Names.ToArray(); + } + } + } + } + + World.Instance.SendMessage("@w+----------------------------------------------------------------------+", + i.ClientMask); + World.Instance.SendMessage("@w| @WEntry @w: @Y" + string.Format("{0,-55}", r.Entry) + "@w|", + i.ClientMask); + int k = 0; + foreach(string z in r.Name) + { + ++k; + string tag = "Name (" + k + ")"; + World.Instance.SendMessage( + "@w| @W" + string.Format("{0,-11}", tag) + " @w: @G" + + string.Format("{0,-55}", !string.IsNullOrEmpty(z) ? z : "Unknown") + "@w|", i.ClientMask); + } + string area = ""; + if(r.Areas != null) + { + foreach(string y in r.Areas) + { + if(area.Length > 0) + area += " "; + area += y; + } + } + World.Instance.SendMessage("@w| @WArea @w: @M" + string.Format("{0,-55}", area) + "@w|", i.ClientMask); + { + StringBuilder strFlags = new StringBuilder(); + if(r.Flags != null) + { + foreach(string x in r.Flags) + { + if(strFlags.Length > 0) + strFlags.Append(", "); + strFlags.Append(x); + } + } + + string[] spl = Utility.WrapColored(strFlags.ToString(), 54, 0); + for(int j = 0; j < spl.Length; j++) + { + if(j == 0) + World.Instance.SendMessage("@w| @WFlags @w: " + string.Format("{0,-55}", spl[j]) + "@w|", + i.ClientMask); + else + World.Instance.SendMessage("@w| : " + string.Format("{0,-55}", spl[j]) + "@w|", + i.ClientMask); + } + } + + World.Instance.SendMessage("@w| @WLongname @w: " + Utility.FormatColoredString(r.Longname, -55) + "@w|", + i.ClientMask); + World.Instance.SendMessage("@w| @WKeywords @w: " + string.Format("{0,-55}", r.Keyword) + "@w|", + i.ClientMask); + World.Instance.SendMessage("@w| @WLevel @w: @Y" + string.Format("{0,-55}", r.Level) + "@w|", + i.ClientMask); + + string defColor = Config.GetString("Mob.DefaultColor", "@y"); + if(string.IsNullOrEmpty(r.DefaultColor)) + defColor += "Default"; + else + defColor = r.DefaultColor + r.DefaultColor.Replace("@", "@@"); + World.Instance.SendMessage("@w| @WColor @w: " + Utility.FormatColoredString(defColor, -55) + "@w|", + i.ClientMask); + + World.Instance.SendMessage("@w+----------------------------------------------------------------------+", + i.ClientMask); + return true; + } + + private bool CommandFind(InputData i) + { + if(!i.Arguments.Success) + { + World.Instance.SendMessage("@wSyntax: mobdb find [exact] [case] ", i.ClientMask); + return true; + } + + string name = i.Arguments.Groups[3].Value; + if(i.Arguments.Groups[2].Length == 0) + name = name.ToLower(); + else if(name.Length >= 1) + name = NormalizeName(name); + + World.Instance.SendMessage("@wSearched for '@W" + name + "@w'.", i.ClientMask); + List Found = new List(); + foreach(KeyValuePair x in IMobs) + { + if(i.Arguments.Groups[1].Length != 0) + { + if(i.Arguments.Groups[2].Length != 0) + { + if(x.Value.Name.Contains(name)) + Found.Add(x.Value); + } + else + { + foreach(string z in x.Value.Name) + { + if(z.ToLower() == name) + { + Found.Add(x.Value); + break; + } + } + } + } + else + { + if(i.Arguments.Groups[2].Length != 0) + { + if(x.Value.Name.Contains(name)) + Found.Add(x.Value); + } + else + { + foreach(string z in x.Value.Name) + { + if(z.ToLower().Contains(name)) + { + Found.Add(x.Value); + break; + } + } + } + } + } + + if(Found.Count != 0) + { + World.Instance.SendMessage("@WEntry Name Area Room", i.ClientMask); + World.Instance.SendMessage("@G====== ============================================= ============ ======", + i.ClientMask); + foreach(Mob x in Found) + { + string area = ""; + if(x.Areas != null) + { + foreach(string y in x.Areas) + { + if(area.Length != 0) + area += " "; + area += y; + } + } + string room = ""; + uint ro = x.GetBestRoom(); + if(ro != uint.MaxValue) + room = ro.ToString(); + World.Instance.SendMessage("@Y" + string.Format("{0,-6}", x.Entry) + " @c" + + string.Format( + "{0,-" + "=============================================".Length + "}", + x.Names) + " @g" + string.Format("{0,-12}", area) + " @Y" + room); + } + } + + World.Instance.SendMessage("@wFound @C" + Found.Count + " @wmob" + (Found.Count != 1 ? "s" : "") + ".", + i.ClientMask); + return true; + } + + private bool CommandDelete(InputData i) + { + if(!i.Arguments.Success) + { + World.Instance.SendMessage("@wSyntax: mobdb delete ", i.ClientMask); + World.Instance.SendMessage(" @wmobdb delete ", i.ClientMask); + World.Instance.SendMessage(" @wmobdb delete locations", i.ClientMask); + World.Instance.SendMessage(" @wmobdb delete all", i.ClientMask); + return true; + } + + if(i.Arguments.Groups[1].Value.ToLower().Trim() == "locations") + { + foreach(KeyValuePair x in IMobs) + { + x.Value.Locations.Clear(); + } + + World.Instance.SendMessage("@wDeleted all mob locations.", i.ClientMask); + return true; + } + + uint id; + if(uint.TryParse(i.Arguments.Groups[1].Value, out id)) + { + if(!IMobs.ContainsKey(id)) + World.Instance.SendMessage("@wNo such mob in database (@R" + id + "@w).", i.ClientMask); + else + { + World.Instance.SendMessage("@wDeleted '@G" + IMobs[id].Names + "@w'.", i.ClientMask); + foreach(MobLocation ml in IMobs[id].Locations) + { + RoomLocations[ml.RoomEntry].Remove(ml); + if(RoomLocations[ml.RoomEntry].Count == 0) + RoomLocations.Remove(ml.RoomEntry); + } + IMobs.Remove(id); + } + } + else + { + string key = i.Arguments.Groups[1].Value.ToLower().Trim(); + bool isConfirm = false; + if(key.Contains(' ')) + { + isConfirm = key.Substring(key.IndexOf(' ') + 1).Trim() == "confirm"; + key = key.Substring(0, key.IndexOf(' ')); + } + + if(key == "all" && !isConfirm) + { + World.Instance.SendMessage("@wAre you sure you wish to delete all mobs? Enter '@Wmobdb delete all confirm@w' to confirm.", i.ClientMask); + return true; + } + + List del = new List(); + foreach(KeyValuePair x in IMobs) + { + if(key == "all" || x.Value.Areas.Contains(key)) + del.Add(x.Key); + } + + foreach(uint x in del) + IMobs.Remove(x); + + World.Instance.SendMessage("@wDeleted @C" + del.Count + " @wmob" + (del.Count != 1 ? "s" : "") + ".", i.ClientMask); + } + return true; + } + + private bool CommandCount(InputData i) + { + int thisArea = 0; + int total = IMobs.Count; + if(!string.IsNullOrEmpty(RoomInfoArea)) + { + foreach(KeyValuePair x in IMobs) + { + if(x.Value.Areas == null || x.Value.Areas.Length == 0) + continue; + if(x.Value.Areas.Contains(RoomInfoArea)) + thisArea++; + } + } + World.Instance.SendMessage("@wYou have added @G" + thisArea + " @wmobs to database in this area.", + i.ClientMask); + World.Instance.SendMessage("@wYou have added @G" + total + " @wmobs to database in all areas.", i.ClientMask); + return true; + } + + private bool CommandSave(InputData i) + { + string fileName = DBFileName; + if(i.Arguments.Success) + fileName = i.Arguments.Groups[0].Value; + + Save(fileName); + World.Instance.SendMessage("@wSaved mob database to '@W" + fileName + "@w'.", i.ClientMask); + return true; + } + + #endregion + + #region Triggers + + private bool TriggerLastKills(TriggerData t) + { + if(ChooseFromUnknown == 1) + ChooseFromUnknown = 2; + return false; + } + + private bool TriggerLastKills2(TriggerData t) + { + if(ChooseFromUnknown == 0) + return false; + + AddMobName = t.Match.Groups[1].Value.Trim(); + if(!int.TryParse(t.Match.Groups[2].Value, out AddMobLevel) || UnknownMobs.Count == 0) + { + ChooseFromUnknown = 0; + return false; + } + AddMobArea = RoomInfoArea; + + int i = 1; + World.Instance.SendMessage("@wSelect mob longname from list (type number):"); + foreach(string x in UnknownMobs) + { + World.Instance.SendMessage("@W" + i + ". " + x); + i++; + } + return false; + } + + private bool TriggerRoomChars1(TriggerData t) + { + foundMobs.Clear(); + UnknownMobs.Clear(); + ListeningRoomChars = true; + if(Config.GetInt32("Tags.Gag", 1) != 0) + t.Msg.AuthMask = 0; + + CurrentTime = (uint)(DateTime.UtcNow - new DateTime(2012, 1, 1)).TotalSeconds; + return false; + } + + private bool TriggerRoomChars2(TriggerData t) + { + ListeningRoomChars = false; + if(Config.GetInt32("Tags.Gag", 1) != 0) + t.Msg.AuthMask = 0; + if(RoomInfoEntry != uint.MaxValue && RoomLocations.ContainsKey(RoomInfoEntry)) + { + foreach(MobLocation x in RoomLocations[RoomInfoEntry]) + { + Mob m = GetMob(x.MobEntry); + if(m != null && CurrentTime - x.LastVisited >= 600) + { + x.TimesVisited++; + if(foundMobs.Contains(m)) + x.TimesSeen++; + x.LastVisited = CurrentTime; + } + } + } + return false; + } + + private List foundMobs = new List(); + private bool TriggerRoomChars3(TriggerData t) + { + if(!ListeningRoomChars) + return false; + + string n = t.Msg.Msg; + Mob m = GetMob(ref n); + t.Msg.Msg = n; + + if(m == null) + return false; + + if(RoomInfoEntry != uint.MaxValue) + { + if(!foundMobs.Contains(m)) + foundMobs.Add(m); + + bool f = false; + foreach(MobLocation x in m.Locations) + { + if(x.RoomEntry != RoomInfoEntry) + continue; + + f = true; + if(CurrentTime - x.LastVisited >= 600) + x.CountSeen++; + break; + } + + if(!f) + { + MobLocation ml = new MobLocation(); + ml.RoomEntry = RoomInfoEntry; + ml.MobEntry = m.Entry; + ml.LastVisited = CurrentTime; + ml.TimesSeen = 0; + ml.TimesVisited = 0; + ml.CountSeen = 1; + m.Locations.Add(ml); + if(!RoomLocations.ContainsKey(RoomInfoEntry)) + RoomLocations[RoomInfoEntry] = new List(); + RoomLocations[RoomInfoEntry].Add(ml); + } + } + return false; + } + + private bool TriggerRoomInfoNum(TriggerData t) + { + if(ChooseFromUnknown != 0) + { + ChooseFromUnknown = 0; + World.Instance.SendMessage("@wChanged room. Mob adding was cancelled."); + } + UnknownMobs.Clear(); + uint i; + if(!uint.TryParse(t.Match.Groups[1].Value, out i)) + { + RoomInfoEntry = uint.MaxValue; + return false; + } + + RoomInfoEntry = i; + return false; + } + + private bool TriggerRoomInfoArea(TriggerData t) + { + RoomInfoArea = t.Match.Groups[1].Value.Trim(); + return false; + } + + #endregion + + #region Saving & Loading + + public override void Shutdown() + { + base.Shutdown(); + + Save(DBFileName); + } + + private void Load() + { + StreamReader f; + try + { + f = new StreamReader(DBFileName); + } + catch + { + // No database exists or we aren't allowed to read it. Make a new database. + return; + } + + Mob[] data; + try + { + DataContractSerializer x = new DataContractSerializer(typeof(Mob[])); + data = x.ReadObject(f.BaseStream) as Mob[]; + } + catch + { + f.Close(); + Log.Error("Failed loading mob database! File corrupted?"); + return; + } + + f.Close(); + + if(data == null) + return; + + foreach(Mob a in data) + { + if(a == null) + continue; + + IMobs[a.Entry] = a; + if(a.Entry > _guidMob && a.Entry != uint.MaxValue) + _guidMob = a.Entry; + + foreach(MobLocation m in a.Locations) + { + if(!RoomLocations.ContainsKey(m.RoomEntry)) + RoomLocations[m.RoomEntry] = new List(); + RoomLocations[m.RoomEntry].Add(m); + } + } + + // Successfully loaded a database. Now make a backup because we have a working copy at the moment. + File.Delete(DBFileBackup); + File.Copy(DBFileName, DBFileBackup); + } + + private void Save(string fileName) + { + if(IMobs.Count == 0) + return; + StreamWriter f = new StreamWriter(fileName, false); + + try + { + DataContractSerializer x = new DataContractSerializer(typeof(Mob[])); + x.WriteObject(f.BaseStream, IMobs.Values.ToArray()); + } + catch(Exception e) + { + f.Close(); + throw e; + } + + f.Close(); + if(Config.GetInt32("AutoSave", 0) != 0) + WhenSave = World.Instance.MSTime + Config.GetInt32("AutoSave", 0) * 1000; + } + + #endregion + + public override void Update(long msTime) + { + base.Update(msTime); + + if(WhenSave == 0 && Config.GetInt32("AutoSave", 0) != 0) + WhenSave = Config.GetInt32("AutoSave", 0) * 1000 + msTime; + else if(WhenSave > 0 && WhenSave <= msTime) + Save(DBFileName); + } + } + + [DataContract] + internal class MobLocation + { + [DataMember] + internal uint MobEntry; + + [DataMember] + internal uint RoomEntry; + + [DataMember] + internal uint TimesSeen; + + [DataMember] + internal uint CountSeen; + + [DataMember] + internal uint TimesVisited; + + [DataMember] + internal uint LastVisited; + } + + public class MobDBConfig : ConfigFile + { + protected override void OnCreated() + { + base.OnCreated(); + + CreateSetting("Mob.DefaultColor", "@y", "Default color for the mob. Color can be changed by other plugins"); + CreateSetting("Mob.Longname", "@w[@G$mob.level@w] $mob.color$mob.name @D($mob.keywords)", "Replace mob room name with this format. Set this to \"\" to disable mob replacing. You can have variables in the name such as:\n$mob.entry - This is the unique ID of mob (our assigned not mud).\n$mob.level - Level of the mob.\n$mob.name - Mob shortname, what appears when you are fighting it.\n$mob.longname - Mob room name.\n$mob.keywords - These are mob keywords.\n$mob.color - This is the color of the mob name. Can be set from other plugins or manually changed.\nEnter $$ to escape the $ character."); + CreateSetting("AutoSave", 0, "Save mob database every X seconds. For example enter 600 to save mob database every 10 minutes. Enter 0 to disable this feature. The database is also saved on shutdown of program. You can also type \"mobdb save\" to manually save the database."); + CreateSetting("Tags.Gag", 1, "Gag {roomchars} tags for clients."); + } + } +} diff --git a/MobDB/MobDB.csproj b/MobDB/MobDB.csproj new file mode 100644 index 0000000..992d9bc --- /dev/null +++ b/MobDB/MobDB.csproj @@ -0,0 +1,94 @@ + + + + Debug + AnyCPU + 9.0.30729 + 2.0 + {8A7FE055-E1B4-4967-9C76-CA46BA854E73} + Library + Properties + MobDB + MobDB + v3.5 + 512 + + + + + 3.5 + publish\ + true + Disk + false + Foreground + 7 + Days + false + false + true + 0 + 1.0.0.%2a + false + false + true + + + true + full + false + ..\..\..\..\Desktop\MushProxy-Build\Plugins\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + ..\..\..\..\Desktop\MushProxy-Build\Plugins\ + TRACE + prompt + 4 + + + + False + ..\ProxyCore\bin\ProxyCore.dll + + + + 3.5 + + + 3.0 + + + 3.5 + + + 3.5 + + + + + + + + + + + + False + .NET Framework 3.5 SP1 + true + + + + + \ No newline at end of file diff --git a/MobDB/Properties/.svn/all-wcprops b/MobDB/Properties/.svn/all-wcprops new file mode 100644 index 0000000..d327cc7 --- /dev/null +++ b/MobDB/Properties/.svn/all-wcprops @@ -0,0 +1,11 @@ +K 25 +svn:wc:ra_dav:version-url +V 39 +/svn/!svn/ver/30/trunk/MobDB/Properties +END +AssemblyInfo.cs +K 25 +svn:wc:ra_dav:version-url +V 55 +/svn/!svn/ver/30/trunk/MobDB/Properties/AssemblyInfo.cs +END diff --git a/MobDB/Properties/.svn/desktop.ini b/MobDB/Properties/.svn/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/MobDB/Properties/.svn/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/MobDB/Properties/.svn/dir-prop-base b/MobDB/Properties/.svn/dir-prop-base new file mode 100644 index 0000000..f1b96ea --- /dev/null +++ b/MobDB/Properties/.svn/dir-prop-base @@ -0,0 +1,5 @@ +K 14 +bugtraq:number +V 4 +true +END diff --git a/MobDB/Properties/.svn/entries b/MobDB/Properties/.svn/entries new file mode 100644 index 0000000..aca64f8 --- /dev/null +++ b/MobDB/Properties/.svn/entries @@ -0,0 +1,62 @@ +10 + +dir +58 +http://proxymud.googlecode.com/svn/trunk/MobDB/Properties +http://proxymud.googlecode.com/svn + + + +2012-01-23T07:49:14.623991Z +30 +default8p@gmail.com +has-props + + + + + + + + + + + + + +8a6e9f07-fe1d-2472-fcf8-0b435762827a + +AssemblyInfo.cs +file + + + + +2016-03-25T22:18:43.020138Z +6b951bead6f1cf41e5815b8ee4489dd6 +2012-01-23T07:49:14.623991Z +30 +default8p@gmail.com + + + + + + + + + + + + + + + + + + + + + +1422 + diff --git a/MobDB/Properties/.svn/prop-base/desktop.ini b/MobDB/Properties/.svn/prop-base/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/MobDB/Properties/.svn/prop-base/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/MobDB/Properties/.svn/props/desktop.ini b/MobDB/Properties/.svn/props/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/MobDB/Properties/.svn/props/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/MobDB/Properties/.svn/text-base/AssemblyInfo.cs.svn-base b/MobDB/Properties/.svn/text-base/AssemblyInfo.cs.svn-base new file mode 100644 index 0000000..302c561 --- /dev/null +++ b/MobDB/Properties/.svn/text-base/AssemblyInfo.cs.svn-base @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("MobDB")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("MobDB")] +[assembly: AssemblyCopyright("Copyright © 2012")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("e96d05a9-e49d-43b6-8730-38cf3415d9b1")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/MobDB/Properties/.svn/text-base/desktop.ini b/MobDB/Properties/.svn/text-base/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/MobDB/Properties/.svn/text-base/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/MobDB/Properties/.svn/tmp/desktop.ini b/MobDB/Properties/.svn/tmp/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/MobDB/Properties/.svn/tmp/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/MobDB/Properties/.svn/tmp/prop-base/desktop.ini b/MobDB/Properties/.svn/tmp/prop-base/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/MobDB/Properties/.svn/tmp/prop-base/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/MobDB/Properties/.svn/tmp/props/desktop.ini b/MobDB/Properties/.svn/tmp/props/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/MobDB/Properties/.svn/tmp/props/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/MobDB/Properties/.svn/tmp/text-base/desktop.ini b/MobDB/Properties/.svn/tmp/text-base/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/MobDB/Properties/.svn/tmp/text-base/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/MobDB/Properties/AssemblyInfo.cs b/MobDB/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..302c561 --- /dev/null +++ b/MobDB/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("MobDB")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("MobDB")] +[assembly: AssemblyCopyright("Copyright © 2012")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("e96d05a9-e49d-43b6-8730-38cf3415d9b1")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/MobDB/Properties/desktop.ini b/MobDB/Properties/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/MobDB/Properties/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/MobDB/desktop.ini b/MobDB/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/MobDB/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/MoonScript/.svn/all-wcprops b/MoonScript/.svn/all-wcprops new file mode 100644 index 0000000..0b9e1cd --- /dev/null +++ b/MoonScript/.svn/all-wcprops @@ -0,0 +1,17 @@ +K 25 +svn:wc:ra_dav:version-url +V 32 +/svn/!svn/ver/2/trunk/MoonScript +END +MoonScript.csproj +K 25 +svn:wc:ra_dav:version-url +V 50 +/svn/!svn/ver/2/trunk/MoonScript/MoonScript.csproj +END +MoonScript.cs +K 25 +svn:wc:ra_dav:version-url +V 46 +/svn/!svn/ver/2/trunk/MoonScript/MoonScript.cs +END diff --git a/MoonScript/.svn/desktop.ini b/MoonScript/.svn/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/MoonScript/.svn/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/MoonScript/.svn/dir-prop-base b/MoonScript/.svn/dir-prop-base new file mode 100644 index 0000000..f1b96ea --- /dev/null +++ b/MoonScript/.svn/dir-prop-base @@ -0,0 +1,5 @@ +K 14 +bugtraq:number +V 4 +true +END diff --git a/MoonScript/.svn/entries b/MoonScript/.svn/entries new file mode 100644 index 0000000..4bfe16f --- /dev/null +++ b/MoonScript/.svn/entries @@ -0,0 +1,99 @@ +10 + +dir +58 +http://proxymud.googlecode.com/svn/trunk/MoonScript +http://proxymud.googlecode.com/svn + + + +2012-01-17T10:55:35.805502Z +2 +default8p@gmail.com +has-props + + + + + + + + + + + + + +8a6e9f07-fe1d-2472-fcf8-0b435762827a + +Properties +dir + +MoonScript.csproj +file + + + + +2016-03-25T22:18:43.236138Z +15b79e5ac554c9750588f19864572afc +2012-01-17T10:55:35.805502Z +2 +default8p@gmail.com + + + + + + + + + + + + + + + + + + + + + +2724 + +MoonScript.cs +file + + + + +2016-03-25T22:18:43.236138Z +392e5e192e1e4d5d03cc0444e5183cd7 +2012-01-17T10:55:35.805502Z +2 +default8p@gmail.com + + + + + + + + + + + + + + + + + + + + + +14037 + diff --git a/MoonScript/.svn/prop-base/desktop.ini b/MoonScript/.svn/prop-base/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/MoonScript/.svn/prop-base/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/MoonScript/.svn/props/desktop.ini b/MoonScript/.svn/props/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/MoonScript/.svn/props/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/MoonScript/.svn/text-base/MoonScript.cs.svn-base b/MoonScript/.svn/text-base/MoonScript.cs.svn-base new file mode 100644 index 0000000..54c6170 --- /dev/null +++ b/MoonScript/.svn/text-base/MoonScript.cs.svn-base @@ -0,0 +1,329 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using ProxyCore.Scripting; +using ProxyCore.Output; +using ProxyCore.Input; +using ProxyCore; + +namespace MoonScript +{ + public class MoonScript : Plugin + { + public MoonScript() : base("moons", "Moon Script") + { + // Set up extra information (optional). + Author = "Duckbat"; + Version = 1; + Description = "Tracks the position of three moons and displays how many ticks are until a moon rises or falls. Also tracks, and if you want, alerts when all three moons are about to rise. You need to have been outside and seen all three moons rise or fall at least once for it to work."; + RequiredPlayerConfig.Add("noweather ON"); // Need this to see the moons. + UpdateUrl = "www.duckbat.com/plugins/update.moons.txt"; + Website = "www.duckbat.com/plugins/index.php?t=moons"; + + // Register some triggers needed for the moon script + RegisterTrigger("whiterise", "@WYou see the white moon rising in the west.", OnSeeMoon, TriggerFlags.NotRegex, 1000, 3); + RegisterTrigger("whitefall", "@WYou notice the white moon falling to the east.", OnSeeMoon, TriggerFlags.NotRegex, 1000, -3); + RegisterTrigger("greyrise", "@[wD]You see the grey moon rising in the east.", OnSeeMoon, TriggerFlags.None, 1000, 2); + RegisterTrigger("greyfall", "@[wD]You notice the grey moon falling to the west.", OnSeeMoon, TriggerFlags.None, 1000, -2); + RegisterTrigger("blackrise", "@BYou see the black moon rising in the east.", OnSeeMoon, TriggerFlags.NotRegex, 1000, 1); + RegisterTrigger("blackfall", "@BYou notice the black moon falling to the west.", OnSeeMoon, TriggerFlags.NotRegex, 1000, -1); + RegisterTrigger("tick", "$gmcp.comm.tick", OnTick, TriggerFlags.NotRegex); + + // Register commands to check on the moons + RegisterCommand("moons", @"^alert\s+(on|off)$", MoonsCommand, 4); + } + + private int AlertMoons = -1; + + /// + /// This command is set up so if you type moons without arguments you will see the status of all moons. + /// If you type argument "alert on" or "alert off" you will change whether the plugin will alert us + /// when three moons are about to rise. + /// + /// + /// + private bool MoonsCommand(InputData i) + { + // If arguments capture was success it means user typed "alert on" or "alert off" + if(i.Arguments.Success) + { + // If length of captured word is 2 then we must have typed "on" and not "off" + if(i.Arguments.Groups[1].Length == 2) + { + AlertMoons = 3; // Change this to any amount you like, you will be alerted this many ticks before moons rise. + World.Instance.SendMessage("@wYou will now be alerted " + AlertMoons + " tick" + (AlertMoons != 1 ? "s" : "") + " before three moons appear.", i.ClientMask); + } + else // Otherwise it's "off" + { + AlertMoons = -1; + World.Instance.SendMessage("@wYou will no longer be alerted of three moons.", i.ClientMask); + } + } + else + { + /* Only send to the client that typed this alias, other's don't need to see it. + * This is what i.ClientMask is here. If it was called from a plugin send to all + * connected clients. */ + World.Instance.SendMessage("@w+-----------------------------+", i.ClientMask); + World.Instance.SendMessage("@w| @gMOONS @w|", i.ClientMask); + World.Instance.SendMessage("@w+-----------------------------+", i.ClientMask); + if(!HasSeenMoon(MoonTypes.Black)) + World.Instance.SendMessage("@w| @cBlack@w: " + string.Format("{0,-21}", "Unknown") + "|", i.ClientMask); + else + { + int j = WhenAreMoonsUp(MoonTypes.Black); + if(j == 0) + { + j = HowLongAreMoonsUp(MoonTypes.Black); + World.Instance.SendMessage("@w| @cBlack@w: @G" + string.Format("{0,-21}", j) + "@w|", i.ClientMask); + } + else + World.Instance.SendMessage("@w| @cBlack@w: @W" + string.Format("{0,-21}", j) + "@w|", i.ClientMask); + } + if(!HasSeenMoon(MoonTypes.Grey)) + World.Instance.SendMessage("@w| @cGrey @w: " + string.Format("{0,-21}", "Unknown") + "|", i.ClientMask); + else + { + int j = WhenAreMoonsUp(MoonTypes.Grey); + if(j == 0) + { + j = HowLongAreMoonsUp(MoonTypes.Grey); + World.Instance.SendMessage("@w| @cGrey @w: @G" + string.Format("{0,-21}", j) + "@w|", i.ClientMask); + } + else + World.Instance.SendMessage("@w| @cGrey @w: @W" + string.Format("{0,-21}", j) + "@w|", i.ClientMask); + } + if(!HasSeenMoon(MoonTypes.White)) + World.Instance.SendMessage("@w| @cWhite@w: " + string.Format("{0,-21}", "Unknown") + "|", i.ClientMask); + else + { + int j = WhenAreMoonsUp(MoonTypes.White); + if(j == 0) + { + j = HowLongAreMoonsUp(MoonTypes.White); + World.Instance.SendMessage("@w| @cWhite@w: @G" + string.Format("{0,-21}", j) + "@w|", i.ClientMask); + } + else + World.Instance.SendMessage("@w| @cWhite@w: @W" + string.Format("{0,-21}", j) + "@w|", i.ClientMask); + } + if(!HasSeenMoon(MoonTypes.Black) || !HasSeenMoon(MoonTypes.Grey) || !HasSeenMoon(MoonTypes.White)) + World.Instance.SendMessage("@w| @cAll @w: " + string.Format("{0,-21}", "Unknown") + "|", i.ClientMask); + else + { + int j = WhenAreMoonsUp(MoonTypes.Black, MoonTypes.Grey, MoonTypes.White); + if(j == 0) + { + j = HowLongAreMoonsUp(MoonTypes.Black, MoonTypes.Grey, MoonTypes.White); + World.Instance.SendMessage("@w| @cAll @w: @G" + string.Format("{0,-21}", j) + "@w|", i.ClientMask); + } + else + { + string k = j + "(" + HowLongAreMoonsUp(MoonTypes.Black, MoonTypes.Grey, MoonTypes.White) + ")"; + World.Instance.SendMessage("@w| @cAll @w: @W" + string.Format("{0,-21}", k) + "@w|", + new[] {i.ClientId}); + } + } + World.Instance.SendMessage("@w+-----------------------------+", i.ClientMask); + if(AlertMoons == -1) + World.Instance.SendMessage("@wUse '@Wmoons alert on@w' to see alert when three moons are about to rise."); + else + World.Instance.SendMessage("@wUse '@Wmoons alert off@w' if you don't want to be notified of three moons."); + } + + return true; + } + + private bool OnSeeMoon(TriggerData t) + { + /* Arg here is what we used to register trigger with, for example if you see whiterise trigger + * I set the argument to be 3 so it will go to case 3: */ + switch(t.Arg) + { + case 3: + MoonTimer[(int)MoonTypes.White] = MoonDuration[(int)MoonTypes.White] - 1; + break; + case -3: + MoonTimer[(int)MoonTypes.White] = 0; + break; + + case 2: + MoonTimer[(int)MoonTypes.Grey] = MoonDuration[(int)MoonTypes.Grey] - 1; + break; + case -2: + MoonTimer[(int)MoonTypes.Grey] = 0; + break; + + case 1: + MoonTimer[(int)MoonTypes.Black] = MoonDuration[(int)MoonTypes.Black] - 1; + break; + case -1: + MoonTimer[(int)MoonTypes.Black] = 0; + break; + } + return false; + } + + /// + /// Full interval of moons (black, grey, white). + /// + private readonly int[] MoonInterval = new[] { 50, 30, 65 }; + + /// + /// Duration of the moons, this is inverted so duration is actually MoonInterval[i] - MoonDuration[i]. + /// + private readonly int[] MoonDuration = new[] { 39, 24, 50 }; + + /// + /// Current tick timers on the moons. -1 means unknown haven't seen moon yet. + /// + private int[] MoonTimer = new[] { -1, -1, -1 }; + + private bool OnTick(TriggerData t) + { + for(int i = 0; i < MoonTimer.Length; i++) + { + // Increase moon timers if we have seen a moon rise or fall. + if(MoonTimer[i] == -1) + continue; + MoonTimer[i]++; + MoonTimer[i] %= MoonInterval[i]; + } + + // See if we must alert users when moons are about to come up. + if(AlertMoons != -1) + { + int i = WhenAreMoonsUp(MoonTypes.Black, MoonTypes.Grey, MoonTypes.White); + if(i == 0) + { + if(!IsMoonUp(MoonTypes.Black, -1) || !IsMoonUp(MoonTypes.Grey, -1) || !IsMoonUp(MoonTypes.White, -1)) + World.Instance.SendMessage("@GMOONS: @wThree moons are now @WUP@w!"); + } + else if(i <= AlertMoons) + { + World.Instance.SendMessage("@GMOONS: @wThree moons will be up in @W" + i + " @wtick" + (i != 1 ? "s" : "") + "."); + } + } + return false; + } + + private void Reset() + { + // Reset moon timers to unknown, this will be called if we lose connection. + MoonTimer = new[] { -1, -1, -1 }; + } + + public override void OnDisconnect() + { + base.OnDisconnect(); + Reset(); + } + + /// + /// Check if moon is up. + /// + /// Moon type to check for. + /// Offset to current tick. For example 0 would check if moon is currently up but 1 would check if moon is up in 1 tick. + /// + public bool IsMoonUp(MoonTypes i, int tickOffset) + { + if(MoonTimer[(int)i] == -1) + return false; + return (MoonTimer[(int)i] + tickOffset) % MoonInterval[(int)i] >= MoonDuration[(int)i] - 1; + } + + /// + /// Check if we have seen a moon rise or fall. + /// + /// Moon type to check for. + /// + public bool HasSeenMoon(MoonTypes i) + { + return MoonTimer[(int)i] != -1; + } + + /// + /// Check in how many ticks are all these moons up. + /// + /// Moons types to check for. Can be more than one or all. + /// + public int WhenAreMoonsUp(params MoonTypes[] args) + { + if(args.Length == 0) + return 0; + + foreach(MoonTypes t in args) + { + if(!HasSeenMoon(t)) + return -1; + } + + int i = 0; + while(true) + { + bool are = true; + for(int j = 0; j < args.Length; j++) + { + if(!IsMoonUp(args[j], i)) + { + are = false; + break; + } + } + + if(!are) + { + i++; + continue; + } + + return i; + } + } + + /// + /// Next time these moons are up how long are they up for (how many ticks). + /// + /// Moons to check for. Can be more than one or all. + /// + public int HowLongAreMoonsUp(params MoonTypes[] args) + { + if(args.Length == 0) + return 0; + + foreach(MoonTypes t in args) + { + if(!HasSeenMoon(t)) + return -1; + } + + int i = WhenAreMoonsUp(args); + int k = 0; + while(true) + { + bool are = true; + for(int j = 0; j < args.Length; j++) + { + if(!IsMoonUp(args[j], i)) + { + are = false; + break; + } + } + + if(!are) + return k; + + k++; + i++; + } + } + } + + public enum MoonTypes + { + Black = 0, + Grey = 1, + White = 2, + } +} diff --git a/MoonScript/.svn/text-base/MoonScript.csproj.svn-base b/MoonScript/.svn/text-base/MoonScript.csproj.svn-base new file mode 100644 index 0000000..9b2b804 --- /dev/null +++ b/MoonScript/.svn/text-base/MoonScript.csproj.svn-base @@ -0,0 +1,63 @@ + + + + Debug + AnyCPU + 9.0.30729 + 2.0 + {884C4C56-29D1-4761-B3B8-3DC2BF19D54C} + Library + Properties + MoonScript + MoonScript + v3.5 + 512 + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + False + ..\ProxyCore\bin\ProxyCore.dll + + + + 3.5 + + + 3.5 + + + 3.5 + + + + + + + + + + + \ No newline at end of file diff --git a/MoonScript/.svn/text-base/desktop.ini b/MoonScript/.svn/text-base/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/MoonScript/.svn/text-base/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/MoonScript/.svn/tmp/desktop.ini b/MoonScript/.svn/tmp/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/MoonScript/.svn/tmp/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/MoonScript/.svn/tmp/prop-base/desktop.ini b/MoonScript/.svn/tmp/prop-base/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/MoonScript/.svn/tmp/prop-base/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/MoonScript/.svn/tmp/props/desktop.ini b/MoonScript/.svn/tmp/props/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/MoonScript/.svn/tmp/props/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/MoonScript/.svn/tmp/text-base/desktop.ini b/MoonScript/.svn/tmp/text-base/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/MoonScript/.svn/tmp/text-base/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/MoonScript/MoonScript.cs b/MoonScript/MoonScript.cs new file mode 100644 index 0000000..54c6170 --- /dev/null +++ b/MoonScript/MoonScript.cs @@ -0,0 +1,329 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using ProxyCore.Scripting; +using ProxyCore.Output; +using ProxyCore.Input; +using ProxyCore; + +namespace MoonScript +{ + public class MoonScript : Plugin + { + public MoonScript() : base("moons", "Moon Script") + { + // Set up extra information (optional). + Author = "Duckbat"; + Version = 1; + Description = "Tracks the position of three moons and displays how many ticks are until a moon rises or falls. Also tracks, and if you want, alerts when all three moons are about to rise. You need to have been outside and seen all three moons rise or fall at least once for it to work."; + RequiredPlayerConfig.Add("noweather ON"); // Need this to see the moons. + UpdateUrl = "www.duckbat.com/plugins/update.moons.txt"; + Website = "www.duckbat.com/plugins/index.php?t=moons"; + + // Register some triggers needed for the moon script + RegisterTrigger("whiterise", "@WYou see the white moon rising in the west.", OnSeeMoon, TriggerFlags.NotRegex, 1000, 3); + RegisterTrigger("whitefall", "@WYou notice the white moon falling to the east.", OnSeeMoon, TriggerFlags.NotRegex, 1000, -3); + RegisterTrigger("greyrise", "@[wD]You see the grey moon rising in the east.", OnSeeMoon, TriggerFlags.None, 1000, 2); + RegisterTrigger("greyfall", "@[wD]You notice the grey moon falling to the west.", OnSeeMoon, TriggerFlags.None, 1000, -2); + RegisterTrigger("blackrise", "@BYou see the black moon rising in the east.", OnSeeMoon, TriggerFlags.NotRegex, 1000, 1); + RegisterTrigger("blackfall", "@BYou notice the black moon falling to the west.", OnSeeMoon, TriggerFlags.NotRegex, 1000, -1); + RegisterTrigger("tick", "$gmcp.comm.tick", OnTick, TriggerFlags.NotRegex); + + // Register commands to check on the moons + RegisterCommand("moons", @"^alert\s+(on|off)$", MoonsCommand, 4); + } + + private int AlertMoons = -1; + + /// + /// This command is set up so if you type moons without arguments you will see the status of all moons. + /// If you type argument "alert on" or "alert off" you will change whether the plugin will alert us + /// when three moons are about to rise. + /// + /// + /// + private bool MoonsCommand(InputData i) + { + // If arguments capture was success it means user typed "alert on" or "alert off" + if(i.Arguments.Success) + { + // If length of captured word is 2 then we must have typed "on" and not "off" + if(i.Arguments.Groups[1].Length == 2) + { + AlertMoons = 3; // Change this to any amount you like, you will be alerted this many ticks before moons rise. + World.Instance.SendMessage("@wYou will now be alerted " + AlertMoons + " tick" + (AlertMoons != 1 ? "s" : "") + " before three moons appear.", i.ClientMask); + } + else // Otherwise it's "off" + { + AlertMoons = -1; + World.Instance.SendMessage("@wYou will no longer be alerted of three moons.", i.ClientMask); + } + } + else + { + /* Only send to the client that typed this alias, other's don't need to see it. + * This is what i.ClientMask is here. If it was called from a plugin send to all + * connected clients. */ + World.Instance.SendMessage("@w+-----------------------------+", i.ClientMask); + World.Instance.SendMessage("@w| @gMOONS @w|", i.ClientMask); + World.Instance.SendMessage("@w+-----------------------------+", i.ClientMask); + if(!HasSeenMoon(MoonTypes.Black)) + World.Instance.SendMessage("@w| @cBlack@w: " + string.Format("{0,-21}", "Unknown") + "|", i.ClientMask); + else + { + int j = WhenAreMoonsUp(MoonTypes.Black); + if(j == 0) + { + j = HowLongAreMoonsUp(MoonTypes.Black); + World.Instance.SendMessage("@w| @cBlack@w: @G" + string.Format("{0,-21}", j) + "@w|", i.ClientMask); + } + else + World.Instance.SendMessage("@w| @cBlack@w: @W" + string.Format("{0,-21}", j) + "@w|", i.ClientMask); + } + if(!HasSeenMoon(MoonTypes.Grey)) + World.Instance.SendMessage("@w| @cGrey @w: " + string.Format("{0,-21}", "Unknown") + "|", i.ClientMask); + else + { + int j = WhenAreMoonsUp(MoonTypes.Grey); + if(j == 0) + { + j = HowLongAreMoonsUp(MoonTypes.Grey); + World.Instance.SendMessage("@w| @cGrey @w: @G" + string.Format("{0,-21}", j) + "@w|", i.ClientMask); + } + else + World.Instance.SendMessage("@w| @cGrey @w: @W" + string.Format("{0,-21}", j) + "@w|", i.ClientMask); + } + if(!HasSeenMoon(MoonTypes.White)) + World.Instance.SendMessage("@w| @cWhite@w: " + string.Format("{0,-21}", "Unknown") + "|", i.ClientMask); + else + { + int j = WhenAreMoonsUp(MoonTypes.White); + if(j == 0) + { + j = HowLongAreMoonsUp(MoonTypes.White); + World.Instance.SendMessage("@w| @cWhite@w: @G" + string.Format("{0,-21}", j) + "@w|", i.ClientMask); + } + else + World.Instance.SendMessage("@w| @cWhite@w: @W" + string.Format("{0,-21}", j) + "@w|", i.ClientMask); + } + if(!HasSeenMoon(MoonTypes.Black) || !HasSeenMoon(MoonTypes.Grey) || !HasSeenMoon(MoonTypes.White)) + World.Instance.SendMessage("@w| @cAll @w: " + string.Format("{0,-21}", "Unknown") + "|", i.ClientMask); + else + { + int j = WhenAreMoonsUp(MoonTypes.Black, MoonTypes.Grey, MoonTypes.White); + if(j == 0) + { + j = HowLongAreMoonsUp(MoonTypes.Black, MoonTypes.Grey, MoonTypes.White); + World.Instance.SendMessage("@w| @cAll @w: @G" + string.Format("{0,-21}", j) + "@w|", i.ClientMask); + } + else + { + string k = j + "(" + HowLongAreMoonsUp(MoonTypes.Black, MoonTypes.Grey, MoonTypes.White) + ")"; + World.Instance.SendMessage("@w| @cAll @w: @W" + string.Format("{0,-21}", k) + "@w|", + new[] {i.ClientId}); + } + } + World.Instance.SendMessage("@w+-----------------------------+", i.ClientMask); + if(AlertMoons == -1) + World.Instance.SendMessage("@wUse '@Wmoons alert on@w' to see alert when three moons are about to rise."); + else + World.Instance.SendMessage("@wUse '@Wmoons alert off@w' if you don't want to be notified of three moons."); + } + + return true; + } + + private bool OnSeeMoon(TriggerData t) + { + /* Arg here is what we used to register trigger with, for example if you see whiterise trigger + * I set the argument to be 3 so it will go to case 3: */ + switch(t.Arg) + { + case 3: + MoonTimer[(int)MoonTypes.White] = MoonDuration[(int)MoonTypes.White] - 1; + break; + case -3: + MoonTimer[(int)MoonTypes.White] = 0; + break; + + case 2: + MoonTimer[(int)MoonTypes.Grey] = MoonDuration[(int)MoonTypes.Grey] - 1; + break; + case -2: + MoonTimer[(int)MoonTypes.Grey] = 0; + break; + + case 1: + MoonTimer[(int)MoonTypes.Black] = MoonDuration[(int)MoonTypes.Black] - 1; + break; + case -1: + MoonTimer[(int)MoonTypes.Black] = 0; + break; + } + return false; + } + + /// + /// Full interval of moons (black, grey, white). + /// + private readonly int[] MoonInterval = new[] { 50, 30, 65 }; + + /// + /// Duration of the moons, this is inverted so duration is actually MoonInterval[i] - MoonDuration[i]. + /// + private readonly int[] MoonDuration = new[] { 39, 24, 50 }; + + /// + /// Current tick timers on the moons. -1 means unknown haven't seen moon yet. + /// + private int[] MoonTimer = new[] { -1, -1, -1 }; + + private bool OnTick(TriggerData t) + { + for(int i = 0; i < MoonTimer.Length; i++) + { + // Increase moon timers if we have seen a moon rise or fall. + if(MoonTimer[i] == -1) + continue; + MoonTimer[i]++; + MoonTimer[i] %= MoonInterval[i]; + } + + // See if we must alert users when moons are about to come up. + if(AlertMoons != -1) + { + int i = WhenAreMoonsUp(MoonTypes.Black, MoonTypes.Grey, MoonTypes.White); + if(i == 0) + { + if(!IsMoonUp(MoonTypes.Black, -1) || !IsMoonUp(MoonTypes.Grey, -1) || !IsMoonUp(MoonTypes.White, -1)) + World.Instance.SendMessage("@GMOONS: @wThree moons are now @WUP@w!"); + } + else if(i <= AlertMoons) + { + World.Instance.SendMessage("@GMOONS: @wThree moons will be up in @W" + i + " @wtick" + (i != 1 ? "s" : "") + "."); + } + } + return false; + } + + private void Reset() + { + // Reset moon timers to unknown, this will be called if we lose connection. + MoonTimer = new[] { -1, -1, -1 }; + } + + public override void OnDisconnect() + { + base.OnDisconnect(); + Reset(); + } + + /// + /// Check if moon is up. + /// + /// Moon type to check for. + /// Offset to current tick. For example 0 would check if moon is currently up but 1 would check if moon is up in 1 tick. + /// + public bool IsMoonUp(MoonTypes i, int tickOffset) + { + if(MoonTimer[(int)i] == -1) + return false; + return (MoonTimer[(int)i] + tickOffset) % MoonInterval[(int)i] >= MoonDuration[(int)i] - 1; + } + + /// + /// Check if we have seen a moon rise or fall. + /// + /// Moon type to check for. + /// + public bool HasSeenMoon(MoonTypes i) + { + return MoonTimer[(int)i] != -1; + } + + /// + /// Check in how many ticks are all these moons up. + /// + /// Moons types to check for. Can be more than one or all. + /// + public int WhenAreMoonsUp(params MoonTypes[] args) + { + if(args.Length == 0) + return 0; + + foreach(MoonTypes t in args) + { + if(!HasSeenMoon(t)) + return -1; + } + + int i = 0; + while(true) + { + bool are = true; + for(int j = 0; j < args.Length; j++) + { + if(!IsMoonUp(args[j], i)) + { + are = false; + break; + } + } + + if(!are) + { + i++; + continue; + } + + return i; + } + } + + /// + /// Next time these moons are up how long are they up for (how many ticks). + /// + /// Moons to check for. Can be more than one or all. + /// + public int HowLongAreMoonsUp(params MoonTypes[] args) + { + if(args.Length == 0) + return 0; + + foreach(MoonTypes t in args) + { + if(!HasSeenMoon(t)) + return -1; + } + + int i = WhenAreMoonsUp(args); + int k = 0; + while(true) + { + bool are = true; + for(int j = 0; j < args.Length; j++) + { + if(!IsMoonUp(args[j], i)) + { + are = false; + break; + } + } + + if(!are) + return k; + + k++; + i++; + } + } + } + + public enum MoonTypes + { + Black = 0, + Grey = 1, + White = 2, + } +} diff --git a/MoonScript/MoonScript.csproj b/MoonScript/MoonScript.csproj new file mode 100644 index 0000000..179a7cb --- /dev/null +++ b/MoonScript/MoonScript.csproj @@ -0,0 +1,90 @@ + + + + Debug + AnyCPU + 9.0.30729 + 2.0 + {884C4C56-29D1-4761-B3B8-3DC2BF19D54C} + Library + Properties + MoonScript + MoonScript + v3.5 + 512 + + + + + 3.5 + publish\ + true + Disk + false + Foreground + 7 + Days + false + false + true + 0 + 1.0.0.%2a + false + false + true + + + true + full + false + ..\..\..\..\Desktop\MushProxy-Build\Plugins\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + ..\..\..\..\Desktop\MushProxy-Build\Plugins\ + TRACE + prompt + 4 + + + + False + ..\ProxyCore\bin\ProxyCore.dll + + + + 3.5 + + + 3.5 + + + 3.5 + + + + + + + + + + + False + .NET Framework 3.5 SP1 + true + + + + + \ No newline at end of file diff --git a/MoonScript/Properties/.svn/all-wcprops b/MoonScript/Properties/.svn/all-wcprops new file mode 100644 index 0000000..03d956d --- /dev/null +++ b/MoonScript/Properties/.svn/all-wcprops @@ -0,0 +1,11 @@ +K 25 +svn:wc:ra_dav:version-url +V 43 +/svn/!svn/ver/2/trunk/MoonScript/Properties +END +AssemblyInfo.cs +K 25 +svn:wc:ra_dav:version-url +V 59 +/svn/!svn/ver/2/trunk/MoonScript/Properties/AssemblyInfo.cs +END diff --git a/MoonScript/Properties/.svn/desktop.ini b/MoonScript/Properties/.svn/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/MoonScript/Properties/.svn/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/MoonScript/Properties/.svn/dir-prop-base b/MoonScript/Properties/.svn/dir-prop-base new file mode 100644 index 0000000..f1b96ea --- /dev/null +++ b/MoonScript/Properties/.svn/dir-prop-base @@ -0,0 +1,5 @@ +K 14 +bugtraq:number +V 4 +true +END diff --git a/MoonScript/Properties/.svn/entries b/MoonScript/Properties/.svn/entries new file mode 100644 index 0000000..b9378e4 --- /dev/null +++ b/MoonScript/Properties/.svn/entries @@ -0,0 +1,62 @@ +10 + +dir +58 +http://proxymud.googlecode.com/svn/trunk/MoonScript/Properties +http://proxymud.googlecode.com/svn + + + +2012-01-17T10:55:35.805502Z +2 +default8p@gmail.com +has-props + + + + + + + + + + + + + +8a6e9f07-fe1d-2472-fcf8-0b435762827a + +AssemblyInfo.cs +file + + + + +2016-03-25T22:18:43.236138Z +a6f52db3a0f64151a4dafb0b208c1c07 +2012-01-17T10:55:35.805502Z +2 +default8p@gmail.com + + + + + + + + + + + + + + + + + + + + + +1432 + diff --git a/MoonScript/Properties/.svn/prop-base/desktop.ini b/MoonScript/Properties/.svn/prop-base/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/MoonScript/Properties/.svn/prop-base/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/MoonScript/Properties/.svn/props/desktop.ini b/MoonScript/Properties/.svn/props/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/MoonScript/Properties/.svn/props/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/MoonScript/Properties/.svn/text-base/AssemblyInfo.cs.svn-base b/MoonScript/Properties/.svn/text-base/AssemblyInfo.cs.svn-base new file mode 100644 index 0000000..2f5ac7f --- /dev/null +++ b/MoonScript/Properties/.svn/text-base/AssemblyInfo.cs.svn-base @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("MoonScript")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("MoonScript")] +[assembly: AssemblyCopyright("Copyright © 2012")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("81ed5fc1-054a-4f5a-af4b-a5fa2aedf490")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/MoonScript/Properties/.svn/text-base/desktop.ini b/MoonScript/Properties/.svn/text-base/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/MoonScript/Properties/.svn/text-base/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/MoonScript/Properties/.svn/tmp/desktop.ini b/MoonScript/Properties/.svn/tmp/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/MoonScript/Properties/.svn/tmp/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/MoonScript/Properties/.svn/tmp/prop-base/desktop.ini b/MoonScript/Properties/.svn/tmp/prop-base/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/MoonScript/Properties/.svn/tmp/prop-base/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/MoonScript/Properties/.svn/tmp/props/desktop.ini b/MoonScript/Properties/.svn/tmp/props/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/MoonScript/Properties/.svn/tmp/props/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/MoonScript/Properties/.svn/tmp/text-base/desktop.ini b/MoonScript/Properties/.svn/tmp/text-base/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/MoonScript/Properties/.svn/tmp/text-base/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/MoonScript/Properties/AssemblyInfo.cs b/MoonScript/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..2f5ac7f --- /dev/null +++ b/MoonScript/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("MoonScript")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("MoonScript")] +[assembly: AssemblyCopyright("Copyright © 2012")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("81ed5fc1-054a-4f5a-af4b-a5fa2aedf490")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/MoonScript/Properties/desktop.ini b/MoonScript/Properties/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/MoonScript/Properties/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/MoonScript/desktop.ini b/MoonScript/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/MoonScript/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/MudLog/.svn/all-wcprops b/MudLog/.svn/all-wcprops new file mode 100644 index 0000000..60aea3e --- /dev/null +++ b/MudLog/.svn/all-wcprops @@ -0,0 +1,17 @@ +K 25 +svn:wc:ra_dav:version-url +V 28 +/svn/!svn/ver/2/trunk/MudLog +END +MudLog.cs +K 25 +svn:wc:ra_dav:version-url +V 38 +/svn/!svn/ver/2/trunk/MudLog/MudLog.cs +END +MudLog.csproj +K 25 +svn:wc:ra_dav:version-url +V 42 +/svn/!svn/ver/2/trunk/MudLog/MudLog.csproj +END diff --git a/MudLog/.svn/desktop.ini b/MudLog/.svn/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/MudLog/.svn/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/MudLog/.svn/dir-prop-base b/MudLog/.svn/dir-prop-base new file mode 100644 index 0000000..f1b96ea --- /dev/null +++ b/MudLog/.svn/dir-prop-base @@ -0,0 +1,5 @@ +K 14 +bugtraq:number +V 4 +true +END diff --git a/MudLog/.svn/entries b/MudLog/.svn/entries new file mode 100644 index 0000000..9ef0dcc --- /dev/null +++ b/MudLog/.svn/entries @@ -0,0 +1,99 @@ +10 + +dir +58 +http://proxymud.googlecode.com/svn/trunk/MudLog +http://proxymud.googlecode.com/svn + + + +2012-01-17T10:55:35.805502Z +2 +default8p@gmail.com +has-props + + + + + + + + + + + + + +8a6e9f07-fe1d-2472-fcf8-0b435762827a + +MudLog.csproj +file + + + + +2016-03-25T22:18:43.144138Z +dd2dd3662a0b51bed88e462b8aa7075a +2012-01-17T10:55:35.805502Z +2 +default8p@gmail.com + + + + + + + + + + + + + + + + + + + + + +2712 + +MudLog.cs +file + + + + +2016-03-25T22:18:43.144138Z +627c80ade0e5117d641835c4f2771f4c +2012-01-17T10:55:35.805502Z +2 +default8p@gmail.com + + + + + + + + + + + + + + + + + + + + + +4320 + +Properties +dir + diff --git a/MudLog/.svn/prop-base/desktop.ini b/MudLog/.svn/prop-base/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/MudLog/.svn/prop-base/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/MudLog/.svn/props/desktop.ini b/MudLog/.svn/props/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/MudLog/.svn/props/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/MudLog/.svn/text-base/MudLog.cs.svn-base b/MudLog/.svn/text-base/MudLog.cs.svn-base new file mode 100644 index 0000000..c0e3fe7 --- /dev/null +++ b/MudLog/.svn/text-base/MudLog.cs.svn-base @@ -0,0 +1,109 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using ProxyCore; +using ProxyCore.Scripting; + +namespace MudLog +{ + public class MudLog : Plugin + { + public MudLog() + : base("mudlog", "MUD Logger") + { + Author = "Duckbat"; + Version = 1; + Description = "This plugin will log (write down into a file) all text that comes from MUD so you can later look at it if you like."; + UpdateUrl = "www.duckbat.com/plugins/update.mudlog.txt"; + Website = "www.duckbat.com/plugins/index.php?t=mudlog"; + + Config = new MudLogConfig(); + } + + private StreamWriter f; + + public override void OnLoadedConfig(bool Success) + { + base.OnLoadedConfig(Success); + + if(Config.GetInt32("Log.Enabled", 1) != 0) + { + string fn = Config.GetString("Log.Filename", "log.{year}-{month}-{day}.{hour}-{minute}-{second}.txt"); + fn = fn.Replace("{year}", DateTime.Now.Year.ToString()); + fn = fn.Replace("{month}", DateTime.Now.Month.ToString()); + fn = fn.Replace("{day}", DateTime.Now.Day.ToString()); + fn = fn.Replace("{hour}", DateTime.Now.Hour.ToString()); + fn = fn.Replace("{minute}", DateTime.Now.Minute.ToString()); + fn = fn.Replace("{second}", DateTime.Now.Second.ToString()); + + if(fn.Contains("/")) + fn = fn.Substring(fn.LastIndexOf("/") + 1); + if(fn.Contains("\\")) + fn = fn.Substring(fn.LastIndexOf("\\") + 1); + + if(string.IsNullOrEmpty(fn)) + return; + + if(!Directory.Exists("logs")) + { + try + { + Directory.CreateDirectory("logs"); + } + catch + { + return; + } + } + + f = new StreamWriter("logs/" + fn, true); + } + } + + public override void OnReceivedLineAfter(ProxyCore.Messages.Message Msg) + { + base.OnReceivedLineAfter(Msg); + + if(f != null) + { + string m = Msg.Msg; + if(Config.GetInt32("Log.StripColors", 0) != 0) + m = Colors.RemoveColors(m, false); + f.WriteLine( + string.Format("[" + "{0:D2}" + ":" + "{1:D2}" + ":" + "{2:D2}" + "] ", DateTime.Now.Hour, + DateTime.Now.Minute, DateTime.Now.Second) + m); + } + } + + public override void OnEnteredCommandAfter(ref string Msg, uint ClientId, int AuthLevel) + { + base.OnEnteredCommandAfter(ref Msg, ClientId, AuthLevel); + + if(f != null && Config.GetInt32("Log.Commands", 0) != 0) + f.WriteLine(string.Format("[" + "{0:D2}" + ":" + "{1:D2}" + ":" + "{2:D2}" + "] Sent to MUD: ", DateTime.Now.Hour, DateTime.Now.Minute, DateTime.Now.Second) + Msg); + } + + public override void Shutdown() + { + base.Shutdown(); + + if(f != null) + f.Close(); + } + } + + public class MudLogConfig : ConfigFile + { + protected override void OnCreated() + { + base.OnCreated(); + + CreateSetting("Log.Enabled", 1, "Enable logging of all what happens in MUD to a file."); + CreateSetting("Log.Filename", "log.{year}-{month}-{day}.{hour}-{minute}-{second}.txt", "File name of log. You can use {year}, {month}, {day}, {hour}, {minute}, {second} in the filename. If a log file with this name already exists in logs folder then it will be appended to. Be careful however if the log file gets too big this will become slow so it's highly recommended that you differentiate them by including the timestamp keywords somehow."); + CreateSetting("Log.Commands", 0, "Log commands sent to MUD (not ones that were handled by plugins)."); + CreateSetting("Log.StripColors", 0, "Remove all color codes when logging."); + } + } +} diff --git a/MudLog/.svn/text-base/MudLog.csproj.svn-base b/MudLog/.svn/text-base/MudLog.csproj.svn-base new file mode 100644 index 0000000..54f4d2f --- /dev/null +++ b/MudLog/.svn/text-base/MudLog.csproj.svn-base @@ -0,0 +1,63 @@ + + + + Debug + AnyCPU + 9.0.30729 + 2.0 + {2268C185-E9CC-409D-BE6F-A50ED4B900D7} + Library + Properties + MudLog + MudLog + v3.5 + 512 + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + False + ..\ProxyCore\bin\ProxyCore.dll + + + + 3.5 + + + 3.5 + + + 3.5 + + + + + + + + + + + \ No newline at end of file diff --git a/MudLog/.svn/text-base/desktop.ini b/MudLog/.svn/text-base/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/MudLog/.svn/text-base/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/MudLog/.svn/tmp/desktop.ini b/MudLog/.svn/tmp/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/MudLog/.svn/tmp/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/MudLog/.svn/tmp/prop-base/desktop.ini b/MudLog/.svn/tmp/prop-base/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/MudLog/.svn/tmp/prop-base/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/MudLog/.svn/tmp/props/desktop.ini b/MudLog/.svn/tmp/props/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/MudLog/.svn/tmp/props/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/MudLog/.svn/tmp/text-base/desktop.ini b/MudLog/.svn/tmp/text-base/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/MudLog/.svn/tmp/text-base/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/MudLog/MudLog.cs b/MudLog/MudLog.cs new file mode 100644 index 0000000..c0e3fe7 --- /dev/null +++ b/MudLog/MudLog.cs @@ -0,0 +1,109 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using ProxyCore; +using ProxyCore.Scripting; + +namespace MudLog +{ + public class MudLog : Plugin + { + public MudLog() + : base("mudlog", "MUD Logger") + { + Author = "Duckbat"; + Version = 1; + Description = "This plugin will log (write down into a file) all text that comes from MUD so you can later look at it if you like."; + UpdateUrl = "www.duckbat.com/plugins/update.mudlog.txt"; + Website = "www.duckbat.com/plugins/index.php?t=mudlog"; + + Config = new MudLogConfig(); + } + + private StreamWriter f; + + public override void OnLoadedConfig(bool Success) + { + base.OnLoadedConfig(Success); + + if(Config.GetInt32("Log.Enabled", 1) != 0) + { + string fn = Config.GetString("Log.Filename", "log.{year}-{month}-{day}.{hour}-{minute}-{second}.txt"); + fn = fn.Replace("{year}", DateTime.Now.Year.ToString()); + fn = fn.Replace("{month}", DateTime.Now.Month.ToString()); + fn = fn.Replace("{day}", DateTime.Now.Day.ToString()); + fn = fn.Replace("{hour}", DateTime.Now.Hour.ToString()); + fn = fn.Replace("{minute}", DateTime.Now.Minute.ToString()); + fn = fn.Replace("{second}", DateTime.Now.Second.ToString()); + + if(fn.Contains("/")) + fn = fn.Substring(fn.LastIndexOf("/") + 1); + if(fn.Contains("\\")) + fn = fn.Substring(fn.LastIndexOf("\\") + 1); + + if(string.IsNullOrEmpty(fn)) + return; + + if(!Directory.Exists("logs")) + { + try + { + Directory.CreateDirectory("logs"); + } + catch + { + return; + } + } + + f = new StreamWriter("logs/" + fn, true); + } + } + + public override void OnReceivedLineAfter(ProxyCore.Messages.Message Msg) + { + base.OnReceivedLineAfter(Msg); + + if(f != null) + { + string m = Msg.Msg; + if(Config.GetInt32("Log.StripColors", 0) != 0) + m = Colors.RemoveColors(m, false); + f.WriteLine( + string.Format("[" + "{0:D2}" + ":" + "{1:D2}" + ":" + "{2:D2}" + "] ", DateTime.Now.Hour, + DateTime.Now.Minute, DateTime.Now.Second) + m); + } + } + + public override void OnEnteredCommandAfter(ref string Msg, uint ClientId, int AuthLevel) + { + base.OnEnteredCommandAfter(ref Msg, ClientId, AuthLevel); + + if(f != null && Config.GetInt32("Log.Commands", 0) != 0) + f.WriteLine(string.Format("[" + "{0:D2}" + ":" + "{1:D2}" + ":" + "{2:D2}" + "] Sent to MUD: ", DateTime.Now.Hour, DateTime.Now.Minute, DateTime.Now.Second) + Msg); + } + + public override void Shutdown() + { + base.Shutdown(); + + if(f != null) + f.Close(); + } + } + + public class MudLogConfig : ConfigFile + { + protected override void OnCreated() + { + base.OnCreated(); + + CreateSetting("Log.Enabled", 1, "Enable logging of all what happens in MUD to a file."); + CreateSetting("Log.Filename", "log.{year}-{month}-{day}.{hour}-{minute}-{second}.txt", "File name of log. You can use {year}, {month}, {day}, {hour}, {minute}, {second} in the filename. If a log file with this name already exists in logs folder then it will be appended to. Be careful however if the log file gets too big this will become slow so it's highly recommended that you differentiate them by including the timestamp keywords somehow."); + CreateSetting("Log.Commands", 0, "Log commands sent to MUD (not ones that were handled by plugins)."); + CreateSetting("Log.StripColors", 0, "Remove all color codes when logging."); + } + } +} diff --git a/MudLog/MudLog.csproj b/MudLog/MudLog.csproj new file mode 100644 index 0000000..349f644 --- /dev/null +++ b/MudLog/MudLog.csproj @@ -0,0 +1,90 @@ + + + + Debug + AnyCPU + 9.0.30729 + 2.0 + {2268C185-E9CC-409D-BE6F-A50ED4B900D7} + Library + Properties + MudLog + MudLog + v3.5 + 512 + + + + + 3.5 + publish\ + true + Disk + false + Foreground + 7 + Days + false + false + true + 0 + 1.0.0.%2a + false + false + true + + + true + full + false + ..\..\..\..\Desktop\MushProxy-Build\Plugins\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + ..\..\..\..\Desktop\MushProxy-Build\Plugins\ + TRACE + prompt + 4 + + + + False + ..\ProxyCore\bin\ProxyCore.dll + + + + 3.5 + + + 3.5 + + + 3.5 + + + + + + + + + + + False + .NET Framework 3.5 SP1 + true + + + + + \ No newline at end of file diff --git a/MudLog/Properties/.svn/all-wcprops b/MudLog/Properties/.svn/all-wcprops new file mode 100644 index 0000000..08d8b1b --- /dev/null +++ b/MudLog/Properties/.svn/all-wcprops @@ -0,0 +1,11 @@ +K 25 +svn:wc:ra_dav:version-url +V 39 +/svn/!svn/ver/2/trunk/MudLog/Properties +END +AssemblyInfo.cs +K 25 +svn:wc:ra_dav:version-url +V 55 +/svn/!svn/ver/2/trunk/MudLog/Properties/AssemblyInfo.cs +END diff --git a/MudLog/Properties/.svn/desktop.ini b/MudLog/Properties/.svn/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/MudLog/Properties/.svn/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/MudLog/Properties/.svn/dir-prop-base b/MudLog/Properties/.svn/dir-prop-base new file mode 100644 index 0000000..f1b96ea --- /dev/null +++ b/MudLog/Properties/.svn/dir-prop-base @@ -0,0 +1,5 @@ +K 14 +bugtraq:number +V 4 +true +END diff --git a/MudLog/Properties/.svn/entries b/MudLog/Properties/.svn/entries new file mode 100644 index 0000000..a8a6d7c --- /dev/null +++ b/MudLog/Properties/.svn/entries @@ -0,0 +1,62 @@ +10 + +dir +58 +http://proxymud.googlecode.com/svn/trunk/MudLog/Properties +http://proxymud.googlecode.com/svn + + + +2012-01-17T10:55:35.805502Z +2 +default8p@gmail.com +has-props + + + + + + + + + + + + + +8a6e9f07-fe1d-2472-fcf8-0b435762827a + +AssemblyInfo.cs +file + + + + +2016-03-25T22:18:43.140138Z +3984ebfff866f267b9fe8cf07db1cdaf +2012-01-17T10:55:35.805502Z +2 +default8p@gmail.com + + + + + + + + + + + + + + + + + + + + + +1424 + diff --git a/MudLog/Properties/.svn/prop-base/desktop.ini b/MudLog/Properties/.svn/prop-base/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/MudLog/Properties/.svn/prop-base/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/MudLog/Properties/.svn/props/desktop.ini b/MudLog/Properties/.svn/props/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/MudLog/Properties/.svn/props/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/MudLog/Properties/.svn/text-base/AssemblyInfo.cs.svn-base b/MudLog/Properties/.svn/text-base/AssemblyInfo.cs.svn-base new file mode 100644 index 0000000..09be98f --- /dev/null +++ b/MudLog/Properties/.svn/text-base/AssemblyInfo.cs.svn-base @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("MudLog")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("MudLog")] +[assembly: AssemblyCopyright("Copyright © 2012")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("b19209a5-d989-44b1-8bab-6a9b87fb9477")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/MudLog/Properties/.svn/text-base/desktop.ini b/MudLog/Properties/.svn/text-base/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/MudLog/Properties/.svn/text-base/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/MudLog/Properties/.svn/tmp/desktop.ini b/MudLog/Properties/.svn/tmp/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/MudLog/Properties/.svn/tmp/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/MudLog/Properties/.svn/tmp/prop-base/desktop.ini b/MudLog/Properties/.svn/tmp/prop-base/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/MudLog/Properties/.svn/tmp/prop-base/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/MudLog/Properties/.svn/tmp/props/desktop.ini b/MudLog/Properties/.svn/tmp/props/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/MudLog/Properties/.svn/tmp/props/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/MudLog/Properties/.svn/tmp/text-base/desktop.ini b/MudLog/Properties/.svn/tmp/text-base/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/MudLog/Properties/.svn/tmp/text-base/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/MudLog/Properties/AssemblyInfo.cs b/MudLog/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..09be98f --- /dev/null +++ b/MudLog/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("MudLog")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("MudLog")] +[assembly: AssemblyCopyright("Copyright © 2012")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("b19209a5-d989-44b1-8bab-6a9b87fb9477")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/MudLog/Properties/desktop.ini b/MudLog/Properties/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/MudLog/Properties/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/MudLog/desktop.ini b/MudLog/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/MudLog/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/MySQL/.svn/all-wcprops b/MySQL/.svn/all-wcprops new file mode 100644 index 0000000..3264365 --- /dev/null +++ b/MySQL/.svn/all-wcprops @@ -0,0 +1,29 @@ +K 25 +svn:wc:ra_dav:version-url +V 28 +/svn/!svn/ver/58/trunk/MySQL +END +MySQL.csproj +K 25 +svn:wc:ra_dav:version-url +V 41 +/svn/!svn/ver/58/trunk/MySQL/MySQL.csproj +END +MySql.Data.dll +K 25 +svn:wc:ra_dav:version-url +V 43 +/svn/!svn/ver/58/trunk/MySQL/MySql.Data.dll +END +MySQL.cs +K 25 +svn:wc:ra_dav:version-url +V 37 +/svn/!svn/ver/58/trunk/MySQL/MySQL.cs +END +MySql.Data.Entity.dll +K 25 +svn:wc:ra_dav:version-url +V 50 +/svn/!svn/ver/58/trunk/MySQL/MySql.Data.Entity.dll +END diff --git a/MySQL/.svn/desktop.ini b/MySQL/.svn/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/MySQL/.svn/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/MySQL/.svn/dir-prop-base b/MySQL/.svn/dir-prop-base new file mode 100644 index 0000000..f1b96ea --- /dev/null +++ b/MySQL/.svn/dir-prop-base @@ -0,0 +1,5 @@ +K 14 +bugtraq:number +V 4 +true +END diff --git a/MySQL/.svn/entries b/MySQL/.svn/entries new file mode 100644 index 0000000..e1ed965 --- /dev/null +++ b/MySQL/.svn/entries @@ -0,0 +1,167 @@ +10 + +dir +58 +http://proxymud.googlecode.com/svn/trunk/MySQL +http://proxymud.googlecode.com/svn + + + +2012-03-20T06:14:18.138919Z +58 +default8p@gmail.com +has-props + + + + + + + + + + + + + +8a6e9f07-fe1d-2472-fcf8-0b435762827a + +MySQL.csproj +file + + + + +2016-03-25T22:18:43.104138Z +95d3f202c08dba38194188c3fed82ee3 +2012-03-20T06:14:18.138919Z +58 +default8p@gmail.com + + + + + + + + + + + + + + + + + + + + + +2953 + +MySql.Data.dll +file + + + + +2016-03-25T22:18:43.104138Z +43336eb748b73004368a48ac4ddbfc98 +2012-03-20T06:14:18.138919Z +58 +default8p@gmail.com +has-props + + + + + + + + + + + + + + + + + + + + +369152 + +MySQL.cs +file + + + + +2016-03-25T22:18:43.104138Z +000f2d6f6d34d645af2addb73131cb0f +2012-03-20T06:14:18.138919Z +58 +default8p@gmail.com + + + + + + + + + + + + + + + + + + + + + +13683 + +Properties +dir + +MySql.Data.Entity.dll +file + + + + +2016-03-25T22:18:43.104138Z +b61604e25e4c9a96f362782071fd2f3e +2012-03-20T06:14:18.138919Z +58 +default8p@gmail.com +has-props + + + + + + + + + + + + + + + + + + + + +229888 + diff --git a/MySQL/.svn/prop-base/MySql.Data.Entity.dll.svn-base b/MySQL/.svn/prop-base/MySql.Data.Entity.dll.svn-base new file mode 100644 index 0000000..5e9587e --- /dev/null +++ b/MySQL/.svn/prop-base/MySql.Data.Entity.dll.svn-base @@ -0,0 +1,5 @@ +K 13 +svn:mime-type +V 24 +application/octet-stream +END diff --git a/MySQL/.svn/prop-base/MySql.Data.dll.svn-base b/MySQL/.svn/prop-base/MySql.Data.dll.svn-base new file mode 100644 index 0000000..5e9587e --- /dev/null +++ b/MySQL/.svn/prop-base/MySql.Data.dll.svn-base @@ -0,0 +1,5 @@ +K 13 +svn:mime-type +V 24 +application/octet-stream +END diff --git a/MySQL/.svn/prop-base/desktop.ini b/MySQL/.svn/prop-base/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/MySQL/.svn/prop-base/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/MySQL/.svn/props/desktop.ini b/MySQL/.svn/props/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/MySQL/.svn/props/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/MySQL/.svn/text-base/MySQL.cs.svn-base b/MySQL/.svn/text-base/MySQL.cs.svn-base new file mode 100644 index 0000000..75825f8 --- /dev/null +++ b/MySQL/.svn/text-base/MySQL.cs.svn-base @@ -0,0 +1,450 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using MySql.Data.MySqlClient; +using ProxyCore; +using ProxyCore.Scripting; + +namespace MySQL +{ + public class MySQL : Plugin + { + public MySQL() + : base("mysql", "MySQL Database") + { + Author = "Duckbat"; + Version = 1; + Description = "Provides easy access to MySQL database."; + UpdateUrl = "www.duckbat.com/plugins/update.mysql.txt"; + Website = "code.google.com/p/proxymud/"; + + Config = new MySQLConfig(); + } + + internal static long MSTime; + private Database db; + + private void InitDB() + { + if(db == null) + db = new Database(Config.GetString("MySQL.Host", "localhost"), Config.GetString("MySQL.User", "root"), Config.GetString("MySQL.Pass", "pass"), Config.GetInt32("MySQL.Port", 3306), Config.GetString("MySQL.Database", "aardwolf")); + } + + public override void Shutdown() + { + base.Shutdown(); + + if(db != null) + { + db.CloseAll(); + db = null; + } + } + + public override void Update(long msTime) + { + base.Update(msTime); + + MSTime = msTime; + if(db != null) + db.Update(msTime); + } + + /// + /// Query data from the database. + /// + /// + /// + public QueryData Query(string q) + { + InitDB(); + return db.Query(q); + } + + /// + /// Execute a query in the database. + /// + /// + public void Execute(string q) + { + InitDB(); + db.Execute(q); + } + } + + public class MySQLConfig : ConfigFile + { + protected override void OnCreated() + { + base.OnCreated(); + + CreateSetting("MySQL.Host", "localhost", "Hostname for MySQL connection."); + CreateSetting("MySQL.Port", 3306, "Port for MySQL connection."); + CreateSetting("MySQL.User", "root", "Username for MySQL connection."); + CreateSetting("MySQL.Pass", "pass", "Password for MySQL connection."); + CreateSetting("MySQL.Database", "aardwolf", "Database name for the MySQL connection."); + } + } + + internal class Database + { + internal Database(string Host, string Login, string Password, int Port, string dbName) + { + host = Host; + login = Login; + password = Password; + port = Port; + DBName = dbName; + } + + private readonly string host; + private readonly string login; + private readonly string password; + private readonly int port; + private readonly string DBName; + private Dictionary _con = new Dictionary(); + private MySqlConnection freeConnection = null; + private long freeTimer = 0; + + internal void Update(long msTime) + { + if(freeConnection != null && freeTimer < msTime) + { + freeConnection.Close(); + freeConnection = null; + } + + QueryData idle = null; + foreach(KeyValuePair x in _con) + { + if(x.Key.IsIdle) + { + idle = x.Key; + break; + } + } + + if(idle != null) + _CloseResult(idle); + } + + internal void CloseAll() + { + if(freeConnection != null) + { + freeConnection.Close(); + freeConnection = null; + } + + foreach(KeyValuePair x in _con) + { + x.Key._Close(); + x.Value.Close(); + } + + _con.Clear(); + } + + internal void _CloseResult(QueryData data) + { + data._Close(); + if(!_con.ContainsKey(data)) + return; + + if(freeConnection == null) + freeConnection = _con[data]; + _con.Remove(data); + freeTimer = MySQL.MSTime + 3000; + } + + internal QueryData Query(string q) + { + MySqlConnection con = null; + if(freeConnection == null) + { + string conString = "SERVER=" + host + ";DATABASE=" + DBName + ";UID=" + login + ";PASSWORD=" + password + ";PORT=" + port.ToString() + ";"; + con = new MySqlConnection(conString); + con.Open(); + } + else + { + con = freeConnection; + freeConnection = null; + } + + MySqlCommand cmd = con.CreateCommand(); + cmd.CommandText = q; + MySqlDataReader reader = cmd.ExecuteReader(); + + QueryData m = new QueryData(reader, this); + _con[m] = con; + return m; + } + + internal void Execute(string q) + { + MySqlConnection con = null; + if(freeConnection == null) + { + string conString = "SERVER=" + host + ";DATABASE=" + DBName + ";UID=" + login + ";PASSWORD=" + password + ";PORT=" + port.ToString() + ";"; + con = new MySqlConnection(conString); + con.Open(); + } + else + con = freeConnection; + + MySqlCommand cmd = con.CreateCommand(); + cmd.CommandText = q; + cmd.ExecuteNonQuery(); + if(freeConnection == null) + freeConnection = con; + else if(freeConnection != con) + con.Close(); + + freeTimer = MySQL.MSTime + 3000; + } + } + + public class QueryData + { + internal QueryData(MySqlDataReader res, Database connection) + { + r = res; + db = connection; + lastUpdate = MySQL.MSTime; + } + + internal readonly MySqlDataReader r; + internal readonly Database db; + + private long lastUpdate; + + internal bool IsIdle + { + get + { + return MySQL.MSTime - lastUpdate > 5000; + } + } + + /// + /// Close and free the result. + /// + public void Close() + { + db._CloseResult(this); + } + + internal void _Close() + { + if(!r.IsClosed) + r.Close(); + } + + /// + /// Read the next row in the result. If next row exists true will be returned, otherwise false. + /// + /// + public bool Read() + { + lastUpdate = MySQL.MSTime; + return r.Read(); + } + + /// + /// Read a double value in the specified field. Field index starts with 0. + /// + /// + /// + public double GetDouble(int i) + { + lastUpdate = MySQL.MSTime; + if(r.FieldCount > i && !r.IsDBNull(i)) + return r.GetDouble(i); + return 0; + } + + /// + /// Read a float value in the specified field. Field index starts with 0. + /// + /// + /// + public float GetFloat(int i) + { + lastUpdate = MySQL.MSTime; + if(r.FieldCount > i && !r.IsDBNull(i)) + return r.GetFloat(i); + return 0; + } + + /// + /// Read an integer value in the specified field. Field index starts with 0. + /// + /// + /// + public int GetInt32(int i) + { + lastUpdate = MySQL.MSTime; + if(r.FieldCount > i && !r.IsDBNull(i)) + return r.GetInt32(i); + return 0; + } + + /// + /// Read an unsigned integer value in the specified field. Field index starts with 0. + /// + /// + /// + public uint GetUInt32(int i) + { + lastUpdate = MySQL.MSTime; + if(r.FieldCount > i && !r.IsDBNull(i)) + return r.GetUInt32(i); + return 0; + } + + /// + /// Read a long value in the specified field. Field index starts with 0. + /// + /// + /// + public long GetInt64(int i) + { + lastUpdate = MySQL.MSTime; + if(r.FieldCount > i && !r.IsDBNull(i)) + return r.GetInt64(i); + return 0; + } + + /// + /// Read an unsigned long value in the specified field. Field index starts with 0. + /// + /// + /// + public ulong GetUInt64(int i) + { + lastUpdate = MySQL.MSTime; + if(r.FieldCount > i && !r.IsDBNull(i)) + return r.GetUInt64(i); + return 0; + } + + /// + /// Read a string value in the specified field. Field index starts with 0. + /// + /// + /// + public string GetString(int i) + { + lastUpdate = MySQL.MSTime; + if(r.FieldCount > i && !r.IsDBNull(i)) + return r.GetString(i); + return null; + } + + /// + /// Read a short value in the specified field. Field index starts with 0. + /// + /// + /// + public short GetInt16(int i) + { + lastUpdate = MySQL.MSTime; + if(r.FieldCount > i && !r.IsDBNull(i)) + return r.GetInt16(i); + return 0; + } + + /// + /// Read an unsigned short value in the specified field. Field index starts with 0. + /// + /// + /// + public ushort GetUInt16(int i) + { + lastUpdate = MySQL.MSTime; + if(r.FieldCount > i && !r.IsDBNull(i)) + return r.GetUInt16(i); + return 0; + } + + /// + /// Read a byte value in the specified field. Field index starts with 0. + /// + /// + /// + public byte GetByte(int i) + { + lastUpdate = MySQL.MSTime; + if(r.FieldCount > i && !r.IsDBNull(i)) + return r.GetByte(i); + return 0; + } + + /// + /// Read a char value in the specified field. Field index starts with 0. + /// + /// + /// + public char GetChar(int i) + { + lastUpdate = MySQL.MSTime; + if(r.FieldCount > i && !r.IsDBNull(i)) + return r.GetChar(i); + return '\0'; + } + + /// + /// Read a boolean value in the specified field. Field index starts with 0. + /// + /// + /// + public bool GetBool(int i) + { + lastUpdate = MySQL.MSTime; + if(r.FieldCount > i && !r.IsDBNull(i)) + return r.GetBoolean(i); + return false; + } + + /// + /// Read a date time value in the specified field. Field index starts with 0. + /// + /// + /// + public DateTime GetDateTime(int i) + { + lastUpdate = MySQL.MSTime; + if(r.FieldCount > i && !r.IsDBNull(i)) + return r.GetDateTime(i); + return DateTime.MinValue; + } + + /// + /// Read a time span value in the specified field. Field index starts with 0. + /// + /// + /// + public TimeSpan GetTimeSpan(int i) + { + lastUpdate = MySQL.MSTime; + if(r.FieldCount > i && !r.IsDBNull(i)) + return r.GetTimeSpan(i); + return TimeSpan.Zero; + } + + /// + /// Read an object value in the specified field. Field index starts with 0. + /// + /// + /// + public object GetValue(int i) + { + lastUpdate = MySQL.MSTime; + if(r.FieldCount > i && !r.IsDBNull(i)) + return r.GetValue(i); + return 0; + } + } +} diff --git a/MySQL/.svn/text-base/MySQL.csproj.svn-base b/MySQL/.svn/text-base/MySQL.csproj.svn-base new file mode 100644 index 0000000..de10ac7 --- /dev/null +++ b/MySQL/.svn/text-base/MySQL.csproj.svn-base @@ -0,0 +1,67 @@ + + + + Debug + AnyCPU + 9.0.30729 + 2.0 + {A0D29A29-FE11-4CB2-B256-B6EDD3B03A85} + Library + Properties + MySQL + MySQL + v3.5 + 512 + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + False + .\MySql.Data.dll + + + False + ..\ProxyCore\bin\ProxyCore.dll + + + + 3.5 + + + 3.5 + + + 3.5 + + + + + + + + + + + \ No newline at end of file diff --git a/MySQL/.svn/text-base/MySql.Data.Entity.dll.svn-base b/MySQL/.svn/text-base/MySql.Data.Entity.dll.svn-base new file mode 100644 index 0000000..c9678e7 Binary files /dev/null and b/MySQL/.svn/text-base/MySql.Data.Entity.dll.svn-base differ diff --git a/MySQL/.svn/text-base/MySql.Data.dll.svn-base b/MySQL/.svn/text-base/MySql.Data.dll.svn-base new file mode 100644 index 0000000..917255b Binary files /dev/null and b/MySQL/.svn/text-base/MySql.Data.dll.svn-base differ diff --git a/MySQL/.svn/text-base/desktop.ini b/MySQL/.svn/text-base/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/MySQL/.svn/text-base/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/MySQL/.svn/tmp/desktop.ini b/MySQL/.svn/tmp/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/MySQL/.svn/tmp/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/MySQL/.svn/tmp/prop-base/desktop.ini b/MySQL/.svn/tmp/prop-base/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/MySQL/.svn/tmp/prop-base/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/MySQL/.svn/tmp/props/desktop.ini b/MySQL/.svn/tmp/props/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/MySQL/.svn/tmp/props/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/MySQL/.svn/tmp/text-base/desktop.ini b/MySQL/.svn/tmp/text-base/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/MySQL/.svn/tmp/text-base/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/MySQL/MySQL.cs b/MySQL/MySQL.cs new file mode 100644 index 0000000..75825f8 --- /dev/null +++ b/MySQL/MySQL.cs @@ -0,0 +1,450 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using MySql.Data.MySqlClient; +using ProxyCore; +using ProxyCore.Scripting; + +namespace MySQL +{ + public class MySQL : Plugin + { + public MySQL() + : base("mysql", "MySQL Database") + { + Author = "Duckbat"; + Version = 1; + Description = "Provides easy access to MySQL database."; + UpdateUrl = "www.duckbat.com/plugins/update.mysql.txt"; + Website = "code.google.com/p/proxymud/"; + + Config = new MySQLConfig(); + } + + internal static long MSTime; + private Database db; + + private void InitDB() + { + if(db == null) + db = new Database(Config.GetString("MySQL.Host", "localhost"), Config.GetString("MySQL.User", "root"), Config.GetString("MySQL.Pass", "pass"), Config.GetInt32("MySQL.Port", 3306), Config.GetString("MySQL.Database", "aardwolf")); + } + + public override void Shutdown() + { + base.Shutdown(); + + if(db != null) + { + db.CloseAll(); + db = null; + } + } + + public override void Update(long msTime) + { + base.Update(msTime); + + MSTime = msTime; + if(db != null) + db.Update(msTime); + } + + /// + /// Query data from the database. + /// + /// + /// + public QueryData Query(string q) + { + InitDB(); + return db.Query(q); + } + + /// + /// Execute a query in the database. + /// + /// + public void Execute(string q) + { + InitDB(); + db.Execute(q); + } + } + + public class MySQLConfig : ConfigFile + { + protected override void OnCreated() + { + base.OnCreated(); + + CreateSetting("MySQL.Host", "localhost", "Hostname for MySQL connection."); + CreateSetting("MySQL.Port", 3306, "Port for MySQL connection."); + CreateSetting("MySQL.User", "root", "Username for MySQL connection."); + CreateSetting("MySQL.Pass", "pass", "Password for MySQL connection."); + CreateSetting("MySQL.Database", "aardwolf", "Database name for the MySQL connection."); + } + } + + internal class Database + { + internal Database(string Host, string Login, string Password, int Port, string dbName) + { + host = Host; + login = Login; + password = Password; + port = Port; + DBName = dbName; + } + + private readonly string host; + private readonly string login; + private readonly string password; + private readonly int port; + private readonly string DBName; + private Dictionary _con = new Dictionary(); + private MySqlConnection freeConnection = null; + private long freeTimer = 0; + + internal void Update(long msTime) + { + if(freeConnection != null && freeTimer < msTime) + { + freeConnection.Close(); + freeConnection = null; + } + + QueryData idle = null; + foreach(KeyValuePair x in _con) + { + if(x.Key.IsIdle) + { + idle = x.Key; + break; + } + } + + if(idle != null) + _CloseResult(idle); + } + + internal void CloseAll() + { + if(freeConnection != null) + { + freeConnection.Close(); + freeConnection = null; + } + + foreach(KeyValuePair x in _con) + { + x.Key._Close(); + x.Value.Close(); + } + + _con.Clear(); + } + + internal void _CloseResult(QueryData data) + { + data._Close(); + if(!_con.ContainsKey(data)) + return; + + if(freeConnection == null) + freeConnection = _con[data]; + _con.Remove(data); + freeTimer = MySQL.MSTime + 3000; + } + + internal QueryData Query(string q) + { + MySqlConnection con = null; + if(freeConnection == null) + { + string conString = "SERVER=" + host + ";DATABASE=" + DBName + ";UID=" + login + ";PASSWORD=" + password + ";PORT=" + port.ToString() + ";"; + con = new MySqlConnection(conString); + con.Open(); + } + else + { + con = freeConnection; + freeConnection = null; + } + + MySqlCommand cmd = con.CreateCommand(); + cmd.CommandText = q; + MySqlDataReader reader = cmd.ExecuteReader(); + + QueryData m = new QueryData(reader, this); + _con[m] = con; + return m; + } + + internal void Execute(string q) + { + MySqlConnection con = null; + if(freeConnection == null) + { + string conString = "SERVER=" + host + ";DATABASE=" + DBName + ";UID=" + login + ";PASSWORD=" + password + ";PORT=" + port.ToString() + ";"; + con = new MySqlConnection(conString); + con.Open(); + } + else + con = freeConnection; + + MySqlCommand cmd = con.CreateCommand(); + cmd.CommandText = q; + cmd.ExecuteNonQuery(); + if(freeConnection == null) + freeConnection = con; + else if(freeConnection != con) + con.Close(); + + freeTimer = MySQL.MSTime + 3000; + } + } + + public class QueryData + { + internal QueryData(MySqlDataReader res, Database connection) + { + r = res; + db = connection; + lastUpdate = MySQL.MSTime; + } + + internal readonly MySqlDataReader r; + internal readonly Database db; + + private long lastUpdate; + + internal bool IsIdle + { + get + { + return MySQL.MSTime - lastUpdate > 5000; + } + } + + /// + /// Close and free the result. + /// + public void Close() + { + db._CloseResult(this); + } + + internal void _Close() + { + if(!r.IsClosed) + r.Close(); + } + + /// + /// Read the next row in the result. If next row exists true will be returned, otherwise false. + /// + /// + public bool Read() + { + lastUpdate = MySQL.MSTime; + return r.Read(); + } + + /// + /// Read a double value in the specified field. Field index starts with 0. + /// + /// + /// + public double GetDouble(int i) + { + lastUpdate = MySQL.MSTime; + if(r.FieldCount > i && !r.IsDBNull(i)) + return r.GetDouble(i); + return 0; + } + + /// + /// Read a float value in the specified field. Field index starts with 0. + /// + /// + /// + public float GetFloat(int i) + { + lastUpdate = MySQL.MSTime; + if(r.FieldCount > i && !r.IsDBNull(i)) + return r.GetFloat(i); + return 0; + } + + /// + /// Read an integer value in the specified field. Field index starts with 0. + /// + /// + /// + public int GetInt32(int i) + { + lastUpdate = MySQL.MSTime; + if(r.FieldCount > i && !r.IsDBNull(i)) + return r.GetInt32(i); + return 0; + } + + /// + /// Read an unsigned integer value in the specified field. Field index starts with 0. + /// + /// + /// + public uint GetUInt32(int i) + { + lastUpdate = MySQL.MSTime; + if(r.FieldCount > i && !r.IsDBNull(i)) + return r.GetUInt32(i); + return 0; + } + + /// + /// Read a long value in the specified field. Field index starts with 0. + /// + /// + /// + public long GetInt64(int i) + { + lastUpdate = MySQL.MSTime; + if(r.FieldCount > i && !r.IsDBNull(i)) + return r.GetInt64(i); + return 0; + } + + /// + /// Read an unsigned long value in the specified field. Field index starts with 0. + /// + /// + /// + public ulong GetUInt64(int i) + { + lastUpdate = MySQL.MSTime; + if(r.FieldCount > i && !r.IsDBNull(i)) + return r.GetUInt64(i); + return 0; + } + + /// + /// Read a string value in the specified field. Field index starts with 0. + /// + /// + /// + public string GetString(int i) + { + lastUpdate = MySQL.MSTime; + if(r.FieldCount > i && !r.IsDBNull(i)) + return r.GetString(i); + return null; + } + + /// + /// Read a short value in the specified field. Field index starts with 0. + /// + /// + /// + public short GetInt16(int i) + { + lastUpdate = MySQL.MSTime; + if(r.FieldCount > i && !r.IsDBNull(i)) + return r.GetInt16(i); + return 0; + } + + /// + /// Read an unsigned short value in the specified field. Field index starts with 0. + /// + /// + /// + public ushort GetUInt16(int i) + { + lastUpdate = MySQL.MSTime; + if(r.FieldCount > i && !r.IsDBNull(i)) + return r.GetUInt16(i); + return 0; + } + + /// + /// Read a byte value in the specified field. Field index starts with 0. + /// + /// + /// + public byte GetByte(int i) + { + lastUpdate = MySQL.MSTime; + if(r.FieldCount > i && !r.IsDBNull(i)) + return r.GetByte(i); + return 0; + } + + /// + /// Read a char value in the specified field. Field index starts with 0. + /// + /// + /// + public char GetChar(int i) + { + lastUpdate = MySQL.MSTime; + if(r.FieldCount > i && !r.IsDBNull(i)) + return r.GetChar(i); + return '\0'; + } + + /// + /// Read a boolean value in the specified field. Field index starts with 0. + /// + /// + /// + public bool GetBool(int i) + { + lastUpdate = MySQL.MSTime; + if(r.FieldCount > i && !r.IsDBNull(i)) + return r.GetBoolean(i); + return false; + } + + /// + /// Read a date time value in the specified field. Field index starts with 0. + /// + /// + /// + public DateTime GetDateTime(int i) + { + lastUpdate = MySQL.MSTime; + if(r.FieldCount > i && !r.IsDBNull(i)) + return r.GetDateTime(i); + return DateTime.MinValue; + } + + /// + /// Read a time span value in the specified field. Field index starts with 0. + /// + /// + /// + public TimeSpan GetTimeSpan(int i) + { + lastUpdate = MySQL.MSTime; + if(r.FieldCount > i && !r.IsDBNull(i)) + return r.GetTimeSpan(i); + return TimeSpan.Zero; + } + + /// + /// Read an object value in the specified field. Field index starts with 0. + /// + /// + /// + public object GetValue(int i) + { + lastUpdate = MySQL.MSTime; + if(r.FieldCount > i && !r.IsDBNull(i)) + return r.GetValue(i); + return 0; + } + } +} diff --git a/MySQL/MySQL.csproj b/MySQL/MySQL.csproj new file mode 100644 index 0000000..2e7e185 --- /dev/null +++ b/MySQL/MySQL.csproj @@ -0,0 +1,94 @@ + + + + Debug + AnyCPU + 9.0.30729 + 2.0 + {A0D29A29-FE11-4CB2-B256-B6EDD3B03A85} + Library + Properties + MySQL + MySQL + v3.5 + 512 + + + + + 3.5 + publish\ + true + Disk + false + Foreground + 7 + Days + false + false + true + 0 + 1.0.0.%2a + false + false + true + + + true + full + false + ..\..\..\..\Desktop\MushProxy-Build\Plugins\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + ..\..\..\..\Desktop\MushProxy-Build\Plugins\ + TRACE + prompt + 4 + + + + False + .\MySql.Data.dll + + + False + ..\ProxyCore\bin\ProxyCore.dll + + + + 3.5 + + + 3.5 + + + 3.5 + + + + + + + + + + + False + .NET Framework 3.5 SP1 + true + + + + + \ No newline at end of file diff --git a/MySQL/MySql.Data.Entity.dll b/MySQL/MySql.Data.Entity.dll new file mode 100644 index 0000000..c9678e7 Binary files /dev/null and b/MySQL/MySql.Data.Entity.dll differ diff --git a/MySQL/MySql.Data.dll b/MySQL/MySql.Data.dll new file mode 100644 index 0000000..917255b Binary files /dev/null and b/MySQL/MySql.Data.dll differ diff --git a/MySQL/Properties/.svn/all-wcprops b/MySQL/Properties/.svn/all-wcprops new file mode 100644 index 0000000..1f69d31 --- /dev/null +++ b/MySQL/Properties/.svn/all-wcprops @@ -0,0 +1,11 @@ +K 25 +svn:wc:ra_dav:version-url +V 39 +/svn/!svn/ver/58/trunk/MySQL/Properties +END +AssemblyInfo.cs +K 25 +svn:wc:ra_dav:version-url +V 55 +/svn/!svn/ver/58/trunk/MySQL/Properties/AssemblyInfo.cs +END diff --git a/MySQL/Properties/.svn/desktop.ini b/MySQL/Properties/.svn/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/MySQL/Properties/.svn/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/MySQL/Properties/.svn/dir-prop-base b/MySQL/Properties/.svn/dir-prop-base new file mode 100644 index 0000000..f1b96ea --- /dev/null +++ b/MySQL/Properties/.svn/dir-prop-base @@ -0,0 +1,5 @@ +K 14 +bugtraq:number +V 4 +true +END diff --git a/MySQL/Properties/.svn/entries b/MySQL/Properties/.svn/entries new file mode 100644 index 0000000..8a336e7 --- /dev/null +++ b/MySQL/Properties/.svn/entries @@ -0,0 +1,62 @@ +10 + +dir +58 +http://proxymud.googlecode.com/svn/trunk/MySQL/Properties +http://proxymud.googlecode.com/svn + + + +2012-03-20T06:14:18.138919Z +58 +default8p@gmail.com +has-props + + + + + + + + + + + + + +8a6e9f07-fe1d-2472-fcf8-0b435762827a + +AssemblyInfo.cs +file + + + + +2016-03-25T22:18:43.104138Z +6cf8190db2360afa92509ac4728ac044 +2012-03-20T06:14:18.138919Z +58 +default8p@gmail.com + + + + + + + + + + + + + + + + + + + + + +1422 + diff --git a/MySQL/Properties/.svn/prop-base/desktop.ini b/MySQL/Properties/.svn/prop-base/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/MySQL/Properties/.svn/prop-base/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/MySQL/Properties/.svn/props/desktop.ini b/MySQL/Properties/.svn/props/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/MySQL/Properties/.svn/props/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/MySQL/Properties/.svn/text-base/AssemblyInfo.cs.svn-base b/MySQL/Properties/.svn/text-base/AssemblyInfo.cs.svn-base new file mode 100644 index 0000000..18ba346 --- /dev/null +++ b/MySQL/Properties/.svn/text-base/AssemblyInfo.cs.svn-base @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("MySQL")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("MySQL")] +[assembly: AssemblyCopyright("Copyright © 2012")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("47e638aa-bba8-476f-a72c-4ca9b57ffae5")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/MySQL/Properties/.svn/text-base/desktop.ini b/MySQL/Properties/.svn/text-base/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/MySQL/Properties/.svn/text-base/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/MySQL/Properties/.svn/tmp/desktop.ini b/MySQL/Properties/.svn/tmp/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/MySQL/Properties/.svn/tmp/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/MySQL/Properties/.svn/tmp/prop-base/desktop.ini b/MySQL/Properties/.svn/tmp/prop-base/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/MySQL/Properties/.svn/tmp/prop-base/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/MySQL/Properties/.svn/tmp/props/desktop.ini b/MySQL/Properties/.svn/tmp/props/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/MySQL/Properties/.svn/tmp/props/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/MySQL/Properties/.svn/tmp/text-base/desktop.ini b/MySQL/Properties/.svn/tmp/text-base/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/MySQL/Properties/.svn/tmp/text-base/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/MySQL/Properties/AssemblyInfo.cs b/MySQL/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..18ba346 --- /dev/null +++ b/MySQL/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("MySQL")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("MySQL")] +[assembly: AssemblyCopyright("Copyright © 2012")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("47e638aa-bba8-476f-a72c-4ca9b57ffae5")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/MySQL/Properties/desktop.ini b/MySQL/Properties/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/MySQL/Properties/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/MySQL/desktop.ini b/MySQL/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/MySQL/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/ProxyCore.dll b/ProxyCore.dll new file mode 100644 index 0000000..77fd4ad Binary files /dev/null and b/ProxyCore.dll differ diff --git a/ProxyCore.xml b/ProxyCore.xml new file mode 100644 index 0000000..e1e6625 --- /dev/null +++ b/ProxyCore.xml @@ -0,0 +1,915 @@ + + + + ProxyCore + + + + + Load a configuration file. + + Configuration name - for example "server". This should be your plugin name. + + + + + Regex pattern used to load a line from config file. + Groups[1]: Name of setting + Groups[3]: Value of setting (including "" if string) + + + + + Save a new configuration file with default values. If there is an existing config file, it will be replaced. + + + + + This will be called to populate config data with default values and descriptions. + + + + + Create a new setting for the file. If setting with this name already exists then skip. + + Setting name. + Default value for setting. Make sure to use type casting if not integer. + Description to write in the file for this setting. + + + + Read a 32 bit integer value from configuration file. + + Name of the option. + Default value if config is missing this option or is invalid. + + + + + Read a 32 bit unsigned integer value from configuration file. + + Name of the option. + Default value if config is missing this option or is invalid. + + + + + Read a 64 bit integer value from configuration file. + + Name of the option. + Default value if config is missing this option or is invalid. + + + + + Read a 64 bit unsigned integer value from configuration file. + + Name of the option. + Default value if config is missing this option or is invalid. + + + + + Read a float value from configuration file. + + Name of the option. + Default value if config is missing this option or is invalid. + + + + + Read a double value from configuration file. + + Name of the option. + Default value if config is missing this option or is invalid. + + + + + Read a string value from configuration file. + + Name of the option. + Default value if config is missing this option or is invalid. + + + + + Did we successfully load the config file? If not then it was probably missing. + + + + + This is what we turn the @ into so we can replace colors and keep the symbol intact + + + + + Check if a char code is ANSI color code. + + Char to check for. + + + + + Convert normal colors to HTML colors. It converts inserting </font> in front of every color too + so you need to have started with some font already. + + Message to convert colors in. + + + + + Get last color code in the string (not including foreground colors). This will return + with the @ sign. + + + + + + + Removes duplicate colors from a string. For example "@r @Y bla@w" would become " @Ybla". + Also XTERM color codes become padded with zero if they are present. + + String to fix colors in. + + + + + This function will turn either ANSI color to our format or vice versa. + + String passed for color changing. + False means we change our format (@x) to ANSI; true means we change ANSI to our format (we don't convert XTERM colors this way though). + Allow replacing xterm colors? If disabled we will replace into closest ANSI. + + + + + Remove dark grey color code from string and replace it with normal grey. + + String to remove dark grey from (replacing it with normal grey). + + + + + This function will Remove all color from the string. + + String where the color is being removed. + True means raw color (ansi); false means our format (@x). + + + + + Get XTerm color code from text in index (index must be at @x or @z, before it). + + Text to get color code from. + Index of @z or @x. + + + + + Get full escape string from string in index. + + Text to search from. + Index in text of @e + Length of the thing behind @e. + + + + + Get XTerm color code from text in index (index must be at the number not before @x or @z like the other function) + + Text to get color code from. + Index of number. + Length of the number. + + + + + Replace XTerm color codes into real XTerm or ANSI values. + + Text to search in. + Replace into XTerm codes or if false then convert to closest regular ANSI. + + + + + Convert XTerm to ansi char (closest match). + + Code to convert. + + + + + Name of your plugin. You must set this or your plugin will not be loaded. + + + + + This is the keyword for your plugin. You must set this or your plugin will not be loaded. + This must be unique. If two or more plugins with the same keyword are found then the plugin + with the highest version number is loaded. + + + + + Register a new trigger. + + Unique identifier for the trigger. + Regex pattern for the trigger. + Function that will be called if this trigger fires. + + + + Register a new trigger. + + Unique identifier for the trigger. + Regex pattern for the trigger. + Function that will be called if this trigger fires. + Options for the trigger. + + + + Register a new trigger. + + Unique identifier for the trigger. + Regex pattern for the trigger. + Function that will be called if this trigger fires. + Options for the trigger. + Lower priority triggers get matched first. + + + + Register a new trigger. + + Unique identifier for the trigger. + Regex pattern for the trigger. + Function that will be called if this trigger fires. + Options for the trigger. + Lower priority triggers get matched first. + Custom argument that will be passed to trigger data. + + + + Unregister a trigger by name. + + Name of the trigger you wish to unregister. + + + + Register a new command or overwrite a previous one. + + Command to register. + Arguments to match (regex pattern). This can be set to null or empty string + if you don't want to capture anything or plan to do so in the function yourself. + Function of command. + + + + Register a new command or overwrite a previous one. + + Command to register. + Arguments to match (regex pattern). This can be set to null or empty string + if you don't want to capture anything or plan to do so in the function yourself. + Function of command. + Minimum length of command typed required to activate. For example if command is "plugins" and this is 6 then "plugin" and "plugins" both activate this command but "plugi" won't. Enter 0 to disable this behaviour. + + + + Register a new command or overwrite a previous one. + + Command to register. + Arguments to match (regex pattern). This can be set to null or empty string + if you don't want to capture anything or plan to do so in the function yourself. + Function of command. + Minimum length of command typed required to activate. For example if command is "plugins" and this is 6 then "plugin" and "plugins" both activate this command but "plugi" won't. Enter 0 to disable this behaviour. + Options for command. + + + + Register a new command or overwrite a previous one. + + Command to register. + Arguments to match (regex pattern). This can be set to null or empty string + if you don't want to capture anything or plan to do so in the function yourself. + Function of command. + Minimum length of command typed required to activate. For example if command is "plugins" and this is 6 then "plugin" and "plugins" both activate this command but "plugi" won't. Enter 0 to disable this behaviour. + Options for command. + Parent command (if you want to create a subcommand). You can enter commands separated with space if it's nested. + + + + Register a new command or overwrite a previous one. + + Command to register. + Arguments to match (regex pattern). This can be set to null or empty string + if you don't want to capture anything or plan to do so in the function yourself. + Function of command. + Minimum length of command typed required to activate. For example if command is "plugins" and this is 6 then "plugin" and "plugins" both activate this command but "plugi" won't. Enter 0 to disable this behaviour. + Options for command. + Parent command (if you want to create a subcommand). You can enter commands separated with space if it's nested. + Custom argument to pass to function handler. This way you can register multiple commands to a same + function handler only differentiating them with this custom argument. + + + + Register a new command or overwrite a previous one. + + Command to register. + Arguments to match (regex pattern). This can be set to null or empty string + if you don't want to capture anything or plan to do so in the function yourself. + Function of command. + Options for command. + Parent command (if you want to create a subcommand). You can enter commands separated with space if it's nested. + Custom argument to pass to function handler. This way you can register multiple commands to a same + function handler only differentiating them with this custom argument. + Mask of allowed auth levels to access this command. Default ulong.MaxValue (meaning all auth levels are allowed). + Enter 3 for example to allow only auth level 1 and 2 to access this command. + Minimum length of command typed required to activate. For example if command is "plugins" and this is 6 then "plugin" and "plugins" both activate this command but "plugi" won't. Enter 0 to disable this behaviour. + + + + Unregister a command. + + Command to unregister. If you want to unregister a nested command + separate commands with a space. + + + + This will be called when character enters the game. Either by log in or reconnect. + + + + + This will be called when we disconnect from Aardwolf. + + + + + This will be called when we connect to Aardwolf. + + + + + This is called when program shuts down. Write any code you need to shut down your plugin. + + + + + This is called on every loop of world update. You can use it as your main loop for + the plugin if you need one. + + Current time since program startup. + + + + This is called when we receive a line from MUD. It is called AFTER triggers are done with it. If + a trigger gagged the line this will not be called. + + + + + + This is called when we receive a line from MUD. It is called BEFORE triggers are done with it. + + + + + + This is called when user enters a command and inputhandler did not handle the command. So it + is called AFTER we check for aliases and commands and we are about to send command to MUD. + + Command that was entered. You can change this in the function. If you set null + then nothing will be sent to MUD. + Client who entered the command. If this is 0 it was executed from a plugin. + Auth level of who entered the command. + + + + This is called when user enters a command. It is called BEFORE we check for aliases and commands. + + Command that was entered. You can change this in the function. If you set null + then nothing will be sent to MUD and nothing will be checked for aliases or commands. + Client who entered the command. If this is 0 it was executed from a plugin. + Auth level of who entered the command. + + + + Enter required player config options here. This will be displayed if user requests info about a plugin. + For example you may enter here "echocommands ON" and "statmon ON" etc. Whatever your plugin requires. + This doesn't actually change the settings in game it is only for plugin info command. + + + + + This is the class name of script. For example moons has this set to "MoonScript.MoonScript". + Only needed by developers who want to use another plugin in their plugin. + + + + + Called when we load a configuration file. + + Did the loading succeed? If not then the config file wasn't present and we created a new one. + + + + Disable all triggers with this priority. Disabling triggers from a plugin will make them not work until + you enable them from the same plugin again. If triggers have been disabled from multiple plugins then + all plugins will have to enable them again until they start working. Disabling triggers will make all + triggers with this priority to not work not only triggers in current plugin! + + Priority of triggers to disable. + + + + Disable all triggers with this priority. Disabling triggers from a plugin will make them not work until + you enable them from the same plugin again. If triggers have been disabled from multiple plugins then + all plugins will have to enable them again until they start working. Disabling triggers will make all + triggers with this priority to not work not only triggers in current plugin! + + Minimum priority of triggers to disable. + Maximum priority of triggers to disable. + + + + Enable all previously disabled triggers with this priority. + + Priority of triggers to enable. + + + + Enable all previously disabled triggers with this priority. + + Minimum priority of triggers to enable. + Maximum priority of triggers to enable. + + + + Set this to be your configuration file if you want your plugin to have one. This is optional. + + + + + Creator of the plugin, this is your name / character's name. This is optional. + + + + + Version of your plugin. This is optional. + + + + + Description about your plugin. You should explain here what it does and how to handle it. + This will be displayed if user requests information about your plugin. This is optional. + + + + + Enter a website for this plugin if you wish. Mostly used to see documentation and updates. + + + + + Enter the URL for update checking txt file. For example "www.duckbat.com/plugins/update.moons.txt". + In the text file enter the number of last version. For example whole contents of the txt file can be "3". + Indicating that the last version for this plugin is 3. If version is greater than user's version and + they have update checking on then they will be notified that there is a more up to date version out there. + + + + + Does this plugin require a certain version of core? Set this if there was an update and your plugin requires it. + Plugin is not loaded if an older version core than this is used and user will be notified. + + + + + Version of Proxy. + + + + + Handle text line as if we received it from Aardwolf. + + + + + + Handle GMCP data that we received from Aardwolf. + + GMCP data received. + + + + This is called from proxy when it shuts down. Do NOT call from a plugin. + + + + + Enter input as if a client entered it. Meaning we parse it. Consider using the Execute command instead. + + Input entered. + Which client is this from? Enter 0 to set not from a client. + Authlevel of client who entered command (1...64) + + + + Send message to specified clients. + + Message to send. + Clients to send it to. Enter null to send to all connected clients. + Enter 0 as client to send it as a command to Aardwolf (we don't parse it though, if you want + parsed input use the Execute command). + + + + Send a message to all connected authorized clients. + + Message to send to all authorized clients. + + + + Send a message to all connected authorized clients. + + Message to send to all authorized clients. + Authorization levels required to see this message. This is a mask. + + + + Execute a command. + + Command to execute. + Allow parsing it for aliases and such, or send it directly to Aardwolf? + + + + Execute a command. + + Command to execute. + Allow parsing it for aliases and such, or send it directly to Aardwolf? + Auth level that executes this command. (1...64) + + + + Send raw bytes to MUD. + + Bytes to send. + + + + Internal command for updating the world. DO NOT CALL FROM A PLUGIN! + + New mstime. + + + + This is messages for networking to handle. Don't touch unless you know what you are doing. + + + + + Check for updates and report to all connected users if there are any. + + Check core update. + Check plugin updates. + Should we report if no updates were found? + + + + Game world instance. + + + + + Milliseconds since program startup. + + + + + Get plugin by keyword. + + Keyword of plugin. + + + + + What we triggered on, you can change this value to replace the text. + + + + + Custom argument if you registered a trigger to have one. + + + + + Replace matched %0 value with new string. This only works in regex triggers. You can have {%1} - {%n} in the new string for matched data. + Use {%%1} to escape. If you use % higher than what was captured then a NULL will be replaced there. + For example using %3 when there are only 2 things captured with regex. + + Example: + Line: "@mQuest Points @w: @Y19,361" + Pattern: "^@mQuest Points @w: (\s*)@Y([\d,]+)$" + Replace: "@mQuest Points @w: {%1}@G{%2}" + This would make quest points green in the "worth" command output. Where {%1} inserts the right amount + of spaces (what was captured) and {%2} inserts the quest points amount (19,361). + + New string to replace with. See function summary for help with this. + Allow parsing {%n} in the New string or not. If not then string + is replaced as is without parsing for arguments. + + + + Match data. + + + + + This is the function template that will be called when a trigger fires. Return true to gag it - this + will also prevent other triggers from triggering on this line. + + Triggered text data. + + + + + Normal triggers stop after finding the first match in a line, + with this flag the trigger repeats for each match in the same line. + This only applies if you use regex pattern. + + + + + Ignore lower and upper case. This only applies if you use regex pattern. + + + + + Pattern is not regex but instead just raw string. For example if you want + to trigger on "@w--> @WTICK @w<--" there's no need to create a regex pattern + just insert this string and set this flag in options and the trigger will be MUCH + faster. Use regex only where necessary. + + + + + Trigger ignores color codes. If you set this flag you should NOT include any color codes + in your trigger pattern. + + + + + Matching will start from right and go to left. + + + + + Register a new trigger. + + Unique identifier for the trigger. + Regex pattern for the trigger. + Function that will be called if this trigger fires. + + + + Register a new trigger. + + Unique identifier for the trigger. + Regex pattern for the trigger. + Function that will be called if this trigger fires. + Options for the trigger. + + + + Register a new trigger. + + Unique identifier for the trigger. + Regex pattern for the trigger. + Function that will be called if this trigger fires. + Options for the trigger. + Lower priority triggers get matched first. Default: 1000 + + + + Register a new trigger. + + Unique identifier for the trigger. + Regex pattern for the trigger. + Function that will be called if this trigger fires. + Options for the trigger. + Lower priority triggers get matched first. Default: 1000 + Custom argument to pass to trigger data. + From which plugin was this registered. + + + + Unregister a trigger by name. + + Name of the trigger you wish to unregister. + + + + Function for handling input. Return true if we handled the command (no need to send to MUD) and false + if we didn't and we must send it to MUD. + + Input data. + + + + + Hidden from normal commands menu. + + + + + Command is currently disabled and will be excluded in the list of valid commands. + + + + + Dummy command, player can't type it but it will be redirected from elsewhere. + + + + + Internal - this will be assigned automatically for commands that have subcommands. + + + + + If this is set ignore message and send this byte data instead. Color codes + will not be parsed by server and this is sent as is. + + + + + This is message but without colors. Used for triggering non-ansi triggers. + + + + + Which clients should receive the message. This is a mask for security levels. + For example value "3" would only send this message to security level 1 and 2. + Set ulong.MaxValue (default) to send to all clients or 0 to send to noone. + This field is ignored when sending message to Aardwolf (as a command). + + + + + This setting is used to send the message to specific clients (using client ID). + Enter new uint[] { 0 } to send to Aardwolf and null to send to all clients (default). + + + + + Is this message natural (client entered command or Aardwolf sent message) or + is it generated by us, meaning Aardwolf did not send this and client did not enter + it as a command. + + + + + What kind of line ending do we send with this message (default \n\r). + + + + + When was message generated (send time may vary by some milliseconds) + + + + + Options for message. + + + + + Contents of the message. + + + + + This is a GMCP message the main module will be in Msg and the data will be in MsgData. + + + + + Register a new command or overwrite a previous one. + + Command to register. + Arguments to match (regex pattern). This can be set to null or empty string + if you don't want to capture anything or plan to do so in the function yourself. + Function of command. + + + + Register a new command or overwrite a previous one. + + Command to register. + Arguments to match (regex pattern). This can be set to null or empty string + if you don't want to capture anything or plan to do so in the function yourself. + Function of command. + Options for command. + + + + Register a new command or overwrite a previous one. + + Command to register. + Arguments to match (regex pattern). This can be set to null or empty string + if you don't want to capture anything or plan to do so in the function yourself. + Function of command. + Options for command. + Parent command (if you want to create a subcommand). You can enter commands separated with space if it's nested. + + + + Register a new command or overwrite a previous one. + + Command to register. + Arguments to match (regex pattern). This can be set to null or empty string + if you don't want to capture anything or plan to do so in the function yourself. + Function of command. + Options for command. + Parent command (if you want to create a subcommand). You can enter commands separated with space if it's nested. + Custom argument to pass to function handler. This way you can register multiple commands to a same + function handler only differentiating them with this custom argument. + + + + Register a new command or overwrite a previous one. + + Command to register. + Arguments to match (regex pattern). This can be set to null or empty string + if you don't want to capture anything or plan to do so in the function yourself. + Function of command. + Options for command. + Parent command (if you want to create a subcommand). You can enter commands separated with space if it's nested. + Custom argument to pass to function handler. This way you can register multiple commands to a same + function handler only differentiating them with this custom argument. + Mask of allowed auth levels to access this command. Default ulong.MaxValue (meaning all auth levels are allowed). + Enter 3 for example to allow only auth level 1 and 2 to access this command. + From which plugin did this come. + Minimum length of command typed required to activate. For example if command is "plugins" and this is 6 then "plugin" and "plugins" both activate this command but "plugi" won't. + + + + Unregister a command. + + Command to unregister. If you want to unregister a nested command + separate commands with a space. + + + + Whole command just as it was entered. You can change this to send something different to MUD. Just make + sure you return false on the command handler otherwise nothing will get sent to MUD. + + + + + Which function will we execute with this data. + + + + + Who executed the command? This will be uint.MaxValue if we execute it from a plugin or other places - meaning + it didn't originate from a client. + + + + + Use this if you want to send message to whoever executed the command. If it was executed from a plugin + send message to every client. Example: World.Instance.SendMessage("Test.", i.ClientMask); + + + + + The auth level of client who entered command. (1...64) + + + + + This is where we capture arguments if the arguments pattern was set. Check first if Arguments.Success, otherwise there will be no Groups set. + + + + + Write this into console window. + + Message to write to console window. + + + + Write an error message to console window and error.log + + + + + + Write a stacktrace when program crashes. + + Trace to write. + + + diff --git a/ProxyCore/.svn/all-wcprops b/ProxyCore/.svn/all-wcprops new file mode 100644 index 0000000..b7e93bb --- /dev/null +++ b/ProxyCore/.svn/all-wcprops @@ -0,0 +1,23 @@ +K 25 +svn:wc:ra_dav:version-url +V 32 +/svn/!svn/ver/57/trunk/ProxyCore +END +Log.cs +K 25 +svn:wc:ra_dav:version-url +V 39 +/svn/!svn/ver/54/trunk/ProxyCore/Log.cs +END +ProxyCore.csproj +K 25 +svn:wc:ra_dav:version-url +V 48 +/svn/!svn/ver/2/trunk/ProxyCore/ProxyCore.csproj +END +World.cs +K 25 +svn:wc:ra_dav:version-url +V 41 +/svn/!svn/ver/57/trunk/ProxyCore/World.cs +END diff --git a/ProxyCore/.svn/desktop.ini b/ProxyCore/.svn/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/ProxyCore/.svn/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/ProxyCore/.svn/dir-prop-base b/ProxyCore/.svn/dir-prop-base new file mode 100644 index 0000000..f1b96ea --- /dev/null +++ b/ProxyCore/.svn/dir-prop-base @@ -0,0 +1,5 @@ +K 14 +bugtraq:number +V 4 +true +END diff --git a/ProxyCore/.svn/entries b/ProxyCore/.svn/entries new file mode 100644 index 0000000..3a6b974 --- /dev/null +++ b/ProxyCore/.svn/entries @@ -0,0 +1,148 @@ +10 + +dir +58 +http://proxymud.googlecode.com/svn/trunk/ProxyCore +http://proxymud.googlecode.com/svn + + + +2012-02-08T08:41:07.654540Z +57 +default8p@gmail.com +has-props + + + + + + + + + + + + + +8a6e9f07-fe1d-2472-fcf8-0b435762827a + +Utility +dir + +Log.cs +file + + + + +2016-03-25T22:18:43.228138Z +45e2f897ae1679bf333ba7bb710a266f +2012-02-02T08:38:33.263906Z +54 +default8p@gmail.com + + + + + + + + + + + + + + + + + + + + + +1981 + +Messages +dir + +ProxyCore.csproj +file + + + + +2016-03-25T22:18:43.228138Z +2c65edfe3f4e32d352f9499841a632b7 +2012-01-17T10:55:35.805502Z +2 +default8p@gmail.com + + + + + + + + + + + + + + + + + + + + + +3693 + +World.cs +file + + + + +2016-03-25T22:18:43.228138Z +4c194ca6a3b32f0eec02d527216faf32 +2012-02-08T08:41:07.654540Z +57 +default8p@gmail.com + + + + + + + + + + + + + + + + + + + + + +24207 + +Properties +dir + +Input +dir + +Output +dir + +Scripting +dir + diff --git a/ProxyCore/.svn/prop-base/desktop.ini b/ProxyCore/.svn/prop-base/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/ProxyCore/.svn/prop-base/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/ProxyCore/.svn/props/desktop.ini b/ProxyCore/.svn/props/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/ProxyCore/.svn/props/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/ProxyCore/.svn/text-base/Log.cs.svn-base b/ProxyCore/.svn/text-base/Log.cs.svn-base new file mode 100644 index 0000000..23382e4 --- /dev/null +++ b/ProxyCore/.svn/text-base/Log.cs.svn-base @@ -0,0 +1,52 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.IO; + +namespace ProxyCore +{ + public static class Log + { + /// + /// Write this into console window. + /// + /// Message to write to console window. + public static void Write(string msg) + { + Console.WriteLine(string.Format("[" + "{0:D2}" + ":" + "{1:D2}" + ":" + "{2:D2}" + "] ", DateTime.Now.Hour, DateTime.Now.Minute, DateTime.Now.Second) + msg); + } + + /// + /// Write an error message to console window and error.log + /// + /// + public static void Error(string msg) + { + Write(msg); + try + { + StreamWriter f = new StreamWriter("error.log", true); + f.WriteLine(string.Format("[" + "{0:D2}" + ":" + "{1:D2}" + ":" + "{2:D2}" + "] ", DateTime.Now.Hour, DateTime.Now.Minute, DateTime.Now.Second) + msg); + f.Close(); + } + catch + { + } + } + + /// + /// Write a stacktrace when program crashes. + /// + /// Trace to write. + public static void Crash(Exception e, string Module) + { + string[] E = e.StackTrace.Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries); + World.Instance.SendMessage("@RCRASH: Proxy crashed in module \"@w" + Module + "@R\"! Check error.log for details and send stack trace to author of module."); + Error("Program crashed in module (" + Module + ") with exception: \"" + e.Message + "\", type: \"" + e.GetType().ToString() + "\", trace:"); + foreach(string x in E) + Error(x); + Error("Trace end."); + } + } +} diff --git a/ProxyCore/.svn/text-base/ProxyCore.csproj.svn-base b/ProxyCore/.svn/text-base/ProxyCore.csproj.svn-base new file mode 100644 index 0000000..8bb0e26 --- /dev/null +++ b/ProxyCore/.svn/text-base/ProxyCore.csproj.svn-base @@ -0,0 +1,84 @@ + + + + Debug + AnyCPU + 9.0.30729 + 2.0 + {7863FE6F-E27F-4DBA-B2CC-EDEFE4AE8382} + Library + Properties + ProxyCore + ProxyCore + v3.5 + 512 + + + true + full + false + bin\ + DEBUG;TRACE + prompt + 4 + bin\ProxyCore.XML + + + pdbonly + true + bin\ + TRACE + prompt + 4 + bin\ProxyCore.XML + + + + False + ..\Resources\Jayrock.dll + + + False + ..\Resources\Jayrock.Json.dll + + + + 3.5 + + + 3.5 + + + 3.5 + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ProxyCore/.svn/text-base/World.cs.svn-base b/ProxyCore/.svn/text-base/World.cs.svn-base new file mode 100644 index 0000000..b04b185 --- /dev/null +++ b/ProxyCore/.svn/text-base/World.cs.svn-base @@ -0,0 +1,647 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using ProxyCore.Input; +using ProxyCore.Output; +using ProxyCore.Messages; +using ProxyCore.Scripting; +using System.Net; +using System.IO; +using System.Text.RegularExpressions; + +namespace ProxyCore +{ + public class World + { + public World() + { + Instance = this; + Log.Write("Loading plugins..."); + PluginMgr.LoadAll(); + TriggerHandler.RegisterTrigger("core.login", @"^\$gmcp\.char\.vitals\.hp ", _GMCPHP); + InputHandler.RegisterCommand("commands", "", _Commands, CMDFlags.None, null, 0, ulong.MaxValue, "core", 8); + InputHandler.RegisterCommand("lastlines", @"^(\d+)$", _LineInfo, CMDFlags.None, null, 0, ulong.MaxValue, "core", 8); + InputHandler.RegisterCommand("plugins", @"^(\w+)(\s+full)?", _PluginInfo, CMDFlags.None, null, 0, ulong.MaxValue, "core", 6); + InputHandler.RegisterCommand("shutdown", "", _Shutdown, CMDFlags.None, null, 0, ulong.MaxValue, "core", 8); + } + + private bool _Shutdown(InputData i) + { + _doShutdown = true; + return true; + } + + private bool _Commands(InputData i) + { + SendMessage("@wCommands in @Wcore@w:", i.ClientMask); + int c = WriteCommands(InputHandler.Commands, "core", i.ClientMask); + SendMessage("@C" + c + " @wcommand" + (c == 1 ? "" : "s") + " found."); + + foreach(KeyValuePair p in PluginMgr.Plugins) + { + SendMessage("", i.ClientMask); + SendMessage("@wCommands in @W" + p.Key + "@w:", i.ClientMask); + c = WriteCommands(InputHandler.Commands, p.Key, i.ClientMask); + SendMessage("@C" + c + " @wcommand" + (c == 1 ? "" : "s") + " found."); + } + + SendMessage("", i.ClientMask); + SendMessage("@WThese are commands for the proxy. If you want to see MUD commands type command.", i.ClientMask); + return true; + } + + private int WriteCommands(SortedDictionary y, string plugin, uint[] clientMask) + { + if(y == null || y.Count == 0) + return 0; + + int c = 0; + foreach(KeyValuePair x in y) + { + if(x.Value.Plugin != plugin) + continue; + if((x.Value.Flags & (CMDFlags.Disabled | CMDFlags.Hidden)) != CMDFlags.None) + continue; + string cmd = ""; + InputEntry p = x.Value.Parent; + while(p != null) + { + cmd = cmd.Insert(0, p.Command + " "); + p = p.Parent; + } + SendMessage("@Y" + cmd, clientMask); + c++; + + c += WriteCommands(x.Value.Subcommands, plugin, clientMask); + } + + return c; + } + + /// + /// Game world instance. + /// + public static World Instance + { + get; + private set; + } + + /// + /// Handle text line as if we received it from Aardwolf. + /// + /// + public void _OnReceived(string Msg) + { + TriggerHandler.HandleText(Msg, this); + } + + public void _OnConnected(bool connected) + { + isWorldReady = false; + foreach(KeyValuePair x in PluginMgr.Plugins) + { +#if !DEBUG + try + { +#endif + if(connected) + x.Value.OnConnect(); + else + x.Value.OnDisconnect(); +#if !DEBUG + } + catch(Exception e) + { + Log.Crash(e, x.Key); + } +#endif + } + } + + private bool _GMCPHP(TriggerData t) + { + if(!isWorldReady) + { + isWorldReady = true; + foreach(KeyValuePair x in PluginMgr.Plugins) + { +#if !DEBUG + try + { +#endif + x.Value.OnLogin(); +#if !DEBUG + } + catch(Exception e) + { + Log.Crash(e, x.Key); + } +#endif + } + CheckUpdatesNow = MSTime + 5000; + } + return false; + } + + private long CheckUpdatesNow = 0; + + private bool _LineInfo(InputData i) + { + int j = 10; + if(i.Arguments.Success) + { + if(!int.TryParse(i.Arguments.Groups[1].Value, out j)) + j = 10; + } + + if(j > 100) + j = 100; + else if(j < 1) + j = 1; + + SendMessage("@wDisplaying last @Y" + j + " @wline" + (j != 1 ? "s" : "") + ":", i.ClientMask); + j = lastLine.Count - j; + if(j < 0) + j = 0; + for(; j < lastLine.Count; j++) + SendMessage(lastLine[j].Replace("@", "@@"), i.ClientMask); + if(j == 10) + SendMessage("@wType '@Wlastlines @w' to see amount of lines.", i.ClientMask); + return true; + } + + internal List lastLine = new List(); + + private bool _PluginInfo(InputData i) + { + if(!i.Arguments.Success) + { + SendMessage("@wYou have the following plugins installed:", i.ClientMask); + foreach(KeyValuePair x in PluginMgr.Plugins) + SendMessage("@Y" + string.Format("{0,-20}", x.Value.Keyword.Trim()) + " @w- " + x.Value.Name + ", version " + x.Value.Version.ToString(), i.ClientMask); + if(PluginMgr.Plugins.Count == 0) + SendMessage("@RYou have no plugins installed.", i.ClientMask); + else + { + SendMessage("", i.ClientMask); + SendMessage("@C" + PluginMgr.Plugins.Count + " @wplugin" + (PluginMgr.Plugins.Count != 1 ? "s" : "") + " found."); + SendMessage("@wUse '@Wplugin @w' for more information about a plugin.", i.ClientMask); + SendMessage("@wUse '@Wplugin full@w' for all information about a plugin.", i.ClientMask); + //SendMessage("@wUse '@Wplugin write@w' to write all information about plugin to a file.", i.ClientMask); + } + } + else + { + Plugin p = PluginMgr.Plugins.ContainsKey(i.Arguments.Groups[1].Value.ToLower().Trim()) ? PluginMgr.Plugins[i.Arguments.Groups[1].Value.ToLower().Trim()] : null; + if(p == null) + { + SendMessage("@wNo such plugin (@W" + i.Arguments.Groups[1].Value.ToLower().Trim() + "@w).", i.ClientMask); + SendMessage("@wType '@Wplugins@w' for a list of installed plugins.", i.ClientMask); + return true; + } + + SendMessage("@w+----------------------------------------------------------------------+", i.ClientMask); + SendMessage("@w|@R" + p.Name.Substring(0, p.Name.Length / 2).PadLeft(35, ' ') + + p.Name.Substring(p.Name.Length / 2).PadRight(35, ' ') + "@w|", i.ClientMask); + SendMessage("@w+----------------------------------------------------------------------+", i.ClientMask); + SendMessage("@w| @WKeyword @w: @g" + string.Format("{0,-55}", p.Keyword) + "@w|", i.ClientMask); + SendMessage("@w| @WAuthor @w: @g" + string.Format("{0,-55}", !string.IsNullOrEmpty(p.Author) ? p.Author : "Unknown") + "@w|", i.ClientMask); + SendMessage("@w| @WVersion @w: @Y" + string.Format("{0,-55}", p.Version) + "@w|", i.ClientMask); + if(!string.IsNullOrEmpty(p.Website)) + SendMessage("@w| @WWebsite @w: @Y" + string.Format("{0,-55}", p.Website) + "@w|", i.ClientMask); + SendMessage("@w| @WClass name @w: @g" + string.Format("{0,-55}", p.ClassName) + "@w|", i.ClientMask); + if(!string.IsNullOrEmpty(p.Description)) + { + string[] desc = Utility.WrapColored(p.Description, 54, 0); + for(int j = 0; j < desc.Length; j++) + { + SendMessage( + j == 0 + ? ("@w| @WDescription @w: @C" + string.Format("{0,-55}", desc[j]) + "@w|") + : ("@w| : @C" + string.Format("{0,-55}", desc[j]) + "@w|"), i.ClientMask); + } + } + if(p.RequiredPlayerConfig.Count != 0) + { + for(int j = 0; j < p.RequiredPlayerConfig.Count; j++) + { + SendMessage( + j == 0 + ? ("@w| @WReq. config @w: " + string.Format("{0,-55}", p.RequiredPlayerConfig[j]) + + "@w|") + : ("@w| : " + string.Format("{0,-55}", p.RequiredPlayerConfig[j]) + "@w|"), + i.ClientMask); + } + } + SendMessage("@w+----------------------------------------------------------------------+", i.ClientMask); + if(i.Arguments.Groups[2].Length > 0 || i.Arguments.Groups[3].Length > 0) + { + int j = _PluginInfoWriteCommands(0, InputHandler.Commands, p.Keyword.ToLower().Trim(), i.ClientMask); + + int k = 0; + foreach(KeyValuePair x in TriggerHandler.TriggersName) + { + if(x.Value.Plugin != p.Keyword.ToLower().Trim()) + continue; + + if(k == 0) + { + SendMessage( + "@w| @WTriggers @w: \"" + + Utility.FormatColoredString(x.Value.PatternStr.Replace("@", "@@") + "\"", -54) + "@w|", + i.ClientMask); + } + else + { + SendMessage( + "@w| : \"" + + Utility.FormatColoredString(x.Value.PatternStr.Replace("@", "@@") + "\"", -54) + "@w|", + i.ClientMask); + } + k++; + } + + if(j != 0 || k != 0) + { + SendMessage("@w+----------------------------------------------------------------------+", + i.ClientMask); + } + } + } + + return true; + } + + private int _PluginInfoWriteCommands(int j, SortedDictionary y, string plugin, uint[] clientMask) + { + foreach(KeyValuePair x in y) + { + if(x.Value.Plugin != plugin) + continue; + + string cmd = x.Key; + InputEntry parent = x.Value.Parent; + while(parent != null) + { + cmd = cmd.Insert(0, parent.Command + " "); + parent = parent.Parent; + } + + if(j == 0) + SendMessage("@w| @WCommands @w: @c" + string.Format("{0,-55}", cmd) + "@w|", clientMask); + else + SendMessage("@w| : @c" + string.Format("{0,-55}", cmd) + "@w|", clientMask); + j++; + + if(x.Value.Subcommands != null) + j = _PluginInfoWriteCommands(j, x.Value.Subcommands, plugin, clientMask); + } + + return j; + } + + private bool isWorldReady = false; + + /// + /// Handle GMCP data that we received from Aardwolf. + /// + /// GMCP data received. + public void _OnReceived(byte[] Data) + { + string Msg = Encoding.Default.GetString(Data); + string Module = Msg.Trim().ToLower(); + if(Module.Contains(' ')) + Module = Module.Substring(0, Module.IndexOf(' ')); + Message m = new Message(true); + m.Clients = null; + m.Flags |= MessageFlags.GMCP; + m.Msg = Module; + m.MsgData = Data; + _SendMessage(m); + TriggerHandler.HandleGMCP(Msg); + } + + /// + /// This is called from proxy when it shuts down. Do NOT call from a plugin. + /// + public void Shutdown() + { + foreach(KeyValuePair x in PluginMgr.Plugins) + { +#if !DEBUG + try + { +#endif + x.Value.Shutdown(); +#if !DEBUG + } + catch(Exception e) + { + Log.Crash(e, x.Key); + } +#endif + } + + _doShutdown = true; + } + + /// + /// Enter input as if a client entered it. Meaning we parse it. Consider using the Execute command instead. + /// + /// Input entered. + /// Which client is this from? Enter 0 to set not from a client. + /// Authlevel of client who entered command (1...64) + public void _OnSent(string Msg, uint ClientId, int AuthLevel) + { + foreach(KeyValuePair x in PluginMgr.Plugins) + { +#if !DEBUG + try + { +#endif + x.Value.OnEnteredCommandBefore(ref Msg, ClientId, AuthLevel); +#if !DEBUG + } + catch(Exception e) + { + Log.Crash(e, x.Key); + } +#endif + if(Msg == null) + return; + } + + InputData i = InputHandler.HandleInput(Msg, Msg, ClientId, AuthLevel, null, this); + if(i != null) + { +#if !DEBUG + try + { +#endif + if(i.Function.Func(i)) + return; +#if !DEBUG + } + catch(Exception e) + { + Log.Crash(e, i.Function.Plugin); + } +#endif + Msg = i.Command; + } + + if(Msg != null) + { + foreach(KeyValuePair x in PluginMgr.Plugins) + { +#if !DEBUG + try + { +#endif + x.Value.OnEnteredCommandAfter(ref Msg, ClientId, AuthLevel); +#if !DEBUG + } + catch(Exception e) + { + Log.Crash(e, x.Value.Keyword); + } +#endif + if(Msg == null) + return; + } + _SendMessage(Msg, new uint[] {0}, ClientId != 0); + } + } + + internal void _SendMessage(string Msg, uint[] Clients, bool Natural) + { + _SendMessage(Msg, Clients, Natural, MessageFlags.None); + } + + internal void _SendMessage(string Msg, uint[] Clients, bool Natural, MessageFlags Flags) + { + _SendMessage(Msg, Clients, Natural, Flags, ulong.MaxValue); + } + + internal void _SendMessage(string Msg, uint[] Clients, bool Natural, MessageFlags Flags, ulong AuthMask) + { + Message m = new Message(Natural); + m.Clients = Clients; + m.Msg = Msg; + m.Flags = Flags; + m.AuthMask = AuthMask; + _SendMessage(m); + } + + internal void _SendMessage(Message msg) + { + _MessageData.Add(msg); + } + + /// + /// Send message to specified clients. + /// + /// Message to send. + /// Clients to send it to. Enter null to send to all connected clients. + /// Enter 0 as client to send it as a command to Aardwolf (we don't parse it though, if you want + /// parsed input use the Execute command). + public void SendMessage(string Msg, uint[] Clients) + { + _SendMessage(Msg, Clients, false); + } + + /// + /// Send a message to all connected authorized clients. + /// + /// Message to send to all authorized clients. + public void SendMessage(string Msg) + { + SendMessage(Msg, null); + } + + /// + /// Send a message to all connected authorized clients. + /// + /// Message to send to all authorized clients. + /// Authorization levels required to see this message. This is a mask. + public void SendMessage(string Msg, ulong AuthMask) + { + _SendMessage(Msg, null, false, MessageFlags.None, AuthMask); + } + + /// + /// Execute a command. + /// + /// Command to execute. + /// Allow parsing it for aliases and such, or send it directly to Aardwolf? + public void Execute(string Msg, bool allowParse) + { + Execute(Msg, allowParse, 1); + } + + /// + /// Execute a command. + /// + /// Command to execute. + /// Allow parsing it for aliases and such, or send it directly to Aardwolf? + /// Auth level that executes this command. (1...64) + public void Execute(string Msg, bool allowParse, int AuthLevel) + { + if(Msg == null) + return; + + if(allowParse) + _OnSent(Msg, uint.MaxValue, Math.Max(1, Math.Min(64, AuthLevel))); + else + _SendMessage(Msg, new uint[] { 0 }, false); + } + + /// + /// Send raw bytes to MUD. + /// + /// Bytes to send. + public void Send(byte[] Data) + { + if(Data == null) + return; + + Message m = new Message(false); + m.Clients = new uint[] { 0 }; + m.MsgData = Data; + _SendMessage(m); + } + + /// + /// Internal command for updating the world. DO NOT CALL FROM A PLUGIN! + /// + /// New mstime. + public bool Update(long msTime) + { + MSTime = msTime; + foreach(KeyValuePair x in PluginMgr.Plugins) + { +#if !DEBUG + try + { +#endif + x.Value.Update(msTime); +#if !DEBUG + } + catch(Exception e) + { + Log.Crash(e, x.Key); + } +#endif + } + + if(CheckUpdatesNow != 0 && msTime > CheckUpdatesNow) + { + CheckUpdatesNow = 0; + CheckUpdates(Config.GetInt32("Updates.Core", 1) != 0, Config.GetInt32("Updates.Plugins", 1) != 0, false); + } + + return _doShutdown; + } + + private bool _doShutdown = false; + + /// + /// This is messages for networking to handle. Don't touch unless you know what you are doing. + /// + public readonly List _MessageData = new List(256); + + internal CoreConfig Config = new CoreConfig(); + + /// + /// Version of Proxy. + /// + public const int Version = 7; + public const string CoreUrl = "www.duckbat.com/plugins/update.core.txt"; + public const string CoreUrl2 = "code.google.com/p/proxymud/"; + + private int GetVersion(string Url) + { + if(!_urlRegex.Match(Url).Success) + Url = "http://" + Url; + WebClient w = new WebClient(); + byte[] d = w.DownloadData(Url); + string s = Encoding.Default.GetString(d); + s = s.Replace("\r", ""); + s = s.Replace(" ", ""); + s = s.Replace("\n", ""); + return int.Parse(s); + } + + private static Regex _urlRegex = new Regex(@"^\w+://", RegexOptions.Compiled); + + /// + /// Milliseconds since program startup. + /// + public long MSTime + { + get; + private set; + } + + /// + /// Check for updates and report to all connected users if there are any. + /// + /// Check core update. + /// Check plugin updates. + /// Should we report if no updates were found? + public void CheckUpdates(bool Core, bool Plugins, bool ReportNoUpdates) + { +#if DEBUG + return; +#endif + bool s = false; + if(Core) + { + try + { + int coreVer = GetVersion(CoreUrl); + if(coreVer > Version) + { + SendMessage("@GUPDATE: @wThere is a newer version of @Wcore @wavailable. (@W" + coreVer + "@w)"); + SendMessage(" @wGo to @W" + CoreUrl2 + " @wto see more."); + s = true; + } + } + catch + { + } + } + + if(Plugins) + { + foreach(KeyValuePair x in PluginMgr.Plugins) + { + if(string.IsNullOrEmpty(x.Value.Website) || string.IsNullOrEmpty(x.Value.UpdateUrl)) + continue; + + try + { + int ver = GetVersion(x.Value.UpdateUrl); + if(ver > x.Value.Version) + { + if(s) + SendMessage(""); + SendMessage("@GUPDATE: @wThere is a newer version of @W" + x.Value.Keyword.ToLower().Trim() + " @wavailable. (@W" + ver + "@w)"); + SendMessage(" @wGo to @W" + x.Value.Website + " @wto see more."); + s = true; + } + } + catch + { + continue; + } + } + } + + if(ReportNoUpdates && !s) + SendMessage("@GUPDATE: @wNo updates found."); + } + } +} diff --git a/ProxyCore/.svn/text-base/desktop.ini b/ProxyCore/.svn/text-base/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/ProxyCore/.svn/text-base/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/ProxyCore/.svn/tmp/desktop.ini b/ProxyCore/.svn/tmp/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/ProxyCore/.svn/tmp/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/ProxyCore/.svn/tmp/prop-base/desktop.ini b/ProxyCore/.svn/tmp/prop-base/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/ProxyCore/.svn/tmp/prop-base/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/ProxyCore/.svn/tmp/props/desktop.ini b/ProxyCore/.svn/tmp/props/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/ProxyCore/.svn/tmp/props/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/ProxyCore/.svn/tmp/text-base/desktop.ini b/ProxyCore/.svn/tmp/text-base/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/ProxyCore/.svn/tmp/text-base/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/ProxyCore/Input/.svn/all-wcprops b/ProxyCore/Input/.svn/all-wcprops new file mode 100644 index 0000000..b1976c9 --- /dev/null +++ b/ProxyCore/Input/.svn/all-wcprops @@ -0,0 +1,23 @@ +K 25 +svn:wc:ra_dav:version-url +V 37 +/svn/!svn/ver/2/trunk/ProxyCore/Input +END +InputData.cs +K 25 +svn:wc:ra_dav:version-url +V 50 +/svn/!svn/ver/2/trunk/ProxyCore/Input/InputData.cs +END +InputHandler.cs +K 25 +svn:wc:ra_dav:version-url +V 53 +/svn/!svn/ver/2/trunk/ProxyCore/Input/InputHandler.cs +END +InputEntry.cs +K 25 +svn:wc:ra_dav:version-url +V 51 +/svn/!svn/ver/2/trunk/ProxyCore/Input/InputEntry.cs +END diff --git a/ProxyCore/Input/.svn/desktop.ini b/ProxyCore/Input/.svn/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/ProxyCore/Input/.svn/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/ProxyCore/Input/.svn/dir-prop-base b/ProxyCore/Input/.svn/dir-prop-base new file mode 100644 index 0000000..f1b96ea --- /dev/null +++ b/ProxyCore/Input/.svn/dir-prop-base @@ -0,0 +1,5 @@ +K 14 +bugtraq:number +V 4 +true +END diff --git a/ProxyCore/Input/.svn/entries b/ProxyCore/Input/.svn/entries new file mode 100644 index 0000000..552b024 --- /dev/null +++ b/ProxyCore/Input/.svn/entries @@ -0,0 +1,130 @@ +10 + +dir +58 +http://proxymud.googlecode.com/svn/trunk/ProxyCore/Input +http://proxymud.googlecode.com/svn + + + +2012-01-17T10:55:35.805502Z +2 +default8p@gmail.com +has-props + + + + + + + + + + + + + +8a6e9f07-fe1d-2472-fcf8-0b435762827a + +InputData.cs +file + + + + +2016-03-25T22:18:43.184138Z +155a373f27748daa21a7fce96108399b +2012-01-17T10:55:35.805502Z +2 +default8p@gmail.com + + + + + + + + + + + + + + + + + + + + + +1995 + +InputHandler.cs +file + + + + +2016-03-25T22:18:43.184138Z +560caee9040d3d6c238a177cf5050917 +2012-01-17T10:55:35.805502Z +2 +default8p@gmail.com + + + + + + + + + + + + + + + + + + + + + +12480 + +InputEntry.cs +file + + + + +2016-03-25T22:18:43.184138Z +cf1a6e8a4d7f6acb5e29469c2042ac0d +2012-01-17T10:55:35.805502Z +2 +default8p@gmail.com + + + + + + + + + + + + + + + + + + + + + +1617 + diff --git a/ProxyCore/Input/.svn/prop-base/desktop.ini b/ProxyCore/Input/.svn/prop-base/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/ProxyCore/Input/.svn/prop-base/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/ProxyCore/Input/.svn/props/desktop.ini b/ProxyCore/Input/.svn/props/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/ProxyCore/Input/.svn/props/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/ProxyCore/Input/.svn/text-base/InputData.cs.svn-base b/ProxyCore/Input/.svn/text-base/InputData.cs.svn-base new file mode 100644 index 0000000..4293b57 --- /dev/null +++ b/ProxyCore/Input/.svn/text-base/InputData.cs.svn-base @@ -0,0 +1,66 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; + +namespace ProxyCore.Input +{ + public class InputData + { + internal InputData() + { + } + + /// + /// Who executed the command? This will be uint.MaxValue if we execute it from a plugin or other places - meaning + /// it didn't originate from a client. + /// + public uint ClientId + { + get; + internal set; + } + + /// + /// Use this if you want to send message to whoever executed the command. If it was executed from a plugin + /// send message to every client. Example: World.Instance.SendMessage("Test.", i.ClientMask); + /// + public uint[] ClientMask + { + get + { + return ClientId != uint.MaxValue ? new[] { ClientId } : null; + } + } + + /// + /// The auth level of client who entered command. (1...64) + /// + public int ClientAuthLevel + { + get; + internal set; + } + + /// + /// Whole command just as it was entered. You can change this to send something different to MUD. Just make + /// sure you return false on the command handler otherwise nothing will get sent to MUD. + /// + public string Command; + + /// + /// Which function will we execute with this data. + /// + internal InputEntry Function; + + /// + /// This is where we capture arguments if the arguments pattern was set. Check first if Arguments.Success, otherwise there will be no Groups set. + /// + public Match Arguments + { + get; + internal set; + } + } +} diff --git a/ProxyCore/Input/.svn/text-base/InputEntry.cs.svn-base b/ProxyCore/Input/.svn/text-base/InputEntry.cs.svn-base new file mode 100644 index 0000000..10dda3f --- /dev/null +++ b/ProxyCore/Input/.svn/text-base/InputEntry.cs.svn-base @@ -0,0 +1,56 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; + +namespace ProxyCore.Input +{ + internal class InputEntry + { + internal string Command; + internal CmdFunction Func; + internal CMDFlags Flags; + internal InputEntry Parent; + internal int CustomArg; + internal Regex ArgumentsPattern; + internal ulong AuthMask; + internal string Plugin; + internal int MinLength; + internal SortedDictionary Subcommands; + } + + /// + /// Function for handling input. Return true if we handled the command (no need to send to MUD) and false + /// if we didn't and we must send it to MUD. + /// + /// Input data. + /// + public delegate bool CmdFunction(InputData cmd); + + [Flags] + public enum CMDFlags + { + None = 0, + + /// + /// Hidden from normal commands menu. + /// + Hidden = 2, + + /// + /// Command is currently disabled and will be excluded in the list of valid commands. + /// + Disabled = 4, + + /// + /// Dummy command, player can't type it but it will be redirected from elsewhere. + /// + Dummy = 8, + + /// + /// Internal - this will be assigned automatically for commands that have subcommands. + /// + IsParent = 0x10, + } +} diff --git a/ProxyCore/Input/.svn/text-base/InputHandler.cs.svn-base b/ProxyCore/Input/.svn/text-base/InputHandler.cs.svn-base new file mode 100644 index 0000000..931c6d8 --- /dev/null +++ b/ProxyCore/Input/.svn/text-base/InputHandler.cs.svn-base @@ -0,0 +1,285 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; + +namespace ProxyCore.Input +{ + internal static class InputHandler + { + static InputHandler() + { + } + + internal static SortedDictionary Commands = new SortedDictionary(); + + /// + /// Register a new command or overwrite a previous one. + /// + /// Command to register. + /// Arguments to match (regex pattern). This can be set to null or empty string + /// if you don't want to capture anything or plan to do so in the function yourself. + /// Function of command. + internal static void RegisterCommand(string Cmd, string Args, CmdFunction f) + { + RegisterCommand(Cmd, Args, f, CMDFlags.None); + } + + /// + /// Register a new command or overwrite a previous one. + /// + /// Command to register. + /// Arguments to match (regex pattern). This can be set to null or empty string + /// if you don't want to capture anything or plan to do so in the function yourself. + /// Function of command. + /// Options for command. + internal static void RegisterCommand(string Cmd, string Args, CmdFunction f, CMDFlags flags) + { + RegisterCommand(Cmd, Args, f, flags, null); + } + + /// + /// Register a new command or overwrite a previous one. + /// + /// Command to register. + /// Arguments to match (regex pattern). This can be set to null or empty string + /// if you don't want to capture anything or plan to do so in the function yourself. + /// Function of command. + /// Options for command. + /// Parent command (if you want to create a subcommand). You can enter commands separated with space if it's nested. + internal static void RegisterCommand(string Cmd, string Args, CmdFunction f, CMDFlags flags, string parent) + { + RegisterCommand(Cmd, Args, f, flags, parent, 0); + } + + /// + /// Register a new command or overwrite a previous one. + /// + /// Command to register. + /// Arguments to match (regex pattern). This can be set to null or empty string + /// if you don't want to capture anything or plan to do so in the function yourself. + /// Function of command. + /// Options for command. + /// Parent command (if you want to create a subcommand). You can enter commands separated with space if it's nested. + /// Custom argument to pass to function handler. This way you can register multiple commands to a same + /// function handler only differentiating them with this custom argument. + internal static void RegisterCommand(string Cmd, string Args, CmdFunction f, CMDFlags flags, string parent, int Arg) + { + RegisterCommand(Cmd, Args, f, flags, parent, Arg, ulong.MaxValue, "core", 0); + } + + /// + /// Register a new command or overwrite a previous one. + /// + /// Command to register. + /// Arguments to match (regex pattern). This can be set to null or empty string + /// if you don't want to capture anything or plan to do so in the function yourself. + /// Function of command. + /// Options for command. + /// Parent command (if you want to create a subcommand). You can enter commands separated with space if it's nested. + /// Custom argument to pass to function handler. This way you can register multiple commands to a same + /// function handler only differentiating them with this custom argument. + /// Mask of allowed auth levels to access this command. Default ulong.MaxValue (meaning all auth levels are allowed). + /// Enter 3 for example to allow only auth level 1 and 2 to access this command. + /// From which plugin did this come. + /// Minimum length of command typed required to activate. For example if command is "plugins" and this is 6 then "plugin" and "plugins" both activate this command but "plugi" won't. + internal static void RegisterCommand(string Cmd, string Args, CmdFunction f, CMDFlags flags, string parent, int Arg, ulong AuthMask, string Plugin, int ReqMinLength) + { + if(string.IsNullOrEmpty(Cmd)) + return; + + Cmd = Cmd.ToLower().Trim(); + if(string.IsNullOrEmpty(Cmd)) + return; + + if(Cmd.Contains(' ')) + Cmd = Cmd.Substring(0, Cmd.IndexOf(' ')); + + InputEntry p = null; + if(!string.IsNullOrEmpty(parent)) + { + string[] pc = parent.ToLower().Trim().Split(new string[] { " " }, StringSplitOptions.RemoveEmptyEntries); + if(pc.Length == 0) + return; + + if(Commands.ContainsKey(pc[0])) + { + p = Commands[pc[0]]; + for(int i = 1; i < pc.Length; i++) + { + if(p.Subcommands != null && p.Subcommands.ContainsKey(pc[i])) + p = p.Subcommands[pc[i]]; + else + return; + } + } + else + return; + } + + InputEntry c = new InputEntry() + { + Command = Cmd, + CustomArg = Arg, + Flags = flags, + Func = f, + Parent = p, + Plugin = Plugin, + MinLength = ReqMinLength, + AuthMask = AuthMask + }; + + try + { + c.ArgumentsPattern = new Regex(Args, RegexOptions.IgnoreCase); + } + catch + { + c.ArgumentsPattern = null; + } + + if(p != null) + { + if(p.Subcommands == null) + p.Subcommands = new SortedDictionary(); + p.Subcommands[Cmd] = c; + p.Flags |= CMDFlags.IsParent; + } + else + Commands[Cmd] = c; + } + + /// + /// Unregister a command. + /// + /// Command to unregister. If you want to unregister a nested command + /// separate commands with a space. + internal static void UnregisterCommand(string Cmd) + { + if(Cmd == null) + return; + + string[] pc = Cmd.ToLower().Trim().Split(new string[] { " " }, StringSplitOptions.RemoveEmptyEntries); + if(pc.Length == 0) + return; + + if(!Commands.ContainsKey(pc[0])) + return; + + if(pc.Length > 1) + { + InputEntry p = Commands[pc[0]]; + for(int i = 1; i < pc.Length; i++) + { + if(p.Subcommands == null || !p.Subcommands.ContainsKey(pc[i])) + return; + p = p.Subcommands[pc[i]]; + } + + p.Parent.Subcommands.Remove(p.Command); + if(p.Parent.Subcommands.Count == 0) + p.Parent.Flags &= ~CMDFlags.IsParent; + } + else + Commands.Remove(pc[0]); + } + + internal static InputData HandleInput(string origCommand, string Msg, uint ClientId, int AuthLevel, InputEntry parent, World world) + { + Msg = Msg.Trim(); + string cmd = ""; + string text = ""; + + if(Msg.Contains(' ')) + { + cmd = Msg.Substring(0, Msg.IndexOf(' ')); + text = Msg.Substring(Msg.IndexOf(' ') + 1).Trim(); + } + else + { + cmd = Msg; + } + + cmd = cmd.ToLower(); + InputEntry f = null; + + if(!string.IsNullOrEmpty(cmd)) + { + if(parent == null) + { + foreach(KeyValuePair x in Commands) + { + if(x.Key == cmd && (x.Value.Flags & (CMDFlags.Dummy | CMDFlags.Disabled)) == CMDFlags.None && (x.Value.AuthMask & ((ulong)1 << (AuthLevel - 1))) != 0) + { + f = x.Value; + break; + } + } + + if(f == null) + { + foreach(KeyValuePair x in Commands) + { + if(x.Value.MinLength <= 0) + continue; + if(cmd.Length < x.Value.Command.Length && cmd.Length >= x.Value.MinLength && x.Value.Command.StartsWith(cmd) && (x.Value.Flags & (CMDFlags.Dummy | CMDFlags.Disabled)) == CMDFlags.None && (x.Value.AuthMask & ((ulong)1 << (AuthLevel - 1))) != 0) + { + f = x.Value; + break; + } + } + } + } + else if(parent.Subcommands != null) + { + foreach(KeyValuePair x in parent.Subcommands) + { + if(x.Key == cmd && (x.Value.Flags & (CMDFlags.Dummy | CMDFlags.Disabled)) == CMDFlags.None && (x.Value.AuthMask & ((ulong)1 << (AuthLevel - 1))) != 0) + { + f = x.Value; + break; + } + } + + if(f == null) + { + foreach(KeyValuePair x in parent.Subcommands) + { + if(x.Value.MinLength <= 0) + continue; + if(cmd.Length < x.Value.Command.Length && cmd.Length >= x.Value.MinLength && x.Value.Command.StartsWith(cmd) && (x.Value.Flags & (CMDFlags.Dummy | CMDFlags.Disabled)) == CMDFlags.None && (x.Value.AuthMask & ((ulong)1 << (AuthLevel - 1))) != 0) + { + f = x.Value; + break; + } + } + } + } + } + else + { + if(parent != null && parent.Func != null) + f = parent; + else + return null; + } + + if(f != null && (f.Flags & CMDFlags.IsParent) != CMDFlags.None && !string.IsNullOrEmpty(text)) + return HandleInput(origCommand, text, ClientId, AuthLevel, f, world); + + if(f == null || f.Func == null) + return null; + + InputData data = new InputData(); + data.Command = origCommand; + data.ClientId = ClientId; + data.ClientAuthLevel = AuthLevel; + data.Function = f; + if(f.ArgumentsPattern != null) + data.Arguments = f.ArgumentsPattern.Match(text); + + return data; + } + } +} diff --git a/ProxyCore/Input/.svn/text-base/desktop.ini b/ProxyCore/Input/.svn/text-base/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/ProxyCore/Input/.svn/text-base/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/ProxyCore/Input/.svn/tmp/desktop.ini b/ProxyCore/Input/.svn/tmp/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/ProxyCore/Input/.svn/tmp/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/ProxyCore/Input/.svn/tmp/prop-base/desktop.ini b/ProxyCore/Input/.svn/tmp/prop-base/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/ProxyCore/Input/.svn/tmp/prop-base/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/ProxyCore/Input/.svn/tmp/props/desktop.ini b/ProxyCore/Input/.svn/tmp/props/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/ProxyCore/Input/.svn/tmp/props/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/ProxyCore/Input/.svn/tmp/text-base/desktop.ini b/ProxyCore/Input/.svn/tmp/text-base/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/ProxyCore/Input/.svn/tmp/text-base/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/ProxyCore/Input/InputData.cs b/ProxyCore/Input/InputData.cs new file mode 100644 index 0000000..4293b57 --- /dev/null +++ b/ProxyCore/Input/InputData.cs @@ -0,0 +1,66 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; + +namespace ProxyCore.Input +{ + public class InputData + { + internal InputData() + { + } + + /// + /// Who executed the command? This will be uint.MaxValue if we execute it from a plugin or other places - meaning + /// it didn't originate from a client. + /// + public uint ClientId + { + get; + internal set; + } + + /// + /// Use this if you want to send message to whoever executed the command. If it was executed from a plugin + /// send message to every client. Example: World.Instance.SendMessage("Test.", i.ClientMask); + /// + public uint[] ClientMask + { + get + { + return ClientId != uint.MaxValue ? new[] { ClientId } : null; + } + } + + /// + /// The auth level of client who entered command. (1...64) + /// + public int ClientAuthLevel + { + get; + internal set; + } + + /// + /// Whole command just as it was entered. You can change this to send something different to MUD. Just make + /// sure you return false on the command handler otherwise nothing will get sent to MUD. + /// + public string Command; + + /// + /// Which function will we execute with this data. + /// + internal InputEntry Function; + + /// + /// This is where we capture arguments if the arguments pattern was set. Check first if Arguments.Success, otherwise there will be no Groups set. + /// + public Match Arguments + { + get; + internal set; + } + } +} diff --git a/ProxyCore/Input/InputEntry.cs b/ProxyCore/Input/InputEntry.cs new file mode 100644 index 0000000..10dda3f --- /dev/null +++ b/ProxyCore/Input/InputEntry.cs @@ -0,0 +1,56 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; + +namespace ProxyCore.Input +{ + internal class InputEntry + { + internal string Command; + internal CmdFunction Func; + internal CMDFlags Flags; + internal InputEntry Parent; + internal int CustomArg; + internal Regex ArgumentsPattern; + internal ulong AuthMask; + internal string Plugin; + internal int MinLength; + internal SortedDictionary Subcommands; + } + + /// + /// Function for handling input. Return true if we handled the command (no need to send to MUD) and false + /// if we didn't and we must send it to MUD. + /// + /// Input data. + /// + public delegate bool CmdFunction(InputData cmd); + + [Flags] + public enum CMDFlags + { + None = 0, + + /// + /// Hidden from normal commands menu. + /// + Hidden = 2, + + /// + /// Command is currently disabled and will be excluded in the list of valid commands. + /// + Disabled = 4, + + /// + /// Dummy command, player can't type it but it will be redirected from elsewhere. + /// + Dummy = 8, + + /// + /// Internal - this will be assigned automatically for commands that have subcommands. + /// + IsParent = 0x10, + } +} diff --git a/ProxyCore/Input/InputHandler.cs b/ProxyCore/Input/InputHandler.cs new file mode 100644 index 0000000..931c6d8 --- /dev/null +++ b/ProxyCore/Input/InputHandler.cs @@ -0,0 +1,285 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; + +namespace ProxyCore.Input +{ + internal static class InputHandler + { + static InputHandler() + { + } + + internal static SortedDictionary Commands = new SortedDictionary(); + + /// + /// Register a new command or overwrite a previous one. + /// + /// Command to register. + /// Arguments to match (regex pattern). This can be set to null or empty string + /// if you don't want to capture anything or plan to do so in the function yourself. + /// Function of command. + internal static void RegisterCommand(string Cmd, string Args, CmdFunction f) + { + RegisterCommand(Cmd, Args, f, CMDFlags.None); + } + + /// + /// Register a new command or overwrite a previous one. + /// + /// Command to register. + /// Arguments to match (regex pattern). This can be set to null or empty string + /// if you don't want to capture anything or plan to do so in the function yourself. + /// Function of command. + /// Options for command. + internal static void RegisterCommand(string Cmd, string Args, CmdFunction f, CMDFlags flags) + { + RegisterCommand(Cmd, Args, f, flags, null); + } + + /// + /// Register a new command or overwrite a previous one. + /// + /// Command to register. + /// Arguments to match (regex pattern). This can be set to null or empty string + /// if you don't want to capture anything or plan to do so in the function yourself. + /// Function of command. + /// Options for command. + /// Parent command (if you want to create a subcommand). You can enter commands separated with space if it's nested. + internal static void RegisterCommand(string Cmd, string Args, CmdFunction f, CMDFlags flags, string parent) + { + RegisterCommand(Cmd, Args, f, flags, parent, 0); + } + + /// + /// Register a new command or overwrite a previous one. + /// + /// Command to register. + /// Arguments to match (regex pattern). This can be set to null or empty string + /// if you don't want to capture anything or plan to do so in the function yourself. + /// Function of command. + /// Options for command. + /// Parent command (if you want to create a subcommand). You can enter commands separated with space if it's nested. + /// Custom argument to pass to function handler. This way you can register multiple commands to a same + /// function handler only differentiating them with this custom argument. + internal static void RegisterCommand(string Cmd, string Args, CmdFunction f, CMDFlags flags, string parent, int Arg) + { + RegisterCommand(Cmd, Args, f, flags, parent, Arg, ulong.MaxValue, "core", 0); + } + + /// + /// Register a new command or overwrite a previous one. + /// + /// Command to register. + /// Arguments to match (regex pattern). This can be set to null or empty string + /// if you don't want to capture anything or plan to do so in the function yourself. + /// Function of command. + /// Options for command. + /// Parent command (if you want to create a subcommand). You can enter commands separated with space if it's nested. + /// Custom argument to pass to function handler. This way you can register multiple commands to a same + /// function handler only differentiating them with this custom argument. + /// Mask of allowed auth levels to access this command. Default ulong.MaxValue (meaning all auth levels are allowed). + /// Enter 3 for example to allow only auth level 1 and 2 to access this command. + /// From which plugin did this come. + /// Minimum length of command typed required to activate. For example if command is "plugins" and this is 6 then "plugin" and "plugins" both activate this command but "plugi" won't. + internal static void RegisterCommand(string Cmd, string Args, CmdFunction f, CMDFlags flags, string parent, int Arg, ulong AuthMask, string Plugin, int ReqMinLength) + { + if(string.IsNullOrEmpty(Cmd)) + return; + + Cmd = Cmd.ToLower().Trim(); + if(string.IsNullOrEmpty(Cmd)) + return; + + if(Cmd.Contains(' ')) + Cmd = Cmd.Substring(0, Cmd.IndexOf(' ')); + + InputEntry p = null; + if(!string.IsNullOrEmpty(parent)) + { + string[] pc = parent.ToLower().Trim().Split(new string[] { " " }, StringSplitOptions.RemoveEmptyEntries); + if(pc.Length == 0) + return; + + if(Commands.ContainsKey(pc[0])) + { + p = Commands[pc[0]]; + for(int i = 1; i < pc.Length; i++) + { + if(p.Subcommands != null && p.Subcommands.ContainsKey(pc[i])) + p = p.Subcommands[pc[i]]; + else + return; + } + } + else + return; + } + + InputEntry c = new InputEntry() + { + Command = Cmd, + CustomArg = Arg, + Flags = flags, + Func = f, + Parent = p, + Plugin = Plugin, + MinLength = ReqMinLength, + AuthMask = AuthMask + }; + + try + { + c.ArgumentsPattern = new Regex(Args, RegexOptions.IgnoreCase); + } + catch + { + c.ArgumentsPattern = null; + } + + if(p != null) + { + if(p.Subcommands == null) + p.Subcommands = new SortedDictionary(); + p.Subcommands[Cmd] = c; + p.Flags |= CMDFlags.IsParent; + } + else + Commands[Cmd] = c; + } + + /// + /// Unregister a command. + /// + /// Command to unregister. If you want to unregister a nested command + /// separate commands with a space. + internal static void UnregisterCommand(string Cmd) + { + if(Cmd == null) + return; + + string[] pc = Cmd.ToLower().Trim().Split(new string[] { " " }, StringSplitOptions.RemoveEmptyEntries); + if(pc.Length == 0) + return; + + if(!Commands.ContainsKey(pc[0])) + return; + + if(pc.Length > 1) + { + InputEntry p = Commands[pc[0]]; + for(int i = 1; i < pc.Length; i++) + { + if(p.Subcommands == null || !p.Subcommands.ContainsKey(pc[i])) + return; + p = p.Subcommands[pc[i]]; + } + + p.Parent.Subcommands.Remove(p.Command); + if(p.Parent.Subcommands.Count == 0) + p.Parent.Flags &= ~CMDFlags.IsParent; + } + else + Commands.Remove(pc[0]); + } + + internal static InputData HandleInput(string origCommand, string Msg, uint ClientId, int AuthLevel, InputEntry parent, World world) + { + Msg = Msg.Trim(); + string cmd = ""; + string text = ""; + + if(Msg.Contains(' ')) + { + cmd = Msg.Substring(0, Msg.IndexOf(' ')); + text = Msg.Substring(Msg.IndexOf(' ') + 1).Trim(); + } + else + { + cmd = Msg; + } + + cmd = cmd.ToLower(); + InputEntry f = null; + + if(!string.IsNullOrEmpty(cmd)) + { + if(parent == null) + { + foreach(KeyValuePair x in Commands) + { + if(x.Key == cmd && (x.Value.Flags & (CMDFlags.Dummy | CMDFlags.Disabled)) == CMDFlags.None && (x.Value.AuthMask & ((ulong)1 << (AuthLevel - 1))) != 0) + { + f = x.Value; + break; + } + } + + if(f == null) + { + foreach(KeyValuePair x in Commands) + { + if(x.Value.MinLength <= 0) + continue; + if(cmd.Length < x.Value.Command.Length && cmd.Length >= x.Value.MinLength && x.Value.Command.StartsWith(cmd) && (x.Value.Flags & (CMDFlags.Dummy | CMDFlags.Disabled)) == CMDFlags.None && (x.Value.AuthMask & ((ulong)1 << (AuthLevel - 1))) != 0) + { + f = x.Value; + break; + } + } + } + } + else if(parent.Subcommands != null) + { + foreach(KeyValuePair x in parent.Subcommands) + { + if(x.Key == cmd && (x.Value.Flags & (CMDFlags.Dummy | CMDFlags.Disabled)) == CMDFlags.None && (x.Value.AuthMask & ((ulong)1 << (AuthLevel - 1))) != 0) + { + f = x.Value; + break; + } + } + + if(f == null) + { + foreach(KeyValuePair x in parent.Subcommands) + { + if(x.Value.MinLength <= 0) + continue; + if(cmd.Length < x.Value.Command.Length && cmd.Length >= x.Value.MinLength && x.Value.Command.StartsWith(cmd) && (x.Value.Flags & (CMDFlags.Dummy | CMDFlags.Disabled)) == CMDFlags.None && (x.Value.AuthMask & ((ulong)1 << (AuthLevel - 1))) != 0) + { + f = x.Value; + break; + } + } + } + } + } + else + { + if(parent != null && parent.Func != null) + f = parent; + else + return null; + } + + if(f != null && (f.Flags & CMDFlags.IsParent) != CMDFlags.None && !string.IsNullOrEmpty(text)) + return HandleInput(origCommand, text, ClientId, AuthLevel, f, world); + + if(f == null || f.Func == null) + return null; + + InputData data = new InputData(); + data.Command = origCommand; + data.ClientId = ClientId; + data.ClientAuthLevel = AuthLevel; + data.Function = f; + if(f.ArgumentsPattern != null) + data.Arguments = f.ArgumentsPattern.Match(text); + + return data; + } + } +} diff --git a/ProxyCore/Input/desktop.ini b/ProxyCore/Input/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/ProxyCore/Input/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/ProxyCore/Log.cs b/ProxyCore/Log.cs new file mode 100644 index 0000000..23382e4 --- /dev/null +++ b/ProxyCore/Log.cs @@ -0,0 +1,52 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.IO; + +namespace ProxyCore +{ + public static class Log + { + /// + /// Write this into console window. + /// + /// Message to write to console window. + public static void Write(string msg) + { + Console.WriteLine(string.Format("[" + "{0:D2}" + ":" + "{1:D2}" + ":" + "{2:D2}" + "] ", DateTime.Now.Hour, DateTime.Now.Minute, DateTime.Now.Second) + msg); + } + + /// + /// Write an error message to console window and error.log + /// + /// + public static void Error(string msg) + { + Write(msg); + try + { + StreamWriter f = new StreamWriter("error.log", true); + f.WriteLine(string.Format("[" + "{0:D2}" + ":" + "{1:D2}" + ":" + "{2:D2}" + "] ", DateTime.Now.Hour, DateTime.Now.Minute, DateTime.Now.Second) + msg); + f.Close(); + } + catch + { + } + } + + /// + /// Write a stacktrace when program crashes. + /// + /// Trace to write. + public static void Crash(Exception e, string Module) + { + string[] E = e.StackTrace.Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries); + World.Instance.SendMessage("@RCRASH: Proxy crashed in module \"@w" + Module + "@R\"! Check error.log for details and send stack trace to author of module."); + Error("Program crashed in module (" + Module + ") with exception: \"" + e.Message + "\", type: \"" + e.GetType().ToString() + "\", trace:"); + foreach(string x in E) + Error(x); + Error("Trace end."); + } + } +} diff --git a/ProxyCore/Messages/.svn/all-wcprops b/ProxyCore/Messages/.svn/all-wcprops new file mode 100644 index 0000000..49abc09 --- /dev/null +++ b/ProxyCore/Messages/.svn/all-wcprops @@ -0,0 +1,11 @@ +K 25 +svn:wc:ra_dav:version-url +V 40 +/svn/!svn/ver/2/trunk/ProxyCore/Messages +END +Message.cs +K 25 +svn:wc:ra_dav:version-url +V 51 +/svn/!svn/ver/2/trunk/ProxyCore/Messages/Message.cs +END diff --git a/ProxyCore/Messages/.svn/desktop.ini b/ProxyCore/Messages/.svn/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/ProxyCore/Messages/.svn/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/ProxyCore/Messages/.svn/dir-prop-base b/ProxyCore/Messages/.svn/dir-prop-base new file mode 100644 index 0000000..f1b96ea --- /dev/null +++ b/ProxyCore/Messages/.svn/dir-prop-base @@ -0,0 +1,5 @@ +K 14 +bugtraq:number +V 4 +true +END diff --git a/ProxyCore/Messages/.svn/entries b/ProxyCore/Messages/.svn/entries new file mode 100644 index 0000000..47a0ef5 --- /dev/null +++ b/ProxyCore/Messages/.svn/entries @@ -0,0 +1,62 @@ +10 + +dir +58 +http://proxymud.googlecode.com/svn/trunk/ProxyCore/Messages +http://proxymud.googlecode.com/svn + + + +2012-01-17T10:55:35.805502Z +2 +default8p@gmail.com +has-props + + + + + + + + + + + + + +8a6e9f07-fe1d-2472-fcf8-0b435762827a + +Message.cs +file + + + + +2016-03-25T22:18:43.216138Z +875894e5c9ff74a2fad723d3170d09c9 +2012-01-17T10:55:35.805502Z +2 +default8p@gmail.com + + + + + + + + + + + + + + + + + + + + + +2923 + diff --git a/ProxyCore/Messages/.svn/prop-base/desktop.ini b/ProxyCore/Messages/.svn/prop-base/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/ProxyCore/Messages/.svn/prop-base/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/ProxyCore/Messages/.svn/props/desktop.ini b/ProxyCore/Messages/.svn/props/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/ProxyCore/Messages/.svn/props/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/ProxyCore/Messages/.svn/text-base/Message.cs.svn-base b/ProxyCore/Messages/.svn/text-base/Message.cs.svn-base new file mode 100644 index 0000000..49d33f4 --- /dev/null +++ b/ProxyCore/Messages/.svn/text-base/Message.cs.svn-base @@ -0,0 +1,91 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace ProxyCore.Messages +{ + public class Message + { + internal Message(bool isNaturalMessage) + { + IsNaturalMessage = isNaturalMessage; + } + + /// + /// Contents of the message. + /// + public string Msg + { + get + { + return _msg; + } + set + { + _msg = value; + MsgNoColor = _msg == null ? null : Colors.RemoveColors(_msg, false); + } + } + + private string _msg; + + /// + /// If this is set ignore message and send this byte data instead. Color codes + /// will not be parsed by server and this is sent as is. + /// + public byte[] MsgData = null; + + /// + /// This is message but without colors. Used for triggering non-ansi triggers. + /// + internal string MsgNoColor = null; + + /// + /// Which clients should receive the message. This is a mask for security levels. + /// For example value "3" would only send this message to security level 1 and 2. + /// Set ulong.MaxValue (default) to send to all clients or 0 to send to noone. + /// This field is ignored when sending message to Aardwolf (as a command). + /// + public ulong AuthMask = ulong.MaxValue; + + /// + /// This setting is used to send the message to specific clients (using client ID). + /// Enter new uint[] { 0 } to send to Aardwolf and null to send to all clients (default). + /// + public uint[] Clients = null; + + /// + /// Is this message natural (client entered command or Aardwolf sent message) or + /// is it generated by us, meaning Aardwolf did not send this and client did not enter + /// it as a command. + /// + public readonly bool IsNaturalMessage; + + /// + /// What kind of line ending do we send with this message (default \n\r). + /// + public string LineEnding = "\n\r"; + + /// + /// When was message generated (send time may vary by some milliseconds) + /// + public readonly DateTime Timestamp = DateTime.Now; + + /// + /// Options for message. + /// + public MessageFlags Flags = MessageFlags.None; + } + + [Flags] + public enum MessageFlags + { + None = 0, + + /// + /// This is a GMCP message the main module will be in Msg and the data will be in MsgData. + /// + GMCP = 0x1, + } +} diff --git a/ProxyCore/Messages/.svn/text-base/desktop.ini b/ProxyCore/Messages/.svn/text-base/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/ProxyCore/Messages/.svn/text-base/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/ProxyCore/Messages/.svn/tmp/desktop.ini b/ProxyCore/Messages/.svn/tmp/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/ProxyCore/Messages/.svn/tmp/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/ProxyCore/Messages/.svn/tmp/prop-base/desktop.ini b/ProxyCore/Messages/.svn/tmp/prop-base/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/ProxyCore/Messages/.svn/tmp/prop-base/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/ProxyCore/Messages/.svn/tmp/props/desktop.ini b/ProxyCore/Messages/.svn/tmp/props/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/ProxyCore/Messages/.svn/tmp/props/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/ProxyCore/Messages/.svn/tmp/text-base/desktop.ini b/ProxyCore/Messages/.svn/tmp/text-base/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/ProxyCore/Messages/.svn/tmp/text-base/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/ProxyCore/Messages/Message.cs b/ProxyCore/Messages/Message.cs new file mode 100644 index 0000000..49d33f4 --- /dev/null +++ b/ProxyCore/Messages/Message.cs @@ -0,0 +1,91 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace ProxyCore.Messages +{ + public class Message + { + internal Message(bool isNaturalMessage) + { + IsNaturalMessage = isNaturalMessage; + } + + /// + /// Contents of the message. + /// + public string Msg + { + get + { + return _msg; + } + set + { + _msg = value; + MsgNoColor = _msg == null ? null : Colors.RemoveColors(_msg, false); + } + } + + private string _msg; + + /// + /// If this is set ignore message and send this byte data instead. Color codes + /// will not be parsed by server and this is sent as is. + /// + public byte[] MsgData = null; + + /// + /// This is message but without colors. Used for triggering non-ansi triggers. + /// + internal string MsgNoColor = null; + + /// + /// Which clients should receive the message. This is a mask for security levels. + /// For example value "3" would only send this message to security level 1 and 2. + /// Set ulong.MaxValue (default) to send to all clients or 0 to send to noone. + /// This field is ignored when sending message to Aardwolf (as a command). + /// + public ulong AuthMask = ulong.MaxValue; + + /// + /// This setting is used to send the message to specific clients (using client ID). + /// Enter new uint[] { 0 } to send to Aardwolf and null to send to all clients (default). + /// + public uint[] Clients = null; + + /// + /// Is this message natural (client entered command or Aardwolf sent message) or + /// is it generated by us, meaning Aardwolf did not send this and client did not enter + /// it as a command. + /// + public readonly bool IsNaturalMessage; + + /// + /// What kind of line ending do we send with this message (default \n\r). + /// + public string LineEnding = "\n\r"; + + /// + /// When was message generated (send time may vary by some milliseconds) + /// + public readonly DateTime Timestamp = DateTime.Now; + + /// + /// Options for message. + /// + public MessageFlags Flags = MessageFlags.None; + } + + [Flags] + public enum MessageFlags + { + None = 0, + + /// + /// This is a GMCP message the main module will be in Msg and the data will be in MsgData. + /// + GMCP = 0x1, + } +} diff --git a/ProxyCore/Messages/desktop.ini b/ProxyCore/Messages/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/ProxyCore/Messages/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/ProxyCore/Output/.svn/all-wcprops b/ProxyCore/Output/.svn/all-wcprops new file mode 100644 index 0000000..edd15e4 --- /dev/null +++ b/ProxyCore/Output/.svn/all-wcprops @@ -0,0 +1,23 @@ +K 25 +svn:wc:ra_dav:version-url +V 39 +/svn/!svn/ver/54/trunk/ProxyCore/Output +END +TriggerEntry.cs +K 25 +svn:wc:ra_dav:version-url +V 55 +/svn/!svn/ver/40/trunk/ProxyCore/Output/TriggerEntry.cs +END +TriggerData.cs +K 25 +svn:wc:ra_dav:version-url +V 53 +/svn/!svn/ver/2/trunk/ProxyCore/Output/TriggerData.cs +END +TriggerHandler.cs +K 25 +svn:wc:ra_dav:version-url +V 57 +/svn/!svn/ver/54/trunk/ProxyCore/Output/TriggerHandler.cs +END diff --git a/ProxyCore/Output/.svn/desktop.ini b/ProxyCore/Output/.svn/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/ProxyCore/Output/.svn/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/ProxyCore/Output/.svn/dir-prop-base b/ProxyCore/Output/.svn/dir-prop-base new file mode 100644 index 0000000..f1b96ea --- /dev/null +++ b/ProxyCore/Output/.svn/dir-prop-base @@ -0,0 +1,5 @@ +K 14 +bugtraq:number +V 4 +true +END diff --git a/ProxyCore/Output/.svn/entries b/ProxyCore/Output/.svn/entries new file mode 100644 index 0000000..4bf1932 --- /dev/null +++ b/ProxyCore/Output/.svn/entries @@ -0,0 +1,130 @@ +10 + +dir +58 +http://proxymud.googlecode.com/svn/trunk/ProxyCore/Output +http://proxymud.googlecode.com/svn + + + +2012-02-02T08:38:33.263906Z +54 +default8p@gmail.com +has-props + + + + + + + + + + + + + +8a6e9f07-fe1d-2472-fcf8-0b435762827a + +TriggerData.cs +file + + + + +2016-03-25T22:18:43.188138Z +0d3b660b908fd57e16d0fa2ac14f1fc1 +2012-01-17T10:55:35.805502Z +2 +default8p@gmail.com + + + + + + + + + + + + + + + + + + + + + +3483 + +TriggerHandler.cs +file + + + + +2016-03-25T22:18:43.188138Z +2224e1c4aeda63d93aace92dc537037b +2012-02-02T08:38:33.263906Z +54 +default8p@gmail.com + + + + + + + + + + + + + + + + + + + + + +12669 + +TriggerEntry.cs +file + + + + +2016-03-25T22:18:43.188138Z +462f17031b8eb6511c5fefa7688f64f5 +2012-01-25T09:39:59.831649Z +40 +default8p@gmail.com + + + + + + + + + + + + + + + + + + + + + +2179 + diff --git a/ProxyCore/Output/.svn/prop-base/desktop.ini b/ProxyCore/Output/.svn/prop-base/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/ProxyCore/Output/.svn/prop-base/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/ProxyCore/Output/.svn/props/desktop.ini b/ProxyCore/Output/.svn/props/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/ProxyCore/Output/.svn/props/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/ProxyCore/Output/.svn/text-base/TriggerData.cs.svn-base b/ProxyCore/Output/.svn/text-base/TriggerData.cs.svn-base new file mode 100644 index 0000000..8ca66b5 --- /dev/null +++ b/ProxyCore/Output/.svn/text-base/TriggerData.cs.svn-base @@ -0,0 +1,85 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; +using ProxyCore.Messages; + +namespace ProxyCore.Output +{ + public class TriggerData + { + internal TriggerData() + { + } + + /// + /// Match data. + /// + public Match Match + { + get; + internal set; + } + + /// + /// What we triggered on, you can change this value to replace the text. + /// + public Message Msg; + + /// + /// Custom argument if you registered a trigger to have one. + /// + public int Arg; + + /// + /// Replace matched %0 value with new string. This only works in regex triggers. You can have {%1} - {%n} in the new string for matched data. + /// Use {%%1} to escape. If you use % higher than what was captured then a NULL will be replaced there. + /// For example using %3 when there are only 2 things captured with regex. + /// + /// Example: + /// Line: "@mQuest Points @w: @Y19,361" + /// Pattern: "^@mQuest Points @w: (\s*)@Y([\d,]+)$" + /// Replace: "@mQuest Points @w: {%1}@G{%2}" + /// This would make quest points green in the "worth" command output. Where {%1} inserts the right amount + /// of spaces (what was captured) and {%2} inserts the quest points amount (19,361). + /// + /// New string to replace with. See function summary for help with this. + /// Allow parsing {%n} in the New string or not. If not then string + /// is replaced as is without parsing for arguments. + public void Replace(string New, bool AllowParse) + { + if(Match == null || !Match.Success) + return; + + if(AllowParse) + { + Match m; + if(New.Contains("{%")) // Make fast check first if we want to start messing with regex + { + while((m = _replaceRegex.Match(New)).Success) + { + int i; + if(!int.TryParse(m.Groups[1].Value, out i) || i >= Match.Groups.Count || i < 0) + New = New.Replace(m.Groups[0].Value, "NULL"); + else + New = New.Replace(m.Groups[0].Value, Match.Groups[i].Value); + } + } + if(New.Contains("{%%")) + { + while((m = _replaceRegex2.Match(New)).Success) + { + New = New.Replace(m.Groups[0].Value, "{%" + m.Groups[1].Value + "}"); + } + } + } + + // Don't use replace here because we only want to replace one occurance, wherever it was matched + Msg.Msg = Msg.Msg.Remove(Match.Index, Match.Length).Insert(Match.Index, New); + } + + private static readonly Regex _replaceRegex = new Regex(@"\{%(\d+)\}", RegexOptions.Compiled); + private static readonly Regex _replaceRegex2 = new Regex(@"\{%%(\d+)\}", RegexOptions.Compiled); + } +} diff --git a/ProxyCore/Output/.svn/text-base/TriggerEntry.cs.svn-base b/ProxyCore/Output/.svn/text-base/TriggerEntry.cs.svn-base new file mode 100644 index 0000000..76bfe6d --- /dev/null +++ b/ProxyCore/Output/.svn/text-base/TriggerEntry.cs.svn-base @@ -0,0 +1,66 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; + +namespace ProxyCore.Output +{ + internal class TriggerEntry + { + internal Regex Pattern; + internal string PatternStr; + internal TriggerFunction Function; + internal int Priority; + internal string Name; + internal TriggerFlags Flags; + internal int Arg; + internal string Plugin; + internal List Disabled; + } + + /// + /// This is the function template that will be called when a trigger fires. Return true to gag it - this + /// will also prevent other triggers from triggering on this line. + /// + /// Triggered text data. + /// + public delegate bool TriggerFunction(TriggerData Data); + + [Flags] + public enum TriggerFlags + { + None = 0, + + /// + /// Normal triggers stop after finding the first match in a line, + /// with this flag the trigger repeats for each match in the same line. + /// This only applies if you use regex pattern. + /// + Repeat = 1, + + /// + /// Ignore lower and upper case. This only applies if you use regex pattern. + /// + CaseInsensitive = 2, + + /// + /// Pattern is not regex but instead just raw string. For example if you want + /// to trigger on "@w--> @WTICK @w<--" there's no need to create a regex pattern + /// just insert this string and set this flag in options and the trigger will be MUCH + /// faster. Use regex only where necessary. + /// + NotRegex = 4, + + /// + /// Trigger ignores color codes. If you set this flag you should NOT include any color codes + /// in your trigger pattern. + /// + NonAnsi = 8, + + /// + /// Matching will start from right and go to left. + /// + RightToLeft = 0x10, + } +} diff --git a/ProxyCore/Output/.svn/text-base/TriggerHandler.cs.svn-base b/ProxyCore/Output/.svn/text-base/TriggerHandler.cs.svn-base new file mode 100644 index 0000000..aa7af14 --- /dev/null +++ b/ProxyCore/Output/.svn/text-base/TriggerHandler.cs.svn-base @@ -0,0 +1,345 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; +using ProxyCore.Messages; +using ProxyCore.Scripting; + +namespace ProxyCore.Output +{ + internal static class TriggerHandler + { + static TriggerHandler() + { + } + + private static SortedDictionary> Triggers = new SortedDictionary>(); + internal static Dictionary TriggersName = new Dictionary(); + + internal static void DisableTriggers(string FromPlugin, int MinPriority, int MaxPriority) + { + if(FromPlugin == null) + return; + FromPlugin = FromPlugin.ToLower().Trim(); + if(FromPlugin.Length == 0) + return; + foreach(KeyValuePair> x in Triggers) + { + if(x.Key < MinPriority) + continue; + if(x.Key > MaxPriority) + break; + + foreach(TriggerEntry y in x.Value) + { + if(y.Disabled == null) + y.Disabled = new List(); + if(!y.Disabled.Contains(FromPlugin)) + y.Disabled.Add(FromPlugin); + } + } + } + + internal static void EnableTriggers(string FromPlugin, int MinPriority, int MaxPriority) + { + if(FromPlugin == null) + return; + FromPlugin = FromPlugin.ToLower().Trim(); + if(FromPlugin.Length == 0) + return; + foreach(KeyValuePair> x in Triggers) + { + if(x.Key < MinPriority) + continue; + if(x.Key > MaxPriority) + break; + + foreach(TriggerEntry y in x.Value) + { + if(y.Disabled == null) + continue; + y.Disabled.Remove(FromPlugin); + } + } + } + + /// + /// Register a new trigger. + /// + /// Unique identifier for the trigger. + /// Regex pattern for the trigger. + /// Function that will be called if this trigger fires. + internal static void RegisterTrigger(string Name, string Pattern, TriggerFunction Function) + { + RegisterTrigger(Name, Pattern, Function, TriggerFlags.None); + } + + /// + /// Register a new trigger. + /// + /// Unique identifier for the trigger. + /// Regex pattern for the trigger. + /// Function that will be called if this trigger fires. + /// Options for the trigger. + internal static void RegisterTrigger(string Name, string Pattern, TriggerFunction Function, TriggerFlags Flags) + { + RegisterTrigger(Name, Pattern, Function, Flags, 1000); + } + + /// + /// Register a new trigger. + /// + /// Unique identifier for the trigger. + /// Regex pattern for the trigger. + /// Function that will be called if this trigger fires. + /// Options for the trigger. + /// Lower priority triggers get matched first. Default: 1000 + internal static void RegisterTrigger(string Name, string Pattern, TriggerFunction Function, TriggerFlags Flags, int Priority) + { + RegisterTrigger(Name, Pattern, Function, Flags, Priority, 0, "core"); + } + + /// + /// Register a new trigger. + /// + /// Unique identifier for the trigger. + /// Regex pattern for the trigger. + /// Function that will be called if this trigger fires. + /// Options for the trigger. + /// Lower priority triggers get matched first. Default: 1000 + /// Custom argument to pass to trigger data. + /// From which plugin was this registered. + internal static void RegisterTrigger(string Name, string Pattern, TriggerFunction Function, TriggerFlags Flags, int Priority, int Arg, string Plugin) + { + if(string.IsNullOrEmpty(Pattern) || string.IsNullOrEmpty(Name) || Function == null) + return; + + Name = Name.ToLower().Trim(); + if(Name.Length == 0) + return; + + Regex p = null; + if((Flags & TriggerFlags.NotRegex) == TriggerFlags.None) + { + try + { + RegexOptions op = RegexOptions.None; + if((Flags & TriggerFlags.RightToLeft) != TriggerFlags.None) + op |= RegexOptions.RightToLeft; + if((Flags & TriggerFlags.CaseInsensitive) != TriggerFlags.None) + op |= RegexOptions.IgnoreCase; + p = new Regex(Pattern, op); + } + catch + { + return; + } + } + + TriggerEntry e = new TriggerEntry(); + e.Function = Function; + e.Pattern = p; + e.PatternStr = Pattern; + e.Priority = Priority; + e.Name = Name; + e.Flags = Flags; + e.Arg = Arg; + e.Plugin = Plugin; + + if(TriggersName.ContainsKey(Name)) + Triggers[TriggersName[Name].Priority].Remove(TriggersName[Name]); + + TriggersName[Name] = e; + if(!Triggers.ContainsKey(e.Priority)) + Triggers[e.Priority] = new List(); + Triggers[e.Priority].Add(e); + } + + /// + /// Unregister a trigger by name. + /// + /// Name of the trigger you wish to unregister. + internal static void UnregisterTrigger(string Name) + { + if(Name != null) + Name = Name.ToLower().Trim(); + if(string.IsNullOrEmpty(Name)) + return; + + if(!TriggersName.ContainsKey(Name)) + return; + + Triggers[TriggersName[Name].Priority].Remove(TriggersName[Name]); + TriggersName.Remove(Name); + } + + internal static void HandleText(string Msg, World world) + { + if(!string.IsNullOrEmpty(lastColorCode)) + Msg = lastColorCode + Msg; + lastColorCode = Colors.GetLastColorCode(Msg); + Msg = Colors.RemoveDuplicateColors(Msg); + + Message m = new Message(true); + m.Msg = Msg; + HandleLineRaw(m); + if(m.Msg != null) + { + world._SendMessage(m); + world.lastLine.Add(m.Msg); + while(world.lastLine.Count > 100) + world.lastLine.RemoveAt(0); + } + } + + private static string lastColorCode = ""; + + private static readonly List> gmcpData = + new List>(); + + internal static void HandleGMCP(string Msg) + { + //string origMsg = Msg; + string module; + try + { + int ind = Msg.IndexOf(' '); + if(ind == -1) + { + module = Msg; + Msg = ""; + } + else + { + module = Msg.Substring(0, ind); + Msg = Msg.Substring(ind).Trim(); + } + } + catch + { + return; + } + + if(string.IsNullOrEmpty(module)) + return; + + if(gmcpData.Count != 0) + gmcpData.Clear(); + module = module.ToLower(); + bool res = JSON.Parse(Msg, module, gmcpData); + if(!res) + return; + + if(gmcpData.Count == 0) + HandleGMCP(module, null); + else + { + foreach(KeyValuePair i in gmcpData) + HandleGMCP(i.Key.ToLower().Trim(), i.Value); + } + } + + private static void HandleGMCP(string Module, string Value) + { + Message m = new Message(true); + m.Msg = "$gmcp." + Module + (Value != null ? (" " + Value) : ""); + HandleLineRaw(m); + } + + private static void HandleLineRaw(Message Msg) + { + foreach(KeyValuePair x in PluginMgr.Plugins) + { + try + { + x.Value.OnReceivedLineBefore(Msg); + } + catch(Exception e) + { + Log.Crash(e, x.Key); + } + if(Msg.Msg == null) + return; + } + + foreach(KeyValuePair> x in Triggers) + { + foreach(TriggerEntry y in x.Value) + { + if(y.Disabled != null && y.Disabled.Count != 0) + continue; + + int i = 0; + while(Msg.Msg != null) + { + int o = i; + Match m = null; + if((y.Flags & TriggerFlags.NotRegex) == TriggerFlags.None) + { + if((y.Flags & TriggerFlags.RightToLeft) != TriggerFlags.None) + m = y.Pattern.Match((y.Flags & TriggerFlags.NonAnsi) == TriggerFlags.None ? Msg.Msg : Msg.MsgNoColor); + else + m = y.Pattern.Match((y.Flags & TriggerFlags.NonAnsi) == TriggerFlags.None ? Msg.Msg : Msg.MsgNoColor, i); + if(!m.Success) + break; + } + else if(y.PatternStr != ((y.Flags & TriggerFlags.NonAnsi) == TriggerFlags.None ? Msg.Msg : Msg.MsgNoColor)) + break; + + TriggerData d = new TriggerData(); + d.Match = m; + d.Arg = y.Arg; + d.Msg = Msg; +#if !DEBUG + try + { +#endif + if(y.Function(d)) + { + Msg.Msg = null; + return; + } +#if !DEBUG + } + catch(Exception e) + { + Log.Crash(e, y.Plugin); + } +#endif + + if((y.Flags & TriggerFlags.NotRegex) != TriggerFlags.None) + break; + if((y.Flags & TriggerFlags.RightToLeft) != TriggerFlags.None) + break; + + i = m.Groups[0].Index + m.Groups[0].Length; + if((y.Flags & TriggerFlags.Repeat) == TriggerFlags.None) + break; + + if(i == o) + i++; + } + } + } + + foreach(KeyValuePair x in PluginMgr.Plugins) + { +#if !DEBUG + try + { +#endif + x.Value.OnReceivedLineAfter(Msg); +#if !DEBUG + } + catch(Exception e) + { + Log.Crash(e, x.Key); + } +#endif + if(Msg.Msg == null) + return; + } + } + } +} diff --git a/ProxyCore/Output/.svn/text-base/desktop.ini b/ProxyCore/Output/.svn/text-base/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/ProxyCore/Output/.svn/text-base/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/ProxyCore/Output/.svn/tmp/desktop.ini b/ProxyCore/Output/.svn/tmp/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/ProxyCore/Output/.svn/tmp/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/ProxyCore/Output/.svn/tmp/prop-base/desktop.ini b/ProxyCore/Output/.svn/tmp/prop-base/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/ProxyCore/Output/.svn/tmp/prop-base/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/ProxyCore/Output/.svn/tmp/props/desktop.ini b/ProxyCore/Output/.svn/tmp/props/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/ProxyCore/Output/.svn/tmp/props/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/ProxyCore/Output/.svn/tmp/text-base/desktop.ini b/ProxyCore/Output/.svn/tmp/text-base/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/ProxyCore/Output/.svn/tmp/text-base/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/ProxyCore/Output/TriggerData.cs b/ProxyCore/Output/TriggerData.cs new file mode 100644 index 0000000..8ca66b5 --- /dev/null +++ b/ProxyCore/Output/TriggerData.cs @@ -0,0 +1,85 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; +using ProxyCore.Messages; + +namespace ProxyCore.Output +{ + public class TriggerData + { + internal TriggerData() + { + } + + /// + /// Match data. + /// + public Match Match + { + get; + internal set; + } + + /// + /// What we triggered on, you can change this value to replace the text. + /// + public Message Msg; + + /// + /// Custom argument if you registered a trigger to have one. + /// + public int Arg; + + /// + /// Replace matched %0 value with new string. This only works in regex triggers. You can have {%1} - {%n} in the new string for matched data. + /// Use {%%1} to escape. If you use % higher than what was captured then a NULL will be replaced there. + /// For example using %3 when there are only 2 things captured with regex. + /// + /// Example: + /// Line: "@mQuest Points @w: @Y19,361" + /// Pattern: "^@mQuest Points @w: (\s*)@Y([\d,]+)$" + /// Replace: "@mQuest Points @w: {%1}@G{%2}" + /// This would make quest points green in the "worth" command output. Where {%1} inserts the right amount + /// of spaces (what was captured) and {%2} inserts the quest points amount (19,361). + /// + /// New string to replace with. See function summary for help with this. + /// Allow parsing {%n} in the New string or not. If not then string + /// is replaced as is without parsing for arguments. + public void Replace(string New, bool AllowParse) + { + if(Match == null || !Match.Success) + return; + + if(AllowParse) + { + Match m; + if(New.Contains("{%")) // Make fast check first if we want to start messing with regex + { + while((m = _replaceRegex.Match(New)).Success) + { + int i; + if(!int.TryParse(m.Groups[1].Value, out i) || i >= Match.Groups.Count || i < 0) + New = New.Replace(m.Groups[0].Value, "NULL"); + else + New = New.Replace(m.Groups[0].Value, Match.Groups[i].Value); + } + } + if(New.Contains("{%%")) + { + while((m = _replaceRegex2.Match(New)).Success) + { + New = New.Replace(m.Groups[0].Value, "{%" + m.Groups[1].Value + "}"); + } + } + } + + // Don't use replace here because we only want to replace one occurance, wherever it was matched + Msg.Msg = Msg.Msg.Remove(Match.Index, Match.Length).Insert(Match.Index, New); + } + + private static readonly Regex _replaceRegex = new Regex(@"\{%(\d+)\}", RegexOptions.Compiled); + private static readonly Regex _replaceRegex2 = new Regex(@"\{%%(\d+)\}", RegexOptions.Compiled); + } +} diff --git a/ProxyCore/Output/TriggerEntry.cs b/ProxyCore/Output/TriggerEntry.cs new file mode 100644 index 0000000..76bfe6d --- /dev/null +++ b/ProxyCore/Output/TriggerEntry.cs @@ -0,0 +1,66 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; + +namespace ProxyCore.Output +{ + internal class TriggerEntry + { + internal Regex Pattern; + internal string PatternStr; + internal TriggerFunction Function; + internal int Priority; + internal string Name; + internal TriggerFlags Flags; + internal int Arg; + internal string Plugin; + internal List Disabled; + } + + /// + /// This is the function template that will be called when a trigger fires. Return true to gag it - this + /// will also prevent other triggers from triggering on this line. + /// + /// Triggered text data. + /// + public delegate bool TriggerFunction(TriggerData Data); + + [Flags] + public enum TriggerFlags + { + None = 0, + + /// + /// Normal triggers stop after finding the first match in a line, + /// with this flag the trigger repeats for each match in the same line. + /// This only applies if you use regex pattern. + /// + Repeat = 1, + + /// + /// Ignore lower and upper case. This only applies if you use regex pattern. + /// + CaseInsensitive = 2, + + /// + /// Pattern is not regex but instead just raw string. For example if you want + /// to trigger on "@w--> @WTICK @w<--" there's no need to create a regex pattern + /// just insert this string and set this flag in options and the trigger will be MUCH + /// faster. Use regex only where necessary. + /// + NotRegex = 4, + + /// + /// Trigger ignores color codes. If you set this flag you should NOT include any color codes + /// in your trigger pattern. + /// + NonAnsi = 8, + + /// + /// Matching will start from right and go to left. + /// + RightToLeft = 0x10, + } +} diff --git a/ProxyCore/Output/TriggerHandler.cs b/ProxyCore/Output/TriggerHandler.cs new file mode 100644 index 0000000..aa7af14 --- /dev/null +++ b/ProxyCore/Output/TriggerHandler.cs @@ -0,0 +1,345 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; +using ProxyCore.Messages; +using ProxyCore.Scripting; + +namespace ProxyCore.Output +{ + internal static class TriggerHandler + { + static TriggerHandler() + { + } + + private static SortedDictionary> Triggers = new SortedDictionary>(); + internal static Dictionary TriggersName = new Dictionary(); + + internal static void DisableTriggers(string FromPlugin, int MinPriority, int MaxPriority) + { + if(FromPlugin == null) + return; + FromPlugin = FromPlugin.ToLower().Trim(); + if(FromPlugin.Length == 0) + return; + foreach(KeyValuePair> x in Triggers) + { + if(x.Key < MinPriority) + continue; + if(x.Key > MaxPriority) + break; + + foreach(TriggerEntry y in x.Value) + { + if(y.Disabled == null) + y.Disabled = new List(); + if(!y.Disabled.Contains(FromPlugin)) + y.Disabled.Add(FromPlugin); + } + } + } + + internal static void EnableTriggers(string FromPlugin, int MinPriority, int MaxPriority) + { + if(FromPlugin == null) + return; + FromPlugin = FromPlugin.ToLower().Trim(); + if(FromPlugin.Length == 0) + return; + foreach(KeyValuePair> x in Triggers) + { + if(x.Key < MinPriority) + continue; + if(x.Key > MaxPriority) + break; + + foreach(TriggerEntry y in x.Value) + { + if(y.Disabled == null) + continue; + y.Disabled.Remove(FromPlugin); + } + } + } + + /// + /// Register a new trigger. + /// + /// Unique identifier for the trigger. + /// Regex pattern for the trigger. + /// Function that will be called if this trigger fires. + internal static void RegisterTrigger(string Name, string Pattern, TriggerFunction Function) + { + RegisterTrigger(Name, Pattern, Function, TriggerFlags.None); + } + + /// + /// Register a new trigger. + /// + /// Unique identifier for the trigger. + /// Regex pattern for the trigger. + /// Function that will be called if this trigger fires. + /// Options for the trigger. + internal static void RegisterTrigger(string Name, string Pattern, TriggerFunction Function, TriggerFlags Flags) + { + RegisterTrigger(Name, Pattern, Function, Flags, 1000); + } + + /// + /// Register a new trigger. + /// + /// Unique identifier for the trigger. + /// Regex pattern for the trigger. + /// Function that will be called if this trigger fires. + /// Options for the trigger. + /// Lower priority triggers get matched first. Default: 1000 + internal static void RegisterTrigger(string Name, string Pattern, TriggerFunction Function, TriggerFlags Flags, int Priority) + { + RegisterTrigger(Name, Pattern, Function, Flags, Priority, 0, "core"); + } + + /// + /// Register a new trigger. + /// + /// Unique identifier for the trigger. + /// Regex pattern for the trigger. + /// Function that will be called if this trigger fires. + /// Options for the trigger. + /// Lower priority triggers get matched first. Default: 1000 + /// Custom argument to pass to trigger data. + /// From which plugin was this registered. + internal static void RegisterTrigger(string Name, string Pattern, TriggerFunction Function, TriggerFlags Flags, int Priority, int Arg, string Plugin) + { + if(string.IsNullOrEmpty(Pattern) || string.IsNullOrEmpty(Name) || Function == null) + return; + + Name = Name.ToLower().Trim(); + if(Name.Length == 0) + return; + + Regex p = null; + if((Flags & TriggerFlags.NotRegex) == TriggerFlags.None) + { + try + { + RegexOptions op = RegexOptions.None; + if((Flags & TriggerFlags.RightToLeft) != TriggerFlags.None) + op |= RegexOptions.RightToLeft; + if((Flags & TriggerFlags.CaseInsensitive) != TriggerFlags.None) + op |= RegexOptions.IgnoreCase; + p = new Regex(Pattern, op); + } + catch + { + return; + } + } + + TriggerEntry e = new TriggerEntry(); + e.Function = Function; + e.Pattern = p; + e.PatternStr = Pattern; + e.Priority = Priority; + e.Name = Name; + e.Flags = Flags; + e.Arg = Arg; + e.Plugin = Plugin; + + if(TriggersName.ContainsKey(Name)) + Triggers[TriggersName[Name].Priority].Remove(TriggersName[Name]); + + TriggersName[Name] = e; + if(!Triggers.ContainsKey(e.Priority)) + Triggers[e.Priority] = new List(); + Triggers[e.Priority].Add(e); + } + + /// + /// Unregister a trigger by name. + /// + /// Name of the trigger you wish to unregister. + internal static void UnregisterTrigger(string Name) + { + if(Name != null) + Name = Name.ToLower().Trim(); + if(string.IsNullOrEmpty(Name)) + return; + + if(!TriggersName.ContainsKey(Name)) + return; + + Triggers[TriggersName[Name].Priority].Remove(TriggersName[Name]); + TriggersName.Remove(Name); + } + + internal static void HandleText(string Msg, World world) + { + if(!string.IsNullOrEmpty(lastColorCode)) + Msg = lastColorCode + Msg; + lastColorCode = Colors.GetLastColorCode(Msg); + Msg = Colors.RemoveDuplicateColors(Msg); + + Message m = new Message(true); + m.Msg = Msg; + HandleLineRaw(m); + if(m.Msg != null) + { + world._SendMessage(m); + world.lastLine.Add(m.Msg); + while(world.lastLine.Count > 100) + world.lastLine.RemoveAt(0); + } + } + + private static string lastColorCode = ""; + + private static readonly List> gmcpData = + new List>(); + + internal static void HandleGMCP(string Msg) + { + //string origMsg = Msg; + string module; + try + { + int ind = Msg.IndexOf(' '); + if(ind == -1) + { + module = Msg; + Msg = ""; + } + else + { + module = Msg.Substring(0, ind); + Msg = Msg.Substring(ind).Trim(); + } + } + catch + { + return; + } + + if(string.IsNullOrEmpty(module)) + return; + + if(gmcpData.Count != 0) + gmcpData.Clear(); + module = module.ToLower(); + bool res = JSON.Parse(Msg, module, gmcpData); + if(!res) + return; + + if(gmcpData.Count == 0) + HandleGMCP(module, null); + else + { + foreach(KeyValuePair i in gmcpData) + HandleGMCP(i.Key.ToLower().Trim(), i.Value); + } + } + + private static void HandleGMCP(string Module, string Value) + { + Message m = new Message(true); + m.Msg = "$gmcp." + Module + (Value != null ? (" " + Value) : ""); + HandleLineRaw(m); + } + + private static void HandleLineRaw(Message Msg) + { + foreach(KeyValuePair x in PluginMgr.Plugins) + { + try + { + x.Value.OnReceivedLineBefore(Msg); + } + catch(Exception e) + { + Log.Crash(e, x.Key); + } + if(Msg.Msg == null) + return; + } + + foreach(KeyValuePair> x in Triggers) + { + foreach(TriggerEntry y in x.Value) + { + if(y.Disabled != null && y.Disabled.Count != 0) + continue; + + int i = 0; + while(Msg.Msg != null) + { + int o = i; + Match m = null; + if((y.Flags & TriggerFlags.NotRegex) == TriggerFlags.None) + { + if((y.Flags & TriggerFlags.RightToLeft) != TriggerFlags.None) + m = y.Pattern.Match((y.Flags & TriggerFlags.NonAnsi) == TriggerFlags.None ? Msg.Msg : Msg.MsgNoColor); + else + m = y.Pattern.Match((y.Flags & TriggerFlags.NonAnsi) == TriggerFlags.None ? Msg.Msg : Msg.MsgNoColor, i); + if(!m.Success) + break; + } + else if(y.PatternStr != ((y.Flags & TriggerFlags.NonAnsi) == TriggerFlags.None ? Msg.Msg : Msg.MsgNoColor)) + break; + + TriggerData d = new TriggerData(); + d.Match = m; + d.Arg = y.Arg; + d.Msg = Msg; +#if !DEBUG + try + { +#endif + if(y.Function(d)) + { + Msg.Msg = null; + return; + } +#if !DEBUG + } + catch(Exception e) + { + Log.Crash(e, y.Plugin); + } +#endif + + if((y.Flags & TriggerFlags.NotRegex) != TriggerFlags.None) + break; + if((y.Flags & TriggerFlags.RightToLeft) != TriggerFlags.None) + break; + + i = m.Groups[0].Index + m.Groups[0].Length; + if((y.Flags & TriggerFlags.Repeat) == TriggerFlags.None) + break; + + if(i == o) + i++; + } + } + } + + foreach(KeyValuePair x in PluginMgr.Plugins) + { +#if !DEBUG + try + { +#endif + x.Value.OnReceivedLineAfter(Msg); +#if !DEBUG + } + catch(Exception e) + { + Log.Crash(e, x.Key); + } +#endif + if(Msg.Msg == null) + return; + } + } + } +} diff --git a/ProxyCore/Output/desktop.ini b/ProxyCore/Output/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/ProxyCore/Output/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/ProxyCore/Properties/.svn/all-wcprops b/ProxyCore/Properties/.svn/all-wcprops new file mode 100644 index 0000000..ffb4463 --- /dev/null +++ b/ProxyCore/Properties/.svn/all-wcprops @@ -0,0 +1,11 @@ +K 25 +svn:wc:ra_dav:version-url +V 42 +/svn/!svn/ver/2/trunk/ProxyCore/Properties +END +AssemblyInfo.cs +K 25 +svn:wc:ra_dav:version-url +V 58 +/svn/!svn/ver/2/trunk/ProxyCore/Properties/AssemblyInfo.cs +END diff --git a/ProxyCore/Properties/.svn/desktop.ini b/ProxyCore/Properties/.svn/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/ProxyCore/Properties/.svn/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/ProxyCore/Properties/.svn/dir-prop-base b/ProxyCore/Properties/.svn/dir-prop-base new file mode 100644 index 0000000..f1b96ea --- /dev/null +++ b/ProxyCore/Properties/.svn/dir-prop-base @@ -0,0 +1,5 @@ +K 14 +bugtraq:number +V 4 +true +END diff --git a/ProxyCore/Properties/.svn/entries b/ProxyCore/Properties/.svn/entries new file mode 100644 index 0000000..da997e1 --- /dev/null +++ b/ProxyCore/Properties/.svn/entries @@ -0,0 +1,62 @@ +10 + +dir +58 +http://proxymud.googlecode.com/svn/trunk/ProxyCore/Properties +http://proxymud.googlecode.com/svn + + + +2012-01-17T10:55:35.805502Z +2 +default8p@gmail.com +has-props + + + + + + + + + + + + + +8a6e9f07-fe1d-2472-fcf8-0b435762827a + +AssemblyInfo.cs +file + + + + +2016-03-25T22:18:43.228138Z +3655dd83493b526d4a7076bf3acfd0ed +2012-01-17T10:55:35.805502Z +2 +default8p@gmail.com + + + + + + + + + + + + + + + + + + + + + +1448 + diff --git a/ProxyCore/Properties/.svn/prop-base/desktop.ini b/ProxyCore/Properties/.svn/prop-base/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/ProxyCore/Properties/.svn/prop-base/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/ProxyCore/Properties/.svn/props/desktop.ini b/ProxyCore/Properties/.svn/props/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/ProxyCore/Properties/.svn/props/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/ProxyCore/Properties/.svn/text-base/AssemblyInfo.cs.svn-base b/ProxyCore/Properties/.svn/text-base/AssemblyInfo.cs.svn-base new file mode 100644 index 0000000..aef339e --- /dev/null +++ b/ProxyCore/Properties/.svn/text-base/AssemblyInfo.cs.svn-base @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("ProxyCore")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("Microsoft")] +[assembly: AssemblyProduct("ProxyCore")] +[assembly: AssemblyCopyright("Copyright © Microsoft 2011")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("7d78ddc1-7213-4910-ba70-2a974d42ac5c")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/ProxyCore/Properties/.svn/text-base/desktop.ini b/ProxyCore/Properties/.svn/text-base/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/ProxyCore/Properties/.svn/text-base/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/ProxyCore/Properties/.svn/tmp/desktop.ini b/ProxyCore/Properties/.svn/tmp/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/ProxyCore/Properties/.svn/tmp/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/ProxyCore/Properties/.svn/tmp/prop-base/desktop.ini b/ProxyCore/Properties/.svn/tmp/prop-base/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/ProxyCore/Properties/.svn/tmp/prop-base/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/ProxyCore/Properties/.svn/tmp/props/desktop.ini b/ProxyCore/Properties/.svn/tmp/props/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/ProxyCore/Properties/.svn/tmp/props/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/ProxyCore/Properties/.svn/tmp/text-base/desktop.ini b/ProxyCore/Properties/.svn/tmp/text-base/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/ProxyCore/Properties/.svn/tmp/text-base/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/ProxyCore/Properties/AssemblyInfo.cs b/ProxyCore/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..aef339e --- /dev/null +++ b/ProxyCore/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("ProxyCore")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("Microsoft")] +[assembly: AssemblyProduct("ProxyCore")] +[assembly: AssemblyCopyright("Copyright © Microsoft 2011")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("7d78ddc1-7213-4910-ba70-2a974d42ac5c")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/ProxyCore/Properties/desktop.ini b/ProxyCore/Properties/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/ProxyCore/Properties/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/ProxyCore/ProxyCore.csproj b/ProxyCore/ProxyCore.csproj new file mode 100644 index 0000000..801f5a4 --- /dev/null +++ b/ProxyCore/ProxyCore.csproj @@ -0,0 +1,112 @@ + + + + Debug + AnyCPU + 9.0.30729 + 2.0 + {7863FE6F-E27F-4DBA-B2CC-EDEFE4AE8382} + Library + Properties + ProxyCore + ProxyCore + v3.5 + 512 + + + + + 3.5 + publish\ + true + Disk + false + Foreground + 7 + Days + false + false + true + 0 + 1.0.0.%2a + false + false + true + + + true + full + false + ..\..\..\..\Desktop\MushProxy-Build\ + DEBUG;TRACE + prompt + 4 + bin\ProxyCore.XML + + + pdbonly + true + ..\..\..\..\Desktop\MushProxy-Build\ + TRACE + prompt + 4 + + + + + + False + ..\Resources\Jayrock.dll + + + False + ..\Resources\Jayrock.Json.dll + + + + 3.5 + + + 3.5 + + + 3.5 + + + + + + + + + + + + + + + + + + + + + + + + + + False + .NET Framework 3.5 SP1 + true + + + + + \ No newline at end of file diff --git a/ProxyCore/Scripting/.svn/all-wcprops b/ProxyCore/Scripting/.svn/all-wcprops new file mode 100644 index 0000000..d93a56a --- /dev/null +++ b/ProxyCore/Scripting/.svn/all-wcprops @@ -0,0 +1,17 @@ +K 25 +svn:wc:ra_dav:version-url +V 42 +/svn/!svn/ver/40/trunk/ProxyCore/Scripting +END +Plugin.cs +K 25 +svn:wc:ra_dav:version-url +V 52 +/svn/!svn/ver/40/trunk/ProxyCore/Scripting/Plugin.cs +END +PluginMgr.cs +K 25 +svn:wc:ra_dav:version-url +V 54 +/svn/!svn/ver/2/trunk/ProxyCore/Scripting/PluginMgr.cs +END diff --git a/ProxyCore/Scripting/.svn/desktop.ini b/ProxyCore/Scripting/.svn/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/ProxyCore/Scripting/.svn/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/ProxyCore/Scripting/.svn/dir-prop-base b/ProxyCore/Scripting/.svn/dir-prop-base new file mode 100644 index 0000000..f1b96ea --- /dev/null +++ b/ProxyCore/Scripting/.svn/dir-prop-base @@ -0,0 +1,5 @@ +K 14 +bugtraq:number +V 4 +true +END diff --git a/ProxyCore/Scripting/.svn/entries b/ProxyCore/Scripting/.svn/entries new file mode 100644 index 0000000..cef0225 --- /dev/null +++ b/ProxyCore/Scripting/.svn/entries @@ -0,0 +1,96 @@ +10 + +dir +58 +http://proxymud.googlecode.com/svn/trunk/ProxyCore/Scripting +http://proxymud.googlecode.com/svn + + + +2012-01-25T09:39:59.831649Z +40 +default8p@gmail.com +has-props + + + + + + + + + + + + + +8a6e9f07-fe1d-2472-fcf8-0b435762827a + +PluginMgr.cs +file + + + + +2016-03-25T22:18:43.196138Z +ed07d3317b48945bad782841c613efd7 +2012-01-17T10:55:35.805502Z +2 +default8p@gmail.com + + + + + + + + + + + + + + + + + + + + + +4277 + +Plugin.cs +file + + + + +2016-03-25T22:18:43.196138Z +967aa696b3d2aac48f62173975174294 +2012-01-25T09:39:59.831649Z +40 +default8p@gmail.com + + + + + + + + + + + + + + + + + + + + + +19884 + diff --git a/ProxyCore/Scripting/.svn/prop-base/desktop.ini b/ProxyCore/Scripting/.svn/prop-base/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/ProxyCore/Scripting/.svn/prop-base/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/ProxyCore/Scripting/.svn/props/desktop.ini b/ProxyCore/Scripting/.svn/props/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/ProxyCore/Scripting/.svn/props/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/ProxyCore/Scripting/.svn/text-base/Plugin.cs.svn-base b/ProxyCore/Scripting/.svn/text-base/Plugin.cs.svn-base new file mode 100644 index 0000000..4e4ac73 --- /dev/null +++ b/ProxyCore/Scripting/.svn/text-base/Plugin.cs.svn-base @@ -0,0 +1,400 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using ProxyCore.Output; +using System.Text.RegularExpressions; +using ProxyCore.Input; + +namespace ProxyCore.Scripting +{ + public class Plugin + { + protected Plugin(string keyword, string name) + { + Keyword = keyword; + Name = name; + } + + /// + /// Set this to be your configuration file if you want your plugin to have one. This is optional. + /// + public ConfigFile Config + { + get; + protected set; + } + + /// + /// Name of your plugin. You must set this or your plugin will not be loaded. + /// + public readonly string Name; + + /// + /// This is the keyword for your plugin. You must set this or your plugin will not be loaded. + /// This must be unique. If two or more plugins with the same keyword are found then the plugin + /// with the highest version number is loaded. + /// + public readonly string Keyword; + + /// + /// Creator of the plugin, this is your name / character's name. This is optional. + /// + public string Author + { + get; + protected set; + } + + /// + /// Version of your plugin. This is optional. + /// + public int Version + { + get; + protected set; + } + + /// + /// Description about your plugin. You should explain here what it does and how to handle it. + /// This will be displayed if user requests information about your plugin. This is optional. + /// + public string Description + { + get; + protected set; + } + + /// + /// Enter a website for this plugin if you wish. Mostly used to see documentation and updates. + /// + public string Website + { + get; + protected set; + } + + /// + /// Enter the URL for update checking txt file. For example "www.duckbat.com/plugins/update.moons.txt". + /// In the text file enter the number of last version. For example whole contents of the txt file can be "3". + /// Indicating that the last version for this plugin is 3. If version is greater than user's version and + /// they have update checking on then they will be notified that there is a more up to date version out there. + /// + public string UpdateUrl + { + get; + protected set; + } + + /// + /// Does this plugin require a certain version of core? Set this if there was an update and your plugin requires it. + /// Plugin is not loaded if an older version core than this is used and user will be notified. + /// + public int RequiredCoreVersion + { + get; + protected set; + } + + /// + /// Register a new trigger. + /// + /// Unique identifier for the trigger. + /// Regex pattern for the trigger. + /// Function that will be called if this trigger fires. + protected void RegisterTrigger(string Name, string Pattern, TriggerFunction Function) + { + RegisterTrigger(Name, Pattern, Function, TriggerFlags.None); + } + + /// + /// Register a new trigger. + /// + /// Unique identifier for the trigger. + /// Regex pattern for the trigger. + /// Function that will be called if this trigger fires. + /// Options for the trigger. + protected void RegisterTrigger(string Name, string Pattern, TriggerFunction Function, TriggerFlags Flags) + { + RegisterTrigger(Name, Pattern, Function, Flags, 1000); + } + + /// + /// Register a new trigger. + /// + /// Unique identifier for the trigger. + /// Regex pattern for the trigger. + /// Function that will be called if this trigger fires. + /// Options for the trigger. + /// Lower priority triggers get matched first. + protected void RegisterTrigger(string Name, string Pattern, TriggerFunction Function, TriggerFlags Flags, int Priority) + { + RegisterTrigger(Name, Pattern, Function, Flags, Priority, 0); + } + + /// + /// Register a new trigger. + /// + /// Unique identifier for the trigger. + /// Regex pattern for the trigger. + /// Function that will be called if this trigger fires. + /// Options for the trigger. + /// Lower priority triggers get matched first. + /// Custom argument that will be passed to trigger data. + protected void RegisterTrigger(string Name, string Pattern, TriggerFunction Function, TriggerFlags Flags, int Priority, int Arg) + { + TriggerHandler.RegisterTrigger(Keyword.ToLower().Trim() + "." + Name, Pattern, Function, Flags, Priority, Arg, Keyword.ToLower().Trim()); + } + + /// + /// Unregister a trigger by name. + /// + /// Name of the trigger you wish to unregister. + protected void UnregisterTrigger(string Name) + { + TriggerHandler.UnregisterTrigger(Keyword.ToLower().Trim() + "." + Name); + } + + /// + /// Register a new command or overwrite a previous one. + /// + /// Command to register. + /// Arguments to match (regex pattern). This can be set to null or empty string + /// if you don't want to capture anything or plan to do so in the function yourself. + /// Function of command. + protected void RegisterCommand(string Cmd, string Args, CmdFunction f) + { + RegisterCommand(Cmd, Args, f, 0); + } + + /// + /// Register a new command or overwrite a previous one. + /// + /// Command to register. + /// Arguments to match (regex pattern). This can be set to null or empty string + /// if you don't want to capture anything or plan to do so in the function yourself. + /// Function of command. + /// Minimum length of command typed required to activate. For example if command is "plugins" and this is 6 then "plugin" and "plugins" both activate this command but "plugi" won't. Enter 0 to disable this behaviour. + protected void RegisterCommand(string Cmd, string Args, CmdFunction f, int MinLength) + { + RegisterCommand(Cmd, Args, f, MinLength, CMDFlags.None); + } + + /// + /// Register a new command or overwrite a previous one. + /// + /// Command to register. + /// Arguments to match (regex pattern). This can be set to null or empty string + /// if you don't want to capture anything or plan to do so in the function yourself. + /// Function of command. + /// Minimum length of command typed required to activate. For example if command is "plugins" and this is 6 then "plugin" and "plugins" both activate this command but "plugi" won't. Enter 0 to disable this behaviour. + /// Options for command. + protected void RegisterCommand(string Cmd, string Args, CmdFunction f, int MinLength, CMDFlags flags) + { + RegisterCommand(Cmd, Args, f, MinLength, flags, null); + } + + /// + /// Register a new command or overwrite a previous one. + /// + /// Command to register. + /// Arguments to match (regex pattern). This can be set to null or empty string + /// if you don't want to capture anything or plan to do so in the function yourself. + /// Function of command. + /// Minimum length of command typed required to activate. For example if command is "plugins" and this is 6 then "plugin" and "plugins" both activate this command but "plugi" won't. Enter 0 to disable this behaviour. + /// Options for command. + /// Parent command (if you want to create a subcommand). You can enter commands separated with space if it's nested. + protected void RegisterCommand(string Cmd, string Args, CmdFunction f, int MinLength, CMDFlags flags, string parent) + { + RegisterCommand(Cmd, Args, f, MinLength, flags, parent, 0); + } + + /// + /// Register a new command or overwrite a previous one. + /// + /// Command to register. + /// Arguments to match (regex pattern). This can be set to null or empty string + /// if you don't want to capture anything or plan to do so in the function yourself. + /// Function of command. + /// Minimum length of command typed required to activate. For example if command is "plugins" and this is 6 then "plugin" and "plugins" both activate this command but "plugi" won't. Enter 0 to disable this behaviour. + /// Options for command. + /// Parent command (if you want to create a subcommand). You can enter commands separated with space if it's nested. + /// Custom argument to pass to function handler. This way you can register multiple commands to a same + /// function handler only differentiating them with this custom argument. + protected void RegisterCommand(string Cmd, string Args, CmdFunction f, int MinLength, CMDFlags flags, string parent, int Arg) + { + RegisterCommand(Cmd, Args, f, MinLength, flags, parent, Arg, ulong.MaxValue); + } + + /// + /// Register a new command or overwrite a previous one. + /// + /// Command to register. + /// Arguments to match (regex pattern). This can be set to null or empty string + /// if you don't want to capture anything or plan to do so in the function yourself. + /// Function of command. + /// Options for command. + /// Parent command (if you want to create a subcommand). You can enter commands separated with space if it's nested. + /// Custom argument to pass to function handler. This way you can register multiple commands to a same + /// function handler only differentiating them with this custom argument. + /// Mask of allowed auth levels to access this command. Default ulong.MaxValue (meaning all auth levels are allowed). + /// Enter 3 for example to allow only auth level 1 and 2 to access this command. + /// Minimum length of command typed required to activate. For example if command is "plugins" and this is 6 then "plugin" and "plugins" both activate this command but "plugi" won't. Enter 0 to disable this behaviour. + protected void RegisterCommand(string Cmd, string Args, CmdFunction f, int MinLength, CMDFlags flags, string parent, int Arg, ulong AuthMask) + { + InputHandler.RegisterCommand(Cmd, Args, f, flags, parent, Arg, AuthMask, Keyword.ToLower().Trim(), MinLength); + } + + /// + /// Unregister a command. + /// + /// Command to unregister. If you want to unregister a nested command + /// separate commands with a space. + protected void UnregisterCommand(string Cmd) + { + InputHandler.UnregisterCommand(Cmd); + } + + /// + /// This will be called when character enters the game. Either by log in or reconnect. + /// + public virtual void OnLogin() + { + } + + /// + /// This will be called when we disconnect from Aardwolf. + /// + public virtual void OnDisconnect() + { + } + + /// + /// This will be called when we connect to Aardwolf. + /// + public virtual void OnConnect() + { + } + + /// + /// This is called when program shuts down. Write any code you need to shut down your plugin. + /// + public virtual void Shutdown() + { + } + + /// + /// This is called on every loop of world update. You can use it as your main loop for + /// the plugin if you need one. + /// + /// Current time since program startup. + public virtual void Update(long msTime) + { + } + + /// + /// This is called when we receive a line from MUD. It is called AFTER triggers are done with it. If + /// a trigger gagged the line this will not be called. + /// + /// + public virtual void OnReceivedLineAfter(Messages.Message Msg) + { + } + + /// + /// This is called when we receive a line from MUD. It is called BEFORE triggers are done with it. + /// + /// + public virtual void OnReceivedLineBefore(Messages.Message Msg) + { + } + + /// + /// This is called when user enters a command and inputhandler did not handle the command. So it + /// is called AFTER we check for aliases and commands and we are about to send command to MUD. + /// + /// Command that was entered. You can change this in the function. If you set null + /// then nothing will be sent to MUD. + /// Client who entered the command. If this is 0 it was executed from a plugin. + /// Auth level of who entered the command. + public virtual void OnEnteredCommandAfter(ref string Msg, uint ClientId, int AuthLevel) + { + } + + /// + /// This is called when user enters a command. It is called BEFORE we check for aliases and commands. + /// + /// Command that was entered. You can change this in the function. If you set null + /// then nothing will be sent to MUD and nothing will be checked for aliases or commands. + /// Client who entered the command. If this is 0 it was executed from a plugin. + /// Auth level of who entered the command. + public virtual void OnEnteredCommandBefore(ref string Msg, uint ClientId, int AuthLevel) + { + } + + /// + /// Enter required player config options here. This will be displayed if user requests info about a plugin. + /// For example you may enter here "echocommands ON" and "statmon ON" etc. Whatever your plugin requires. + /// This doesn't actually change the settings in game it is only for plugin info command. + /// + public readonly List RequiredPlayerConfig = new List(); + + /// + /// This is the class name of script. For example moons has this set to "MoonScript.MoonScript". + /// Only needed by developers who want to use another plugin in their plugin. + /// + internal string ClassName; + + /// + /// Called when we load a configuration file. + /// + /// Did the loading succeed? If not then the config file wasn't present and we created a new one. + public virtual void OnLoadedConfig(bool Success) + { + } + + /// + /// Disable all triggers with this priority. Disabling triggers from a plugin will make them not work until + /// you enable them from the same plugin again. If triggers have been disabled from multiple plugins then + /// all plugins will have to enable them again until they start working. Disabling triggers will make all + /// triggers with this priority to not work not only triggers in current plugin! + /// + /// Priority of triggers to disable. + protected void DisableTriggers(int Priority) + { + DisableTriggers(Priority, Priority); + } + + /// + /// Disable all triggers with this priority. Disabling triggers from a plugin will make them not work until + /// you enable them from the same plugin again. If triggers have been disabled from multiple plugins then + /// all plugins will have to enable them again until they start working. Disabling triggers will make all + /// triggers with this priority to not work not only triggers in current plugin! + /// + /// Minimum priority of triggers to disable. + /// Maximum priority of triggers to disable. + protected void DisableTriggers(int MinPriority, int MaxPriority) + { + TriggerHandler.DisableTriggers(Keyword, MinPriority, MaxPriority); + } + + /// + /// Enable all previously disabled triggers with this priority. + /// + /// Priority of triggers to enable. + protected void EnableTriggers(int Priority) + { + EnableTriggers(Priority, Priority); + } + + /// + /// Enable all previously disabled triggers with this priority. + /// + /// Minimum priority of triggers to enable. + /// Maximum priority of triggers to enable. + protected void EnableTriggers(int MinPriority, int MaxPriority) + { + TriggerHandler.EnableTriggers(Keyword, MinPriority, MaxPriority); + } + } +} diff --git a/ProxyCore/Scripting/.svn/text-base/PluginMgr.cs.svn-base b/ProxyCore/Scripting/.svn/text-base/PluginMgr.cs.svn-base new file mode 100644 index 0000000..75ba26a --- /dev/null +++ b/ProxyCore/Scripting/.svn/text-base/PluginMgr.cs.svn-base @@ -0,0 +1,103 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.IO; +using System.Reflection; + +namespace ProxyCore.Scripting +{ + public static class PluginMgr + { + internal static void LoadAll() + { + if(Plugins.Count != 0) + return; + + try + { + if(!Directory.Exists("plugins")) + { + Directory.CreateDirectory("plugins"); + return; + } + } + catch + { + return; + } + + string[] files = Directory.GetFiles("plugins", "*.dll"); + + if(files.Length != 0) + { + foreach(string file in files) + { + try + { + Assembly assembly = Assembly.LoadFrom(Path.GetFullPath(file)); + foreach(Type type in assembly.GetTypes()) + { + if(!type.IsClass || type.IsNotPublic) + continue; + + if(type.BaseType == typeof(Plugin)) + { + try + { + Plugin obj = (Plugin) Activator.CreateInstance(type); + obj.ClassName = type.ToString(); + if(obj.RequiredCoreVersion > World.Version) + throw new Exception("Newer version of core is needed! (" + obj.RequiredCoreVersion + ")"); + if(string.IsNullOrEmpty(obj.Keyword.Trim()) || string.IsNullOrEmpty(obj.Name.Trim())) + throw new Exception("Plugin has invalid parameters!"); + if(Plugins.ContainsKey(obj.Keyword.ToLower().Trim())) + { + Plugin prev = Plugins[obj.Keyword.ToLower().Trim()]; + if(prev.Version >= obj.Version) + throw new Exception("A newer version of this plugin was already loaded!"); + } + if(obj.Keyword.ToLower().Trim() == "core" || obj.Keyword.ToLower().Trim() == "server") + throw new Exception("Plugin has invalid keyword!"); + + if(obj.Config != null) + { + obj.Config.Load(obj.Keyword.ToLower().Trim()); + obj.OnLoadedConfig(obj.Config.DidLoad); + } + Plugins[obj.Keyword.ToLower().Trim()] = obj; + Log.Write("Loaded: [" + obj.Keyword.ToLower().Trim() + "] " + obj.Name + ", version " + obj.Version.ToString() + "."); + } + catch(Exception e) + { + Log.Write("Failed: [" + type.ToString() + "] in " + file + "!"); + Log.Write(" " + e.Message); + continue; + } + } + } + } + catch + { + continue; + } + } + } + + Log.Write("Done."); + } + + internal static Dictionary Plugins = new Dictionary(); + + /// + /// Get plugin by keyword. + /// + /// Keyword of plugin. + /// + public static Plugin GetPlugin(string Keyword) + { + Keyword = Keyword.ToLower().Trim(); + return Plugins.ContainsKey(Keyword) ? Plugins[Keyword] : null; + } + } +} diff --git a/ProxyCore/Scripting/.svn/text-base/desktop.ini b/ProxyCore/Scripting/.svn/text-base/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/ProxyCore/Scripting/.svn/text-base/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/ProxyCore/Scripting/.svn/tmp/desktop.ini b/ProxyCore/Scripting/.svn/tmp/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/ProxyCore/Scripting/.svn/tmp/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/ProxyCore/Scripting/.svn/tmp/prop-base/desktop.ini b/ProxyCore/Scripting/.svn/tmp/prop-base/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/ProxyCore/Scripting/.svn/tmp/prop-base/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/ProxyCore/Scripting/.svn/tmp/props/desktop.ini b/ProxyCore/Scripting/.svn/tmp/props/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/ProxyCore/Scripting/.svn/tmp/props/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/ProxyCore/Scripting/.svn/tmp/text-base/desktop.ini b/ProxyCore/Scripting/.svn/tmp/text-base/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/ProxyCore/Scripting/.svn/tmp/text-base/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/ProxyCore/Scripting/Plugin.cs b/ProxyCore/Scripting/Plugin.cs new file mode 100644 index 0000000..4e4ac73 --- /dev/null +++ b/ProxyCore/Scripting/Plugin.cs @@ -0,0 +1,400 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using ProxyCore.Output; +using System.Text.RegularExpressions; +using ProxyCore.Input; + +namespace ProxyCore.Scripting +{ + public class Plugin + { + protected Plugin(string keyword, string name) + { + Keyword = keyword; + Name = name; + } + + /// + /// Set this to be your configuration file if you want your plugin to have one. This is optional. + /// + public ConfigFile Config + { + get; + protected set; + } + + /// + /// Name of your plugin. You must set this or your plugin will not be loaded. + /// + public readonly string Name; + + /// + /// This is the keyword for your plugin. You must set this or your plugin will not be loaded. + /// This must be unique. If two or more plugins with the same keyword are found then the plugin + /// with the highest version number is loaded. + /// + public readonly string Keyword; + + /// + /// Creator of the plugin, this is your name / character's name. This is optional. + /// + public string Author + { + get; + protected set; + } + + /// + /// Version of your plugin. This is optional. + /// + public int Version + { + get; + protected set; + } + + /// + /// Description about your plugin. You should explain here what it does and how to handle it. + /// This will be displayed if user requests information about your plugin. This is optional. + /// + public string Description + { + get; + protected set; + } + + /// + /// Enter a website for this plugin if you wish. Mostly used to see documentation and updates. + /// + public string Website + { + get; + protected set; + } + + /// + /// Enter the URL for update checking txt file. For example "www.duckbat.com/plugins/update.moons.txt". + /// In the text file enter the number of last version. For example whole contents of the txt file can be "3". + /// Indicating that the last version for this plugin is 3. If version is greater than user's version and + /// they have update checking on then they will be notified that there is a more up to date version out there. + /// + public string UpdateUrl + { + get; + protected set; + } + + /// + /// Does this plugin require a certain version of core? Set this if there was an update and your plugin requires it. + /// Plugin is not loaded if an older version core than this is used and user will be notified. + /// + public int RequiredCoreVersion + { + get; + protected set; + } + + /// + /// Register a new trigger. + /// + /// Unique identifier for the trigger. + /// Regex pattern for the trigger. + /// Function that will be called if this trigger fires. + protected void RegisterTrigger(string Name, string Pattern, TriggerFunction Function) + { + RegisterTrigger(Name, Pattern, Function, TriggerFlags.None); + } + + /// + /// Register a new trigger. + /// + /// Unique identifier for the trigger. + /// Regex pattern for the trigger. + /// Function that will be called if this trigger fires. + /// Options for the trigger. + protected void RegisterTrigger(string Name, string Pattern, TriggerFunction Function, TriggerFlags Flags) + { + RegisterTrigger(Name, Pattern, Function, Flags, 1000); + } + + /// + /// Register a new trigger. + /// + /// Unique identifier for the trigger. + /// Regex pattern for the trigger. + /// Function that will be called if this trigger fires. + /// Options for the trigger. + /// Lower priority triggers get matched first. + protected void RegisterTrigger(string Name, string Pattern, TriggerFunction Function, TriggerFlags Flags, int Priority) + { + RegisterTrigger(Name, Pattern, Function, Flags, Priority, 0); + } + + /// + /// Register a new trigger. + /// + /// Unique identifier for the trigger. + /// Regex pattern for the trigger. + /// Function that will be called if this trigger fires. + /// Options for the trigger. + /// Lower priority triggers get matched first. + /// Custom argument that will be passed to trigger data. + protected void RegisterTrigger(string Name, string Pattern, TriggerFunction Function, TriggerFlags Flags, int Priority, int Arg) + { + TriggerHandler.RegisterTrigger(Keyword.ToLower().Trim() + "." + Name, Pattern, Function, Flags, Priority, Arg, Keyword.ToLower().Trim()); + } + + /// + /// Unregister a trigger by name. + /// + /// Name of the trigger you wish to unregister. + protected void UnregisterTrigger(string Name) + { + TriggerHandler.UnregisterTrigger(Keyword.ToLower().Trim() + "." + Name); + } + + /// + /// Register a new command or overwrite a previous one. + /// + /// Command to register. + /// Arguments to match (regex pattern). This can be set to null or empty string + /// if you don't want to capture anything or plan to do so in the function yourself. + /// Function of command. + protected void RegisterCommand(string Cmd, string Args, CmdFunction f) + { + RegisterCommand(Cmd, Args, f, 0); + } + + /// + /// Register a new command or overwrite a previous one. + /// + /// Command to register. + /// Arguments to match (regex pattern). This can be set to null or empty string + /// if you don't want to capture anything or plan to do so in the function yourself. + /// Function of command. + /// Minimum length of command typed required to activate. For example if command is "plugins" and this is 6 then "plugin" and "plugins" both activate this command but "plugi" won't. Enter 0 to disable this behaviour. + protected void RegisterCommand(string Cmd, string Args, CmdFunction f, int MinLength) + { + RegisterCommand(Cmd, Args, f, MinLength, CMDFlags.None); + } + + /// + /// Register a new command or overwrite a previous one. + /// + /// Command to register. + /// Arguments to match (regex pattern). This can be set to null or empty string + /// if you don't want to capture anything or plan to do so in the function yourself. + /// Function of command. + /// Minimum length of command typed required to activate. For example if command is "plugins" and this is 6 then "plugin" and "plugins" both activate this command but "plugi" won't. Enter 0 to disable this behaviour. + /// Options for command. + protected void RegisterCommand(string Cmd, string Args, CmdFunction f, int MinLength, CMDFlags flags) + { + RegisterCommand(Cmd, Args, f, MinLength, flags, null); + } + + /// + /// Register a new command or overwrite a previous one. + /// + /// Command to register. + /// Arguments to match (regex pattern). This can be set to null or empty string + /// if you don't want to capture anything or plan to do so in the function yourself. + /// Function of command. + /// Minimum length of command typed required to activate. For example if command is "plugins" and this is 6 then "plugin" and "plugins" both activate this command but "plugi" won't. Enter 0 to disable this behaviour. + /// Options for command. + /// Parent command (if you want to create a subcommand). You can enter commands separated with space if it's nested. + protected void RegisterCommand(string Cmd, string Args, CmdFunction f, int MinLength, CMDFlags flags, string parent) + { + RegisterCommand(Cmd, Args, f, MinLength, flags, parent, 0); + } + + /// + /// Register a new command or overwrite a previous one. + /// + /// Command to register. + /// Arguments to match (regex pattern). This can be set to null or empty string + /// if you don't want to capture anything or plan to do so in the function yourself. + /// Function of command. + /// Minimum length of command typed required to activate. For example if command is "plugins" and this is 6 then "plugin" and "plugins" both activate this command but "plugi" won't. Enter 0 to disable this behaviour. + /// Options for command. + /// Parent command (if you want to create a subcommand). You can enter commands separated with space if it's nested. + /// Custom argument to pass to function handler. This way you can register multiple commands to a same + /// function handler only differentiating them with this custom argument. + protected void RegisterCommand(string Cmd, string Args, CmdFunction f, int MinLength, CMDFlags flags, string parent, int Arg) + { + RegisterCommand(Cmd, Args, f, MinLength, flags, parent, Arg, ulong.MaxValue); + } + + /// + /// Register a new command or overwrite a previous one. + /// + /// Command to register. + /// Arguments to match (regex pattern). This can be set to null or empty string + /// if you don't want to capture anything or plan to do so in the function yourself. + /// Function of command. + /// Options for command. + /// Parent command (if you want to create a subcommand). You can enter commands separated with space if it's nested. + /// Custom argument to pass to function handler. This way you can register multiple commands to a same + /// function handler only differentiating them with this custom argument. + /// Mask of allowed auth levels to access this command. Default ulong.MaxValue (meaning all auth levels are allowed). + /// Enter 3 for example to allow only auth level 1 and 2 to access this command. + /// Minimum length of command typed required to activate. For example if command is "plugins" and this is 6 then "plugin" and "plugins" both activate this command but "plugi" won't. Enter 0 to disable this behaviour. + protected void RegisterCommand(string Cmd, string Args, CmdFunction f, int MinLength, CMDFlags flags, string parent, int Arg, ulong AuthMask) + { + InputHandler.RegisterCommand(Cmd, Args, f, flags, parent, Arg, AuthMask, Keyword.ToLower().Trim(), MinLength); + } + + /// + /// Unregister a command. + /// + /// Command to unregister. If you want to unregister a nested command + /// separate commands with a space. + protected void UnregisterCommand(string Cmd) + { + InputHandler.UnregisterCommand(Cmd); + } + + /// + /// This will be called when character enters the game. Either by log in or reconnect. + /// + public virtual void OnLogin() + { + } + + /// + /// This will be called when we disconnect from Aardwolf. + /// + public virtual void OnDisconnect() + { + } + + /// + /// This will be called when we connect to Aardwolf. + /// + public virtual void OnConnect() + { + } + + /// + /// This is called when program shuts down. Write any code you need to shut down your plugin. + /// + public virtual void Shutdown() + { + } + + /// + /// This is called on every loop of world update. You can use it as your main loop for + /// the plugin if you need one. + /// + /// Current time since program startup. + public virtual void Update(long msTime) + { + } + + /// + /// This is called when we receive a line from MUD. It is called AFTER triggers are done with it. If + /// a trigger gagged the line this will not be called. + /// + /// + public virtual void OnReceivedLineAfter(Messages.Message Msg) + { + } + + /// + /// This is called when we receive a line from MUD. It is called BEFORE triggers are done with it. + /// + /// + public virtual void OnReceivedLineBefore(Messages.Message Msg) + { + } + + /// + /// This is called when user enters a command and inputhandler did not handle the command. So it + /// is called AFTER we check for aliases and commands and we are about to send command to MUD. + /// + /// Command that was entered. You can change this in the function. If you set null + /// then nothing will be sent to MUD. + /// Client who entered the command. If this is 0 it was executed from a plugin. + /// Auth level of who entered the command. + public virtual void OnEnteredCommandAfter(ref string Msg, uint ClientId, int AuthLevel) + { + } + + /// + /// This is called when user enters a command. It is called BEFORE we check for aliases and commands. + /// + /// Command that was entered. You can change this in the function. If you set null + /// then nothing will be sent to MUD and nothing will be checked for aliases or commands. + /// Client who entered the command. If this is 0 it was executed from a plugin. + /// Auth level of who entered the command. + public virtual void OnEnteredCommandBefore(ref string Msg, uint ClientId, int AuthLevel) + { + } + + /// + /// Enter required player config options here. This will be displayed if user requests info about a plugin. + /// For example you may enter here "echocommands ON" and "statmon ON" etc. Whatever your plugin requires. + /// This doesn't actually change the settings in game it is only for plugin info command. + /// + public readonly List RequiredPlayerConfig = new List(); + + /// + /// This is the class name of script. For example moons has this set to "MoonScript.MoonScript". + /// Only needed by developers who want to use another plugin in their plugin. + /// + internal string ClassName; + + /// + /// Called when we load a configuration file. + /// + /// Did the loading succeed? If not then the config file wasn't present and we created a new one. + public virtual void OnLoadedConfig(bool Success) + { + } + + /// + /// Disable all triggers with this priority. Disabling triggers from a plugin will make them not work until + /// you enable them from the same plugin again. If triggers have been disabled from multiple plugins then + /// all plugins will have to enable them again until they start working. Disabling triggers will make all + /// triggers with this priority to not work not only triggers in current plugin! + /// + /// Priority of triggers to disable. + protected void DisableTriggers(int Priority) + { + DisableTriggers(Priority, Priority); + } + + /// + /// Disable all triggers with this priority. Disabling triggers from a plugin will make them not work until + /// you enable them from the same plugin again. If triggers have been disabled from multiple plugins then + /// all plugins will have to enable them again until they start working. Disabling triggers will make all + /// triggers with this priority to not work not only triggers in current plugin! + /// + /// Minimum priority of triggers to disable. + /// Maximum priority of triggers to disable. + protected void DisableTriggers(int MinPriority, int MaxPriority) + { + TriggerHandler.DisableTriggers(Keyword, MinPriority, MaxPriority); + } + + /// + /// Enable all previously disabled triggers with this priority. + /// + /// Priority of triggers to enable. + protected void EnableTriggers(int Priority) + { + EnableTriggers(Priority, Priority); + } + + /// + /// Enable all previously disabled triggers with this priority. + /// + /// Minimum priority of triggers to enable. + /// Maximum priority of triggers to enable. + protected void EnableTriggers(int MinPriority, int MaxPriority) + { + TriggerHandler.EnableTriggers(Keyword, MinPriority, MaxPriority); + } + } +} diff --git a/ProxyCore/Scripting/PluginMgr.cs b/ProxyCore/Scripting/PluginMgr.cs new file mode 100644 index 0000000..75ba26a --- /dev/null +++ b/ProxyCore/Scripting/PluginMgr.cs @@ -0,0 +1,103 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.IO; +using System.Reflection; + +namespace ProxyCore.Scripting +{ + public static class PluginMgr + { + internal static void LoadAll() + { + if(Plugins.Count != 0) + return; + + try + { + if(!Directory.Exists("plugins")) + { + Directory.CreateDirectory("plugins"); + return; + } + } + catch + { + return; + } + + string[] files = Directory.GetFiles("plugins", "*.dll"); + + if(files.Length != 0) + { + foreach(string file in files) + { + try + { + Assembly assembly = Assembly.LoadFrom(Path.GetFullPath(file)); + foreach(Type type in assembly.GetTypes()) + { + if(!type.IsClass || type.IsNotPublic) + continue; + + if(type.BaseType == typeof(Plugin)) + { + try + { + Plugin obj = (Plugin) Activator.CreateInstance(type); + obj.ClassName = type.ToString(); + if(obj.RequiredCoreVersion > World.Version) + throw new Exception("Newer version of core is needed! (" + obj.RequiredCoreVersion + ")"); + if(string.IsNullOrEmpty(obj.Keyword.Trim()) || string.IsNullOrEmpty(obj.Name.Trim())) + throw new Exception("Plugin has invalid parameters!"); + if(Plugins.ContainsKey(obj.Keyword.ToLower().Trim())) + { + Plugin prev = Plugins[obj.Keyword.ToLower().Trim()]; + if(prev.Version >= obj.Version) + throw new Exception("A newer version of this plugin was already loaded!"); + } + if(obj.Keyword.ToLower().Trim() == "core" || obj.Keyword.ToLower().Trim() == "server") + throw new Exception("Plugin has invalid keyword!"); + + if(obj.Config != null) + { + obj.Config.Load(obj.Keyword.ToLower().Trim()); + obj.OnLoadedConfig(obj.Config.DidLoad); + } + Plugins[obj.Keyword.ToLower().Trim()] = obj; + Log.Write("Loaded: [" + obj.Keyword.ToLower().Trim() + "] " + obj.Name + ", version " + obj.Version.ToString() + "."); + } + catch(Exception e) + { + Log.Write("Failed: [" + type.ToString() + "] in " + file + "!"); + Log.Write(" " + e.Message); + continue; + } + } + } + } + catch + { + continue; + } + } + } + + Log.Write("Done."); + } + + internal static Dictionary Plugins = new Dictionary(); + + /// + /// Get plugin by keyword. + /// + /// Keyword of plugin. + /// + public static Plugin GetPlugin(string Keyword) + { + Keyword = Keyword.ToLower().Trim(); + return Plugins.ContainsKey(Keyword) ? Plugins[Keyword] : null; + } + } +} diff --git a/ProxyCore/Scripting/desktop.ini b/ProxyCore/Scripting/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/ProxyCore/Scripting/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/ProxyCore/Utility/.svn/all-wcprops b/ProxyCore/Utility/.svn/all-wcprops new file mode 100644 index 0000000..07d8c46 --- /dev/null +++ b/ProxyCore/Utility/.svn/all-wcprops @@ -0,0 +1,35 @@ +K 25 +svn:wc:ra_dav:version-url +V 40 +/svn/!svn/ver/54/trunk/ProxyCore/Utility +END +Config.cs +K 25 +svn:wc:ra_dav:version-url +V 49 +/svn/!svn/ver/2/trunk/ProxyCore/Utility/Config.cs +END +JSON.cs +K 25 +svn:wc:ra_dav:version-url +V 47 +/svn/!svn/ver/2/trunk/ProxyCore/Utility/JSON.cs +END +Wrap.cs +K 25 +svn:wc:ra_dav:version-url +V 47 +/svn/!svn/ver/2/trunk/ProxyCore/Utility/Wrap.cs +END +ServerConfig.cs +K 25 +svn:wc:ra_dav:version-url +V 56 +/svn/!svn/ver/54/trunk/ProxyCore/Utility/ServerConfig.cs +END +Colors.cs +K 25 +svn:wc:ra_dav:version-url +V 49 +/svn/!svn/ver/4/trunk/ProxyCore/Utility/Colors.cs +END diff --git a/ProxyCore/Utility/.svn/desktop.ini b/ProxyCore/Utility/.svn/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/ProxyCore/Utility/.svn/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/ProxyCore/Utility/.svn/dir-prop-base b/ProxyCore/Utility/.svn/dir-prop-base new file mode 100644 index 0000000..f1b96ea --- /dev/null +++ b/ProxyCore/Utility/.svn/dir-prop-base @@ -0,0 +1,5 @@ +K 14 +bugtraq:number +V 4 +true +END diff --git a/ProxyCore/Utility/.svn/entries b/ProxyCore/Utility/.svn/entries new file mode 100644 index 0000000..39f784d --- /dev/null +++ b/ProxyCore/Utility/.svn/entries @@ -0,0 +1,198 @@ +10 + +dir +58 +http://proxymud.googlecode.com/svn/trunk/ProxyCore/Utility +http://proxymud.googlecode.com/svn + + + +2012-02-02T08:38:33.263906Z +54 +default8p@gmail.com +has-props + + + + + + + + + + + + + +8a6e9f07-fe1d-2472-fcf8-0b435762827a + +Colors.cs +file + + + + +2016-03-25T22:18:43.212138Z +5ae2e0fde8eb3334d8301d5df234e3d2 +2012-01-17T12:29:36.909344Z +4 +default8p@gmail.com + + + + + + + + + + + + + + + + + + + + + +30665 + +Config.cs +file + + + + +2016-03-25T22:18:43.212138Z +5a3c22435b419310b907c98d9d5211dd +2012-01-17T10:55:35.805502Z +2 +default8p@gmail.com + + + + + + + + + + + + + + + + + + + + + +11921 + +JSON.cs +file + + + + +2016-03-25T22:18:43.212138Z +4a1b0482f41a0b953be7acb4bb9f378b +2012-01-17T10:55:35.805502Z +2 +default8p@gmail.com + + + + + + + + + + + + + + + + + + + + + +1750 + +Wrap.cs +file + + + + +2016-03-25T22:18:43.212138Z +2cbea5ce4ee9b94dc77d7b0ad48df18d +2012-01-17T10:55:35.805502Z +2 +default8p@gmail.com + + + + + + + + + + + + + + + + + + + + + +4490 + +ServerConfig.cs +file + + + + +2016-03-25T22:18:43.212138Z +3b3013b1dd6d65734b147b7761f01d59 +2012-02-02T08:38:33.263906Z +54 +default8p@gmail.com + + + + + + + + + + + + + + + + + + + + + +2782 + diff --git a/ProxyCore/Utility/.svn/prop-base/desktop.ini b/ProxyCore/Utility/.svn/prop-base/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/ProxyCore/Utility/.svn/prop-base/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/ProxyCore/Utility/.svn/props/desktop.ini b/ProxyCore/Utility/.svn/props/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/ProxyCore/Utility/.svn/props/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/ProxyCore/Utility/.svn/text-base/Colors.cs.svn-base b/ProxyCore/Utility/.svn/text-base/Colors.cs.svn-base new file mode 100644 index 0000000..1498ab1 --- /dev/null +++ b/ProxyCore/Utility/.svn/text-base/Colors.cs.svn-base @@ -0,0 +1,748 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace ProxyCore +{ + public static class Colors + { + static Colors() + { + XTermToAnsiTable[0] = 'w'; + XTermToAnsiTable[1] = 'r'; + XTermToAnsiTable[2] = 'g'; + XTermToAnsiTable[3] = 'y'; + XTermToAnsiTable[4] = 'b'; + XTermToAnsiTable[5] = 'm'; + XTermToAnsiTable[6] = 'c'; + XTermToAnsiTable[7] = 'w'; + XTermToAnsiTable[8] = 'D'; + XTermToAnsiTable[9] = 'R'; + XTermToAnsiTable[10] = 'G'; + XTermToAnsiTable[11] = 'Y'; + XTermToAnsiTable[12] = 'B'; + XTermToAnsiTable[13] = 'M'; + XTermToAnsiTable[14] = 'C'; + XTermToAnsiTable[15] = 'W'; + XTermToAnsiTable[16] = 'w'; + XTermToAnsiTable[17] = 'b'; + XTermToAnsiTable[18] = 'b'; + XTermToAnsiTable[19] = 'b'; + XTermToAnsiTable[20] = 'B'; + XTermToAnsiTable[21] = 'B'; + XTermToAnsiTable[22] = 'g'; + XTermToAnsiTable[23] = 'c'; + XTermToAnsiTable[24] = 'c'; + XTermToAnsiTable[25] = 'c'; + XTermToAnsiTable[26] = 'c'; + XTermToAnsiTable[27] = 'B'; + XTermToAnsiTable[28] = 'g'; + XTermToAnsiTable[29] = 'c'; + XTermToAnsiTable[30] = 'c'; + XTermToAnsiTable[31] = 'c'; + XTermToAnsiTable[32] = 'c'; + XTermToAnsiTable[33] = 'C'; + XTermToAnsiTable[34] = 'g'; + XTermToAnsiTable[35] = 'c'; + XTermToAnsiTable[36] = 'c'; + XTermToAnsiTable[37] = 'c'; + XTermToAnsiTable[38] = 'C'; + XTermToAnsiTable[39] = 'C'; + XTermToAnsiTable[40] = 'G'; + XTermToAnsiTable[41] = 'c'; + XTermToAnsiTable[42] = 'c'; + XTermToAnsiTable[43] = 'C'; + XTermToAnsiTable[44] = 'C'; + XTermToAnsiTable[45] = 'C'; + XTermToAnsiTable[46] = 'G'; + XTermToAnsiTable[47] = 'G'; + XTermToAnsiTable[48] = 'C'; + XTermToAnsiTable[49] = 'C'; + XTermToAnsiTable[50] = 'C'; + XTermToAnsiTable[51] = 'C'; + XTermToAnsiTable[52] = 'r'; + XTermToAnsiTable[53] = 'm'; + XTermToAnsiTable[54] = 'm'; + XTermToAnsiTable[55] = 'm'; + XTermToAnsiTable[56] = 'm'; + XTermToAnsiTable[57] = 'B'; + XTermToAnsiTable[58] = 'y'; + XTermToAnsiTable[59] = 'D'; + XTermToAnsiTable[60] = 'D'; + XTermToAnsiTable[61] = 'D'; + XTermToAnsiTable[62] = 'D'; + XTermToAnsiTable[63] = 'B'; + XTermToAnsiTable[64] = 'y'; + XTermToAnsiTable[65] = 'D'; + XTermToAnsiTable[66] = 'D'; + XTermToAnsiTable[67] = 'D'; + XTermToAnsiTable[68] = 'D'; + XTermToAnsiTable[69] = 'w'; + XTermToAnsiTable[70] = 'y'; + XTermToAnsiTable[71] = 'D'; + XTermToAnsiTable[72] = 'D'; + XTermToAnsiTable[73] = 'D'; + XTermToAnsiTable[74] = 'w'; + XTermToAnsiTable[75] = 'w'; + XTermToAnsiTable[76] = 'y'; + XTermToAnsiTable[77] = 'D'; + XTermToAnsiTable[78] = 'D'; + XTermToAnsiTable[79] = 'w'; + XTermToAnsiTable[80] = 'w'; + XTermToAnsiTable[81] = 'C'; + XTermToAnsiTable[82] = 'G'; + XTermToAnsiTable[83] = 'G'; + XTermToAnsiTable[84] = 'w'; + XTermToAnsiTable[85] = 'w'; + XTermToAnsiTable[86] = 'C'; + XTermToAnsiTable[87] = 'C'; + XTermToAnsiTable[88] = 'r'; + XTermToAnsiTable[89] = 'm'; + XTermToAnsiTable[90] = 'm'; + XTermToAnsiTable[91] = 'm'; + XTermToAnsiTable[92] = 'm'; + XTermToAnsiTable[93] = 'M'; + XTermToAnsiTable[94] = 'y'; + XTermToAnsiTable[95] = 'D'; + XTermToAnsiTable[96] = 'D'; + XTermToAnsiTable[97] = 'D'; + XTermToAnsiTable[98] = 'D'; + XTermToAnsiTable[99] = 'w'; + XTermToAnsiTable[100] = 'y'; + XTermToAnsiTable[101] = 'D'; + XTermToAnsiTable[102] = 'D'; + XTermToAnsiTable[103] = 'D'; + XTermToAnsiTable[104] = 'w'; + XTermToAnsiTable[105] = 'w'; + XTermToAnsiTable[106] = 'y'; + XTermToAnsiTable[107] = 'D'; + XTermToAnsiTable[108] = 'D'; + XTermToAnsiTable[109] = 'w'; + XTermToAnsiTable[110] = 'w'; + XTermToAnsiTable[111] = 'w'; + XTermToAnsiTable[112] = 'y'; + XTermToAnsiTable[113] = 'D'; + XTermToAnsiTable[114] = 'w'; + XTermToAnsiTable[115] = 'w'; + XTermToAnsiTable[116] = 'w'; + XTermToAnsiTable[117] = 'w'; + XTermToAnsiTable[118] = 'Y'; + XTermToAnsiTable[119] = 'w'; + XTermToAnsiTable[120] = 'w'; + XTermToAnsiTable[121] = 'w'; + XTermToAnsiTable[122] = 'w'; + XTermToAnsiTable[123] = 'w'; + XTermToAnsiTable[124] = 'r'; + XTermToAnsiTable[125] = 'm'; + XTermToAnsiTable[126] = 'm'; + XTermToAnsiTable[127] = 'm'; + XTermToAnsiTable[128] = 'M'; + XTermToAnsiTable[129] = 'M'; + XTermToAnsiTable[130] = 'y'; + XTermToAnsiTable[131] = 'D'; + XTermToAnsiTable[132] = 'D'; + XTermToAnsiTable[133] = 'D'; + XTermToAnsiTable[134] = 'w'; + XTermToAnsiTable[135] = 'w'; + XTermToAnsiTable[136] = 'y'; + XTermToAnsiTable[137] = 'D'; + XTermToAnsiTable[138] = 'D'; + XTermToAnsiTable[139] = 'w'; + XTermToAnsiTable[140] = 'w'; + XTermToAnsiTable[141] = 'w'; + XTermToAnsiTable[142] = 'y'; + XTermToAnsiTable[143] = 'D'; + XTermToAnsiTable[144] = 'w'; + XTermToAnsiTable[145] = 'w'; + XTermToAnsiTable[146] = 'w'; + XTermToAnsiTable[147] = 'w'; + XTermToAnsiTable[148] = 'Y'; + XTermToAnsiTable[149] = 'w'; + XTermToAnsiTable[150] = 'w'; + XTermToAnsiTable[151] = 'w'; + XTermToAnsiTable[152] = 'w'; + XTermToAnsiTable[153] = 'w'; + XTermToAnsiTable[154] = 'Y'; + XTermToAnsiTable[155] = 'w'; + XTermToAnsiTable[156] = 'w'; + XTermToAnsiTable[157] = 'w'; + XTermToAnsiTable[158] = 'w'; + XTermToAnsiTable[159] = 'W'; + XTermToAnsiTable[160] = 'R'; + XTermToAnsiTable[161] = 'm'; + XTermToAnsiTable[162] = 'm'; + XTermToAnsiTable[163] = 'M'; + XTermToAnsiTable[164] = 'M'; + XTermToAnsiTable[165] = 'M'; + XTermToAnsiTable[166] = 'y'; + XTermToAnsiTable[167] = 'D'; + XTermToAnsiTable[168] = 'D'; + XTermToAnsiTable[169] = 'w'; + XTermToAnsiTable[170] = 'w'; + XTermToAnsiTable[171] = 'M'; + XTermToAnsiTable[172] = 'y'; + XTermToAnsiTable[173] = 'D'; + XTermToAnsiTable[174] = 'w'; + XTermToAnsiTable[175] = 'w'; + XTermToAnsiTable[176] = 'w'; + XTermToAnsiTable[177] = 'w'; + XTermToAnsiTable[178] = 'Y'; + XTermToAnsiTable[179] = 'w'; + XTermToAnsiTable[180] = 'w'; + XTermToAnsiTable[181] = 'w'; + XTermToAnsiTable[182] = 'w'; + XTermToAnsiTable[183] = 'w'; + XTermToAnsiTable[184] = 'Y'; + XTermToAnsiTable[185] = 'w'; + XTermToAnsiTable[186] = 'w'; + XTermToAnsiTable[187] = 'w'; + XTermToAnsiTable[188] = 'w'; + XTermToAnsiTable[189] = 'W'; + XTermToAnsiTable[190] = 'Y'; + XTermToAnsiTable[191] = 'Y'; + XTermToAnsiTable[192] = 'w'; + XTermToAnsiTable[193] = 'w'; + XTermToAnsiTable[194] = 'W'; + XTermToAnsiTable[195] = 'W'; + XTermToAnsiTable[196] = 'R'; + XTermToAnsiTable[197] = 'R'; + XTermToAnsiTable[198] = 'M'; + XTermToAnsiTable[199] = 'M'; + XTermToAnsiTable[200] = 'M'; + XTermToAnsiTable[201] = 'M'; + XTermToAnsiTable[202] = 'R'; + XTermToAnsiTable[203] = 'R'; + XTermToAnsiTable[204] = 'w'; + XTermToAnsiTable[205] = 'w'; + XTermToAnsiTable[206] = 'M'; + XTermToAnsiTable[207] = 'M'; + XTermToAnsiTable[208] = 'Y'; + XTermToAnsiTable[209] = 'w'; + XTermToAnsiTable[210] = 'w'; + XTermToAnsiTable[211] = 'w'; + XTermToAnsiTable[212] = 'w'; + XTermToAnsiTable[213] = 'w'; + XTermToAnsiTable[214] = 'Y'; + XTermToAnsiTable[215] = 'w'; + XTermToAnsiTable[216] = 'w'; + XTermToAnsiTable[217] = 'w'; + XTermToAnsiTable[218] = 'w'; + XTermToAnsiTable[219] = 'W'; + XTermToAnsiTable[220] = 'Y'; + XTermToAnsiTable[221] = 'Y'; + XTermToAnsiTable[222] = 'w'; + XTermToAnsiTable[223] = 'w'; + XTermToAnsiTable[224] = 'W'; + XTermToAnsiTable[225] = 'W'; + XTermToAnsiTable[226] = 'Y'; + XTermToAnsiTable[227] = 'Y'; + XTermToAnsiTable[228] = 'w'; + XTermToAnsiTable[229] = 'W'; + XTermToAnsiTable[230] = 'W'; + XTermToAnsiTable[231] = 'W'; + XTermToAnsiTable[232] = 'w'; + XTermToAnsiTable[233] = 'w'; + XTermToAnsiTable[234] = 'w'; + XTermToAnsiTable[235] = 'w'; + XTermToAnsiTable[236] = 'w'; + XTermToAnsiTable[237] = 'w'; + XTermToAnsiTable[238] = 'D'; + XTermToAnsiTable[239] = 'D'; + XTermToAnsiTable[240] = 'D'; + XTermToAnsiTable[241] = 'D'; + XTermToAnsiTable[242] = 'D'; + XTermToAnsiTable[243] = 'D'; + XTermToAnsiTable[244] = 'D'; + XTermToAnsiTable[245] = 'D'; + XTermToAnsiTable[246] = 'D'; + XTermToAnsiTable[247] = 'D'; + XTermToAnsiTable[248] = 'w'; + XTermToAnsiTable[249] = 'w'; + XTermToAnsiTable[250] = 'w'; + XTermToAnsiTable[251] = 'w'; + XTermToAnsiTable[252] = 'w'; + XTermToAnsiTable[253] = 'w'; + XTermToAnsiTable[254] = 'W'; + XTermToAnsiTable[255] = 'W'; + } + + /// + /// Check if a char code is ANSI color code. + /// + /// Char to check for. + /// + public static bool IsColorCode(char code) + { + // Don't allow black color, we can't see it + if(code == 'd') + return false; + + foreach(ColorEntry x in ColorEntries) + { + if(x.ColorChar == code) + return true; + } + + return false; + } + + /// + /// Convert normal colors to HTML colors. It converts inserting </font> in front of every color too + /// so you need to have started with some font already. + /// + /// Message to convert colors in. + /// + public static string GetHTMLColors(string Msg) + { + Msg = Msg.Replace("@@", colorEscape); + foreach(ColorEntry c in ColorEntries) + Msg = Msg.Replace("@" + c.ColorChar, ""); + Msg = Msg.Replace(colorEscape, "@"); + return Msg; + } + + // Any codes that aren't xterm and aren't listed here will be @e instead of escape char. + private static ColorEntry[] ColorEntries = new[] + { + new ColorEntry('w', "", "", "grey", "C0C0C0"), + new ColorEntry('W', "", "", "white", "FFFFFF"), + new ColorEntry('G', "", "", "green", "00FF00"), + new ColorEntry('g', "", "", "dark green", "008000"), + new ColorEntry('R', "", "", "red", "FF0000"), + new ColorEntry('r', "", "", "dark red", "800000"), + new ColorEntry('Y', "", "", "yellow", "FFFF00"), + new ColorEntry('y', "", "", "dark yellow", "808000"), + new ColorEntry('C', "", "", "cyan", "00FFFF"), + new ColorEntry('c', "", "", "dark cyan", "008080"), + new ColorEntry('B', "", "", "blue", "0000FF"), + new ColorEntry('b', "", "", "dark blue", "000080"), + new ColorEntry('M', "", "", "magenta", "FF00FF"), + new ColorEntry('m', "", "", "dark magenta", "800080"), + new ColorEntry('D', "", "", "dark grey", "808080"), + new ColorEntry('d', "", "", "black", "000000"), + new ColorEntry('q', "", "", "default", "C0C0C0") + }; + + /// + /// Get last color code in the string (not including foreground colors). This will return + /// with the @ sign. + /// + /// + /// + public static string GetLastColorCode(string text) + { + text = text.Replace("@@", colorEscape); + + // Start checking from the end + for(int i = text.Length - 1; i >= 0; i--) + { + if(text[i] == '@' && i + 1 < text.Length && text[i + 1] != 'f' && text[i + 1] != 'y') + { + if(text[i + 1] == 'x') + { + int len; + string code = GetXTerm(text, i, out len).ToString(); + if(len == 0) + continue; + + if(code.Length == 1) + code = "00" + code; + else if(code.Length == 2) + code = "0" + code; + + return "@x" + code; + } + else + return "@" + text[i + 1]; + } + } + + return string.Empty; + } + + /// + /// Removes duplicate colors from a string. For example "@r @Y bla@w" would become " @Ybla". + /// Also XTERM color codes become padded with zero if they are present. + /// + /// String to fix colors in. + /// + public static string RemoveDuplicateColors(string orig) + { + StringBuilder txt = new StringBuilder(); + + string currentColor = ""; + bool didWriteColor = false; + bool hasAt = false; + bool hasE = false; + + for(int i = 0; i < orig.Length; i++) + { + switch(orig[i]) + { + case '@': + { + if(hasAt) + { + if(!didWriteColor) + { + txt.Append(currentColor); + didWriteColor = true; + } + + txt.Append("@@"); + hasAt = false; + } + else + { + hasAt = true; + } + } break; + + case ' ': + case '\r': + case '\n': + case '\t': + txt.Append(orig[i]); + break; + + default: + { + if(hasAt) + { + if(orig[i] == 'e') + { + txt.Append("@e"); + hasAt = false; + hasE = true; + continue; + } + if(orig[i] == 'f') + { + if(i + 1 < orig.Length) + txt.Append("@f" + orig[i + 1]); + i++; + hasAt = false; + continue; + } + if(orig[i] == 'z') + { + int len; + string code = GetXTerm(orig, i - 1, out len).ToString(); + if(len > 0) + { + if(code.Length == 1) + code = "00" + code; + else if(code.Length == 2) + code = "0" + code; + txt.Append("@z" + code); + i += len; + } + hasAt = false; + continue; + } + if(orig[i] == 'x') + { + int len; + string code = GetXTerm(orig, i - 1, out len).ToString(); + if(len > 0) + { + if(code.Length == 1) + code = "00" + code; + else if(code.Length == 2) + code = "0" + code; + i += len; + if(currentColor != "@x" + code) + { + currentColor = "@x" + code; + didWriteColor = false; + } + } + hasAt = false; + continue; + } + if(currentColor != "@" + orig[i]) + { + currentColor = "@" + orig[i]; + didWriteColor = false; + } + hasAt = false; + } + else if(hasE) + { + txt.Append(orig[i]); + if(orig[i] == 'm') + hasE = false; + } + else + { + if(!didWriteColor) + { + txt.Append(currentColor); + didWriteColor = true; + } + + txt.Append(orig[i]); + } + } break; + } + } + + return txt.ToString(); + } + + /// + /// This is what we turn the @ into so we can replace colors and keep the symbol intact + /// + private const string colorEscape = "#\r\ncolor_escape_sequence\r\n#"; + + /// + /// This function will turn either ANSI color to our format or vice versa. + /// + /// String passed for color changing. + /// False means we change our format (@x) to ANSI; true means we change ANSI to our format (we don't convert XTERM colors this way though). + /// Allow replacing xterm colors? If disabled we will replace into closest ANSI. + /// + public static string FixColors(string text, bool fromRaw, bool allowXTerm) + { + if(fromRaw == false) + { + text = text.Replace("@@", colorEscape); + text = ReplaceXTerm(text, fromRaw, allowXTerm); + for(int i = 0; i < ColorEntries.Length; i++) + { + text = text.Replace("@" + ColorEntries[i].ColorChar, ColorEntries[i].ANSI); + text = text.Replace("@f" + ColorEntries[i].ColorChar, ColorEntries[i].ForeANSI); + } + text = text.Replace("@e", ""); + text = text.Replace(colorEscape, "@"); + } + else + { + text = text.Replace("@", colorEscape); + text = ReplaceXTerm(text, fromRaw, allowXTerm); + for(int i = 0; i < ColorEntries.Length; i++) + { + text = text.Replace(ColorEntries[i].ANSI, "@" + ColorEntries[i].ColorChar); + text = text.Replace(ColorEntries[i].ForeANSI, "@f" + ColorEntries[i].ColorChar); + } + text = text.Replace("", "@e"); + text = text.Replace(colorEscape, "@@"); + } + return text; + } + + /// + /// Remove dark grey color code from string and replace it with normal grey. + /// + /// String to remove dark grey from (replacing it with normal grey). + /// + public static string RemoveGray(string text) + { + text = text.Replace("@@", colorEscape); + text = text.Replace("@D", "@w"); + text = text.Replace("@fD", "@fw"); + text = text.Replace(colorEscape, "@@"); + return text; + } + + /// + /// This function will Remove all color from the string. + /// + /// String where the color is being removed. + /// True means raw color (ansi); false means our format (@x). + /// + public static string RemoveColors(string text, bool raw) + { + if(!raw) + { + text = text.Replace("@@", colorEscape); + for(int i = 0; i < ColorEntries.Length; i++) + { + text = text.Replace("@" + ColorEntries[i].ColorChar, ""); + text = text.Replace("@f" + ColorEntries[i].ColorChar, ""); + } + int j; + while((j = text.IndexOf("@x")) != -1 || (j = text.IndexOf("@z")) != -1) + text = text.Remove(j, 5); + text = text.Replace(colorEscape, "@"); + return text; + } + + for(int i = 0; i < ColorEntries.Length; i++) + { + text = text.Replace(ColorEntries[i].ANSI, ""); + text = text.Replace(ColorEntries[i].ForeANSI, ""); + } + + int k; + while((k = text.IndexOf("")) != -1) + { + int l = text.IndexOf('m', k); + if(l == -1) + break; + text = text.Remove(k, l - k); + } + return text; + } + + /// + /// Get XTerm color code from text in index (index must be at @x or @z, before it). + /// + /// Text to get color code from. + /// Index of @z or @x. + /// + public static byte GetXTerm(string text, int index, out int xlen) + { + // Skip @x or @z + index += 2; + + // Get byte number now + byte v = GetXTermCode(text, index, out xlen); + return v; + } + + /// + /// Get full escape string from string in index. + /// + /// Text to search from. + /// Index in text of @e + /// Length of the thing behind @e. + /// + public static string GetEscape(string text, int index, out int xlen) + { + index += 2; + if((xlen = text.IndexOf('m', index)) == -1) + { + xlen = 0; + return "@e[0m"; + } + + xlen++; // include the 'm' + xlen -= index; + return "@e" + text.Substring(index, xlen); + } + + /// + /// Get XTerm color code from text in index (index must be at the number not before @x or @z like the other function) + /// + /// Text to get color code from. + /// Index of number. + /// Length of the number. + /// + public static byte GetXTermCode(string text, int index, out int xlen) + { + int len = 0; + while(len < 3 && index + len < text.Length && char.IsNumber(text[index + len])) + len++; + + byte v = 0; + while(len > 0 && !byte.TryParse(text.Substring(index, len), out v)) + len--; + + if(len == 0) + v = 0; + xlen = len; + return v; + } + + /// + /// Replace XTerm color codes into real XTerm or ANSI values. + /// + /// Text to search in. + /// Replace into XTerm codes or if false then convert to closest regular ANSI. + /// + public static string ReplaceXTerm(string text, bool fromRaw, bool allowXTerm) + { + if(fromRaw == false) + { + int index = -1; + while((index = text.IndexOf("@x")) != -1) + { + int len; + byte code = GetXTerm(text, index, out len); + text = text.Remove(index, len + 2); + if(allowXTerm) + text = text.Insert(index, "[38;5;" + code.ToString() + "m"); + else + text = text.Insert(index, "@" + XTermToANSI(code)); + } + while((index = text.IndexOf("@z")) != -1) + { + int len; + byte code = GetXTerm(text, index, out len); + text = text.Remove(index, len + 2); + if(allowXTerm) + text = text.Insert(index, "[48;5;" + code.ToString() + "m"); + else + text = text.Insert(index, "@f" + XTermToANSI(code)); + } + } + else + { + int index = -1; + while((index = text.IndexOf("[38;5;")) != -1) + { + int len; + byte c = GetXTermCode(text, index + 7, out len); + string code = c.ToString(); + if(code.Length == 1) + code = "00" + code; + else if(code.Length == 2) + code = "0" + code; + text = text.Remove(index, len + 8); + if(allowXTerm) + text = text.Insert(index, "@x" + code); + else + text = text.Insert(index, "@" + XTermToANSI(c)); + } + while((index = text.IndexOf("[48;5;")) != -1) + { + int len; + byte c = GetXTermCode(text, index + 7, out len); + string code = c.ToString(); + if(code.Length == 1) + code = "00" + code; + else if(code.Length == 2) + code = "0" + code; + text = text.Remove(index, len + 8); + if(allowXTerm) + text = text.Insert(index, "@z" + code); + else + text = text.Insert(index, "@" + XTermToANSI(c)); + } + } + return text; + } + + private static readonly char[] XTermToAnsiTable = new char[256]; + + /// + /// Convert XTerm to ansi char (closest match). + /// + /// Code to convert. + /// + public static char XTermToANSI(byte code) + { + return XTermToAnsiTable[(int)code]; + } + } + + internal class ColorEntry + { + internal ColorEntry(char colorChar, string ansi, string foreansi, string name, string hex) + { + ColorChar = colorChar; + ANSI = ansi; + ForeANSI = foreansi; + Name = name; + HEX = hex; + } + + public readonly char ColorChar; + public readonly string ANSI; + public readonly string ForeANSI; + public readonly string Name; + public readonly string HEX; + } +} diff --git a/ProxyCore/Utility/.svn/text-base/Config.cs.svn-base b/ProxyCore/Utility/.svn/text-base/Config.cs.svn-base new file mode 100644 index 0000000..e358018 --- /dev/null +++ b/ProxyCore/Utility/.svn/text-base/Config.cs.svn-base @@ -0,0 +1,333 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.IO; +using System.Text.RegularExpressions; +using System.Globalization; + +namespace ProxyCore +{ + public class ConfigFile + { + protected ConfigFile() + { + + } + + private string Filepath; + + /// + /// Did we successfully load the config file? If not then it was probably missing. + /// + public bool DidLoad + { + get; + private set; + } + + /// + /// Load a configuration file. + /// + /// Configuration name - for example "server". This should be your plugin name. + /// + internal void Load(string fileName) + { + fileName = "config." + fileName + ".txt"; + _cfgData.Clear(); + Filepath = fileName; + OnCreated(); + + if(_cfgData.Count == 0) + return; + + StreamReader f = null; + try + { + f = new StreamReader(fileName); + } + catch(FileNotFoundException) + { + SaveNew(); + return; + } + catch + { + return; + } + + string l; + while((l = f.ReadLine()) != null) + { + l = l.Trim(); + if(string.IsNullOrEmpty(l) || l.StartsWith("#") || l.StartsWith(";") || l.StartsWith("//")) + continue; + + Match m = _loadRegex.Match(l); + if(!m.Success) + continue; + + string Key = m.Groups[1].Value.ToLower(); + if(!_cfgData.ContainsKey(Key)) + continue; + + string Value = m.Groups[3].Value; + if(Value.Contains('"') && _cfgData[Key].DefaultValue is string) + Value = Value.Substring(1, Value.Length - 2); + + if(_cfgData[Key].DefaultValue is int) + { + int i; + if(!int.TryParse(Value, out i)) + continue; + + _cfgData[Key].Value = i; + } + else if(_cfgData[Key].DefaultValue is uint) + { + uint i; + if(!uint.TryParse(Value, out i)) + continue; + + _cfgData[Key].Value = i; + } + else if(_cfgData[Key].DefaultValue is long) + { + long i; + if(!long.TryParse(Value, out i)) + continue; + + _cfgData[Key].Value = i; + } + else if(_cfgData[Key].DefaultValue is ulong) + { + ulong i; + if(!ulong.TryParse(Value, out i)) + continue; + + _cfgData[Key].Value = i; + } + else if(_cfgData[Key].DefaultValue is string) + { + _cfgData[Key].Value = Value; + } + else if(_cfgData[Key].DefaultValue is float) + { + try + { + float i = Convert.ToSingle(Value, CultureInfo.InvariantCulture.NumberFormat); + _cfgData[Key].Value = i; + } + catch + { + continue; + } + } + else if(_cfgData[Key].DefaultValue is double) + { + try + { + double i = Convert.ToDouble(Value, CultureInfo.InvariantCulture.NumberFormat); + _cfgData[Key].Value = i; + } + catch + { + continue; + } + } + } + + f.Close(); + } + + /// + /// Regex pattern used to load a line from config file. + /// Groups[1]: Name of setting + /// Groups[3]: Value of setting (including "" if string) + /// + private static readonly Regex _loadRegex = new Regex("([\\w\\.]+)\\s*(=|:|-)\\s*((\".*\")|(-?\\d+\\.\\d+)|(-?\\d+))", RegexOptions.Compiled); + + /// + /// Save a new configuration file with default values. If there is an existing config file, it will be replaced. + /// + public void SaveNew() + { + if(string.IsNullOrEmpty(Filepath) || _cfgData.Count == 0) + return; + + StreamWriter f = null; + try + { + f = new StreamWriter(Filepath, false); + } + catch + { + return; + } + + foreach(KeyValuePair x in _cfgData) + { + f.WriteLine("###############################################################################"); + f.WriteLine("#"); + f.WriteLine("# " + x.Value.Key); + if(!string.IsNullOrEmpty(x.Value.Desc)) + { + string[] oDesc = Utility.WrapColored(x.Value.Desc, 70, 0); + for(int i = 0; i < oDesc.Length; i++) + f.WriteLine("# " + oDesc[i]); + } + f.WriteLine("#"); + f.WriteLine("###############################################################################"); + f.WriteLine(""); + f.WriteLine(x.Value.Key + " = " + ((x.Value.DefaultValue is string) ? ("\"" + x.Value.DefaultValue + "\"") : x.Value.DefaultValue.ToString().Replace(",", "."))); + f.WriteLine(""); + } + + f.Close(); + } + + /// + /// This will be called to populate config data with default values and descriptions. + /// + protected virtual void OnCreated() + { + } + + /// + /// Create a new setting for the file. If setting with this name already exists then skip. + /// + /// Setting name. + /// Default value for setting. Make sure to use type casting if not integer. + /// Description to write in the file for this setting. + protected void CreateSetting(string Key, object Value, string Desc) + { + if(_cfgData.ContainsKey(Key.ToLower().Trim())) + return; + + CfgEntry e = new CfgEntry() + { + Key = Key, + Value = Value, + DefaultValue = Value, + Desc = Desc + }; + + _cfgData[Key.ToLower().Trim()] = e; + } + + /// + /// Read a 32 bit integer value from configuration file. + /// + /// Name of the option. + /// Default value if config is missing this option or is invalid. + /// + public int GetInt32(string Key, int Default) + { + Key = Key.ToLower().Trim(); + if(string.IsNullOrEmpty(Key) || !_cfgData.ContainsKey(Key) || !(_cfgData[Key].Value is int)) + return Default; + + return (int)_cfgData[Key].Value; + } + + /// + /// Read a 32 bit unsigned integer value from configuration file. + /// + /// Name of the option. + /// Default value if config is missing this option or is invalid. + /// + public uint GetUInt32(string Key, uint Default) + { + Key = Key.ToLower().Trim(); + if(string.IsNullOrEmpty(Key) || !_cfgData.ContainsKey(Key) || !(_cfgData[Key].Value is uint)) + return Default; + + return (uint)_cfgData[Key].Value; + } + + /// + /// Read a 64 bit integer value from configuration file. + /// + /// Name of the option. + /// Default value if config is missing this option or is invalid. + /// + public long GetInt64(string Key, long Default) + { + Key = Key.ToLower().Trim(); + if(string.IsNullOrEmpty(Key) || !_cfgData.ContainsKey(Key) || !(_cfgData[Key].Value is long)) + return Default; + + return (long)_cfgData[Key].Value; + } + + /// + /// Read a 64 bit unsigned integer value from configuration file. + /// + /// Name of the option. + /// Default value if config is missing this option or is invalid. + /// + public ulong GetUInt64(string Key, ulong Default) + { + Key = Key.ToLower().Trim(); + if(string.IsNullOrEmpty(Key) || !_cfgData.ContainsKey(Key) || !(_cfgData[Key].Value is ulong)) + return Default; + + return (ulong)_cfgData[Key].Value; + } + + /// + /// Read a float value from configuration file. + /// + /// Name of the option. + /// Default value if config is missing this option or is invalid. + /// + public float GetFloat(string Key, float Default) + { + Key = Key.ToLower().Trim(); + if(string.IsNullOrEmpty(Key) || !_cfgData.ContainsKey(Key) || !(_cfgData[Key].Value is float)) + return Default; + + return (float)_cfgData[Key].Value; + } + + /// + /// Read a double value from configuration file. + /// + /// Name of the option. + /// Default value if config is missing this option or is invalid. + /// + public double GetDouble(string Key, double Default) + { + Key = Key.ToLower().Trim(); + if(string.IsNullOrEmpty(Key) || !_cfgData.ContainsKey(Key) || !(_cfgData[Key].Value is double)) + return Default; + + return (double)_cfgData[Key].Value; + } + + /// + /// Read a string value from configuration file. + /// + /// Name of the option. + /// Default value if config is missing this option or is invalid. + /// + public string GetString(string Key, string Default) + { + Key = Key.ToLower().Trim(); + if(string.IsNullOrEmpty(Key) || !_cfgData.ContainsKey(Key) || !(_cfgData[Key].Value is string)) + return Default; + + return (string)_cfgData[Key].Value; + } + + private Dictionary _cfgData = new Dictionary(); + + private class CfgEntry + { + public string Key; + public object Value; + public object DefaultValue; + public string Desc; + } + } +} diff --git a/ProxyCore/Utility/.svn/text-base/JSON.cs.svn-base b/ProxyCore/Utility/.svn/text-base/JSON.cs.svn-base new file mode 100644 index 0000000..f13972c --- /dev/null +++ b/ProxyCore/Utility/.svn/text-base/JSON.cs.svn-base @@ -0,0 +1,54 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Jayrock.Json; +using Jayrock.Json.Conversion; + +namespace ProxyCore +{ + internal static class JSON + { + internal static bool Parse(string msg, string module, List> data) + { + try + { + JsonObject obj = (JsonObject)JsonConvert.Import(msg); + Explore(module, obj, data); + } + catch + { + //data.Clear(); + return false; + } + return true; + } + + private static void Explore(string nameSpace, JsonObject obj, List> x) + { + var keys = obj.Names; + foreach(string i in keys) + ExplorePair(nameSpace + "." + i, obj[i], x); + } + + private static void ExplorePair(string nameSpace, object obj, List> x) + { + if((obj is JsonNumber) || + (obj is JsonNull) || + (obj is string) || + (obj is JsonBoolean) || + (obj is JsonString)) + x.Add(new KeyValuePair(nameSpace, obj.ToString())); + else if(obj is JsonArray) + { + foreach(JsonObject i in (JsonArray)obj) + Explore(nameSpace, i, x); + } + else if(obj is JsonObject) + Explore(nameSpace, (JsonObject)obj, x); + else if(obj == null) + x.Add(new KeyValuePair(nameSpace, "null")); + else throw new Exception(); + } + } +} diff --git a/ProxyCore/Utility/.svn/text-base/ServerConfig.cs.svn-base b/ProxyCore/Utility/.svn/text-base/ServerConfig.cs.svn-base new file mode 100644 index 0000000..4bd043f --- /dev/null +++ b/ProxyCore/Utility/.svn/text-base/ServerConfig.cs.svn-base @@ -0,0 +1,46 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using ProxyCore; + +namespace ProxyCore +{ + public class ServerConfig : ConfigFile + { + public ServerConfig() + { + Load("server"); + } + + protected override void OnCreated() + { + base.OnCreated(); + + CreateSetting("Listen.Address", "127.0.0.1", "This is the address that the proxy program will be listening on. You will have to connect to this address with your MUD client. Enter 127.0.0.1 to listen only on current computer, enter LAN IP to listen only in your home network or enter 0.0.0.0 to listen on all addresses (even remote)."); + CreateSetting("Listen.Port", 4000, "This is the port that the proxy program will be listening on. You will have to enter this port in your MUD client. If you want remote connections you may have to open this port (TCP) in your firewall."); + CreateSetting("MUD.Address", "aardmud.org", "This is the address for MUD connection."); + CreateSetting("MUD.Port", 4000, "This is the port for MUD connection."); + CreateSetting("Passwords", "", "Passwords for the proxy and their user levels. For example: \"abc->1,def->2,ghi321->1\". If user enters def as password they will get user level 2. Enter as many passwords as you like. If you leave this empty, the proxy will not ask for a password and user will be authed with level 1. The password values should be between 1 and 64."); + CreateSetting("GMCP.Supports", "Core=1, Char=1, Room=1, Comm=1", "What GMCP options do we have on by default? These are modules only needed for the proxy. If your client needs another module it will enable it itself - no need to change here."); + CreateSetting("AutoConnect", 0, "Proxy program will always automatically (re)connect to MUD if there is a client online in the proxy. If there is no client online the proxy will not automatically connect. Enabling this option will force the proxy to always auto (re)connect."); + CreateSetting("ClientCompression", 1, "Enable compression for connected clients (MUD compression will always be on, even if you disable this option). Don't disable unless you are having problems with compression and can't disable client side."); + } + } + + public class CoreConfig : ConfigFile + { + public CoreConfig() + { + Load("core"); + } + + protected override void OnCreated() + { + base.OnCreated(); + + CreateSetting("Updates.Core", 1, "Automatically check updates for core."); + CreateSetting("Updates.Plugins", 1, "Automatically check updates for plugins."); + } + } +} diff --git a/ProxyCore/Utility/.svn/text-base/Wrap.cs.svn-base b/ProxyCore/Utility/.svn/text-base/Wrap.cs.svn-base new file mode 100644 index 0000000..b73ed1a --- /dev/null +++ b/ProxyCore/Utility/.svn/text-base/Wrap.cs.svn-base @@ -0,0 +1,141 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace ProxyCore +{ + public partial class Utility + { + public static string[] WrapColored(string text, int maxLength, int IndentSize) + { + if(maxLength <= 2) + return null; + + if(text.Length <= maxLength) + return new string[1] { text }; + + StringBuilder wrapBuilder = new StringBuilder(); + int count = 0; + bool printed = false; + int lastOk = 0; + int realLength = 0; + int fakeIndex = 0; + text = text.TrimEnd(); + bool didAt = false; + bool doNow = false; + for(int i = 0; i < text.Length; i++) + { + switch(text[i]) + { + case ' ': + /*case ',': + case '.': + case '?': + case '!': + case ':': + case ';': + case ')': + case ']': + case '}': + case '-':*/ + case '\t': + lastOk = i; + realLength++; + break; + + case '\n': + case '\r': + doNow = true; + lastOk = i; + realLength++; + break; + + case '@': + if(didAt) + realLength++; + didAt = !didAt; + break; + + default: + if(!didAt) + realLength++; + else + didAt = false; + break; + } + + if(realLength >= maxLength || doNow) + { + if(printed && IndentSize > 0) + wrapBuilder.Append(' ', IndentSize); + if(lastOk > 0) + { + wrapBuilder.Append(text.Substring(fakeIndex, lastOk - fakeIndex + 1).TrimEnd() + Environment.NewLine); + i = lastOk; + } + else + wrapBuilder.Append(text.Substring(fakeIndex, i - fakeIndex + 1).TrimEnd() + Environment.NewLine); + + fakeIndex = lastOk > 0 ? lastOk + 1 : i + 1; + lastOk = 0; + realLength = IndentSize; + printed = true; + count++; + doNow = false; + } + } + + if(fakeIndex < text.Length - 1) + { + if(printed && IndentSize > 0) + wrapBuilder.Append(' ', IndentSize); + wrapBuilder.Append(text.Substring(fakeIndex, text.Length - fakeIndex).TrimEnd() + Environment.NewLine); + count++; + } + + List lp = wrapBuilder.ToString().Split(new[] { Environment.NewLine }, StringSplitOptions.None).ToList(); + lp.RemoveAt(lp.Count - 1); + return lp.ToArray(); + } + + public static string FormatColoredString(string msg, int len) + { + StringBuilder str = new StringBuilder(); + int real = 0; + bool at = false; + for(int i = 0; i < msg.Length; i++) + { + if(msg[i] == '@') + { + if(at) + { + real++; + str.Append("@@"); + } + at = !at; + } + else if(at) + { + str.Append("@" + msg[i].ToString()); + at = false; + } + else + { + str.Append(msg[i]); + real++; + } + } + + if(real < Math.Abs(len)) + { + if(len < 0) + str.Append(' ', Math.Abs(len) - real); + else + str.Insert(0, " ", len - real); + } + + return str.ToString(); + } + } +} diff --git a/ProxyCore/Utility/.svn/text-base/desktop.ini b/ProxyCore/Utility/.svn/text-base/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/ProxyCore/Utility/.svn/text-base/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/ProxyCore/Utility/.svn/tmp/desktop.ini b/ProxyCore/Utility/.svn/tmp/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/ProxyCore/Utility/.svn/tmp/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/ProxyCore/Utility/.svn/tmp/prop-base/desktop.ini b/ProxyCore/Utility/.svn/tmp/prop-base/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/ProxyCore/Utility/.svn/tmp/prop-base/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/ProxyCore/Utility/.svn/tmp/props/desktop.ini b/ProxyCore/Utility/.svn/tmp/props/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/ProxyCore/Utility/.svn/tmp/props/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/ProxyCore/Utility/.svn/tmp/text-base/desktop.ini b/ProxyCore/Utility/.svn/tmp/text-base/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/ProxyCore/Utility/.svn/tmp/text-base/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/ProxyCore/Utility/Colors.cs b/ProxyCore/Utility/Colors.cs new file mode 100644 index 0000000..1498ab1 --- /dev/null +++ b/ProxyCore/Utility/Colors.cs @@ -0,0 +1,748 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace ProxyCore +{ + public static class Colors + { + static Colors() + { + XTermToAnsiTable[0] = 'w'; + XTermToAnsiTable[1] = 'r'; + XTermToAnsiTable[2] = 'g'; + XTermToAnsiTable[3] = 'y'; + XTermToAnsiTable[4] = 'b'; + XTermToAnsiTable[5] = 'm'; + XTermToAnsiTable[6] = 'c'; + XTermToAnsiTable[7] = 'w'; + XTermToAnsiTable[8] = 'D'; + XTermToAnsiTable[9] = 'R'; + XTermToAnsiTable[10] = 'G'; + XTermToAnsiTable[11] = 'Y'; + XTermToAnsiTable[12] = 'B'; + XTermToAnsiTable[13] = 'M'; + XTermToAnsiTable[14] = 'C'; + XTermToAnsiTable[15] = 'W'; + XTermToAnsiTable[16] = 'w'; + XTermToAnsiTable[17] = 'b'; + XTermToAnsiTable[18] = 'b'; + XTermToAnsiTable[19] = 'b'; + XTermToAnsiTable[20] = 'B'; + XTermToAnsiTable[21] = 'B'; + XTermToAnsiTable[22] = 'g'; + XTermToAnsiTable[23] = 'c'; + XTermToAnsiTable[24] = 'c'; + XTermToAnsiTable[25] = 'c'; + XTermToAnsiTable[26] = 'c'; + XTermToAnsiTable[27] = 'B'; + XTermToAnsiTable[28] = 'g'; + XTermToAnsiTable[29] = 'c'; + XTermToAnsiTable[30] = 'c'; + XTermToAnsiTable[31] = 'c'; + XTermToAnsiTable[32] = 'c'; + XTermToAnsiTable[33] = 'C'; + XTermToAnsiTable[34] = 'g'; + XTermToAnsiTable[35] = 'c'; + XTermToAnsiTable[36] = 'c'; + XTermToAnsiTable[37] = 'c'; + XTermToAnsiTable[38] = 'C'; + XTermToAnsiTable[39] = 'C'; + XTermToAnsiTable[40] = 'G'; + XTermToAnsiTable[41] = 'c'; + XTermToAnsiTable[42] = 'c'; + XTermToAnsiTable[43] = 'C'; + XTermToAnsiTable[44] = 'C'; + XTermToAnsiTable[45] = 'C'; + XTermToAnsiTable[46] = 'G'; + XTermToAnsiTable[47] = 'G'; + XTermToAnsiTable[48] = 'C'; + XTermToAnsiTable[49] = 'C'; + XTermToAnsiTable[50] = 'C'; + XTermToAnsiTable[51] = 'C'; + XTermToAnsiTable[52] = 'r'; + XTermToAnsiTable[53] = 'm'; + XTermToAnsiTable[54] = 'm'; + XTermToAnsiTable[55] = 'm'; + XTermToAnsiTable[56] = 'm'; + XTermToAnsiTable[57] = 'B'; + XTermToAnsiTable[58] = 'y'; + XTermToAnsiTable[59] = 'D'; + XTermToAnsiTable[60] = 'D'; + XTermToAnsiTable[61] = 'D'; + XTermToAnsiTable[62] = 'D'; + XTermToAnsiTable[63] = 'B'; + XTermToAnsiTable[64] = 'y'; + XTermToAnsiTable[65] = 'D'; + XTermToAnsiTable[66] = 'D'; + XTermToAnsiTable[67] = 'D'; + XTermToAnsiTable[68] = 'D'; + XTermToAnsiTable[69] = 'w'; + XTermToAnsiTable[70] = 'y'; + XTermToAnsiTable[71] = 'D'; + XTermToAnsiTable[72] = 'D'; + XTermToAnsiTable[73] = 'D'; + XTermToAnsiTable[74] = 'w'; + XTermToAnsiTable[75] = 'w'; + XTermToAnsiTable[76] = 'y'; + XTermToAnsiTable[77] = 'D'; + XTermToAnsiTable[78] = 'D'; + XTermToAnsiTable[79] = 'w'; + XTermToAnsiTable[80] = 'w'; + XTermToAnsiTable[81] = 'C'; + XTermToAnsiTable[82] = 'G'; + XTermToAnsiTable[83] = 'G'; + XTermToAnsiTable[84] = 'w'; + XTermToAnsiTable[85] = 'w'; + XTermToAnsiTable[86] = 'C'; + XTermToAnsiTable[87] = 'C'; + XTermToAnsiTable[88] = 'r'; + XTermToAnsiTable[89] = 'm'; + XTermToAnsiTable[90] = 'm'; + XTermToAnsiTable[91] = 'm'; + XTermToAnsiTable[92] = 'm'; + XTermToAnsiTable[93] = 'M'; + XTermToAnsiTable[94] = 'y'; + XTermToAnsiTable[95] = 'D'; + XTermToAnsiTable[96] = 'D'; + XTermToAnsiTable[97] = 'D'; + XTermToAnsiTable[98] = 'D'; + XTermToAnsiTable[99] = 'w'; + XTermToAnsiTable[100] = 'y'; + XTermToAnsiTable[101] = 'D'; + XTermToAnsiTable[102] = 'D'; + XTermToAnsiTable[103] = 'D'; + XTermToAnsiTable[104] = 'w'; + XTermToAnsiTable[105] = 'w'; + XTermToAnsiTable[106] = 'y'; + XTermToAnsiTable[107] = 'D'; + XTermToAnsiTable[108] = 'D'; + XTermToAnsiTable[109] = 'w'; + XTermToAnsiTable[110] = 'w'; + XTermToAnsiTable[111] = 'w'; + XTermToAnsiTable[112] = 'y'; + XTermToAnsiTable[113] = 'D'; + XTermToAnsiTable[114] = 'w'; + XTermToAnsiTable[115] = 'w'; + XTermToAnsiTable[116] = 'w'; + XTermToAnsiTable[117] = 'w'; + XTermToAnsiTable[118] = 'Y'; + XTermToAnsiTable[119] = 'w'; + XTermToAnsiTable[120] = 'w'; + XTermToAnsiTable[121] = 'w'; + XTermToAnsiTable[122] = 'w'; + XTermToAnsiTable[123] = 'w'; + XTermToAnsiTable[124] = 'r'; + XTermToAnsiTable[125] = 'm'; + XTermToAnsiTable[126] = 'm'; + XTermToAnsiTable[127] = 'm'; + XTermToAnsiTable[128] = 'M'; + XTermToAnsiTable[129] = 'M'; + XTermToAnsiTable[130] = 'y'; + XTermToAnsiTable[131] = 'D'; + XTermToAnsiTable[132] = 'D'; + XTermToAnsiTable[133] = 'D'; + XTermToAnsiTable[134] = 'w'; + XTermToAnsiTable[135] = 'w'; + XTermToAnsiTable[136] = 'y'; + XTermToAnsiTable[137] = 'D'; + XTermToAnsiTable[138] = 'D'; + XTermToAnsiTable[139] = 'w'; + XTermToAnsiTable[140] = 'w'; + XTermToAnsiTable[141] = 'w'; + XTermToAnsiTable[142] = 'y'; + XTermToAnsiTable[143] = 'D'; + XTermToAnsiTable[144] = 'w'; + XTermToAnsiTable[145] = 'w'; + XTermToAnsiTable[146] = 'w'; + XTermToAnsiTable[147] = 'w'; + XTermToAnsiTable[148] = 'Y'; + XTermToAnsiTable[149] = 'w'; + XTermToAnsiTable[150] = 'w'; + XTermToAnsiTable[151] = 'w'; + XTermToAnsiTable[152] = 'w'; + XTermToAnsiTable[153] = 'w'; + XTermToAnsiTable[154] = 'Y'; + XTermToAnsiTable[155] = 'w'; + XTermToAnsiTable[156] = 'w'; + XTermToAnsiTable[157] = 'w'; + XTermToAnsiTable[158] = 'w'; + XTermToAnsiTable[159] = 'W'; + XTermToAnsiTable[160] = 'R'; + XTermToAnsiTable[161] = 'm'; + XTermToAnsiTable[162] = 'm'; + XTermToAnsiTable[163] = 'M'; + XTermToAnsiTable[164] = 'M'; + XTermToAnsiTable[165] = 'M'; + XTermToAnsiTable[166] = 'y'; + XTermToAnsiTable[167] = 'D'; + XTermToAnsiTable[168] = 'D'; + XTermToAnsiTable[169] = 'w'; + XTermToAnsiTable[170] = 'w'; + XTermToAnsiTable[171] = 'M'; + XTermToAnsiTable[172] = 'y'; + XTermToAnsiTable[173] = 'D'; + XTermToAnsiTable[174] = 'w'; + XTermToAnsiTable[175] = 'w'; + XTermToAnsiTable[176] = 'w'; + XTermToAnsiTable[177] = 'w'; + XTermToAnsiTable[178] = 'Y'; + XTermToAnsiTable[179] = 'w'; + XTermToAnsiTable[180] = 'w'; + XTermToAnsiTable[181] = 'w'; + XTermToAnsiTable[182] = 'w'; + XTermToAnsiTable[183] = 'w'; + XTermToAnsiTable[184] = 'Y'; + XTermToAnsiTable[185] = 'w'; + XTermToAnsiTable[186] = 'w'; + XTermToAnsiTable[187] = 'w'; + XTermToAnsiTable[188] = 'w'; + XTermToAnsiTable[189] = 'W'; + XTermToAnsiTable[190] = 'Y'; + XTermToAnsiTable[191] = 'Y'; + XTermToAnsiTable[192] = 'w'; + XTermToAnsiTable[193] = 'w'; + XTermToAnsiTable[194] = 'W'; + XTermToAnsiTable[195] = 'W'; + XTermToAnsiTable[196] = 'R'; + XTermToAnsiTable[197] = 'R'; + XTermToAnsiTable[198] = 'M'; + XTermToAnsiTable[199] = 'M'; + XTermToAnsiTable[200] = 'M'; + XTermToAnsiTable[201] = 'M'; + XTermToAnsiTable[202] = 'R'; + XTermToAnsiTable[203] = 'R'; + XTermToAnsiTable[204] = 'w'; + XTermToAnsiTable[205] = 'w'; + XTermToAnsiTable[206] = 'M'; + XTermToAnsiTable[207] = 'M'; + XTermToAnsiTable[208] = 'Y'; + XTermToAnsiTable[209] = 'w'; + XTermToAnsiTable[210] = 'w'; + XTermToAnsiTable[211] = 'w'; + XTermToAnsiTable[212] = 'w'; + XTermToAnsiTable[213] = 'w'; + XTermToAnsiTable[214] = 'Y'; + XTermToAnsiTable[215] = 'w'; + XTermToAnsiTable[216] = 'w'; + XTermToAnsiTable[217] = 'w'; + XTermToAnsiTable[218] = 'w'; + XTermToAnsiTable[219] = 'W'; + XTermToAnsiTable[220] = 'Y'; + XTermToAnsiTable[221] = 'Y'; + XTermToAnsiTable[222] = 'w'; + XTermToAnsiTable[223] = 'w'; + XTermToAnsiTable[224] = 'W'; + XTermToAnsiTable[225] = 'W'; + XTermToAnsiTable[226] = 'Y'; + XTermToAnsiTable[227] = 'Y'; + XTermToAnsiTable[228] = 'w'; + XTermToAnsiTable[229] = 'W'; + XTermToAnsiTable[230] = 'W'; + XTermToAnsiTable[231] = 'W'; + XTermToAnsiTable[232] = 'w'; + XTermToAnsiTable[233] = 'w'; + XTermToAnsiTable[234] = 'w'; + XTermToAnsiTable[235] = 'w'; + XTermToAnsiTable[236] = 'w'; + XTermToAnsiTable[237] = 'w'; + XTermToAnsiTable[238] = 'D'; + XTermToAnsiTable[239] = 'D'; + XTermToAnsiTable[240] = 'D'; + XTermToAnsiTable[241] = 'D'; + XTermToAnsiTable[242] = 'D'; + XTermToAnsiTable[243] = 'D'; + XTermToAnsiTable[244] = 'D'; + XTermToAnsiTable[245] = 'D'; + XTermToAnsiTable[246] = 'D'; + XTermToAnsiTable[247] = 'D'; + XTermToAnsiTable[248] = 'w'; + XTermToAnsiTable[249] = 'w'; + XTermToAnsiTable[250] = 'w'; + XTermToAnsiTable[251] = 'w'; + XTermToAnsiTable[252] = 'w'; + XTermToAnsiTable[253] = 'w'; + XTermToAnsiTable[254] = 'W'; + XTermToAnsiTable[255] = 'W'; + } + + /// + /// Check if a char code is ANSI color code. + /// + /// Char to check for. + /// + public static bool IsColorCode(char code) + { + // Don't allow black color, we can't see it + if(code == 'd') + return false; + + foreach(ColorEntry x in ColorEntries) + { + if(x.ColorChar == code) + return true; + } + + return false; + } + + /// + /// Convert normal colors to HTML colors. It converts inserting </font> in front of every color too + /// so you need to have started with some font already. + /// + /// Message to convert colors in. + /// + public static string GetHTMLColors(string Msg) + { + Msg = Msg.Replace("@@", colorEscape); + foreach(ColorEntry c in ColorEntries) + Msg = Msg.Replace("@" + c.ColorChar, ""); + Msg = Msg.Replace(colorEscape, "@"); + return Msg; + } + + // Any codes that aren't xterm and aren't listed here will be @e instead of escape char. + private static ColorEntry[] ColorEntries = new[] + { + new ColorEntry('w', "", "", "grey", "C0C0C0"), + new ColorEntry('W', "", "", "white", "FFFFFF"), + new ColorEntry('G', "", "", "green", "00FF00"), + new ColorEntry('g', "", "", "dark green", "008000"), + new ColorEntry('R', "", "", "red", "FF0000"), + new ColorEntry('r', "", "", "dark red", "800000"), + new ColorEntry('Y', "", "", "yellow", "FFFF00"), + new ColorEntry('y', "", "", "dark yellow", "808000"), + new ColorEntry('C', "", "", "cyan", "00FFFF"), + new ColorEntry('c', "", "", "dark cyan", "008080"), + new ColorEntry('B', "", "", "blue", "0000FF"), + new ColorEntry('b', "", "", "dark blue", "000080"), + new ColorEntry('M', "", "", "magenta", "FF00FF"), + new ColorEntry('m', "", "", "dark magenta", "800080"), + new ColorEntry('D', "", "", "dark grey", "808080"), + new ColorEntry('d', "", "", "black", "000000"), + new ColorEntry('q', "", "", "default", "C0C0C0") + }; + + /// + /// Get last color code in the string (not including foreground colors). This will return + /// with the @ sign. + /// + /// + /// + public static string GetLastColorCode(string text) + { + text = text.Replace("@@", colorEscape); + + // Start checking from the end + for(int i = text.Length - 1; i >= 0; i--) + { + if(text[i] == '@' && i + 1 < text.Length && text[i + 1] != 'f' && text[i + 1] != 'y') + { + if(text[i + 1] == 'x') + { + int len; + string code = GetXTerm(text, i, out len).ToString(); + if(len == 0) + continue; + + if(code.Length == 1) + code = "00" + code; + else if(code.Length == 2) + code = "0" + code; + + return "@x" + code; + } + else + return "@" + text[i + 1]; + } + } + + return string.Empty; + } + + /// + /// Removes duplicate colors from a string. For example "@r @Y bla@w" would become " @Ybla". + /// Also XTERM color codes become padded with zero if they are present. + /// + /// String to fix colors in. + /// + public static string RemoveDuplicateColors(string orig) + { + StringBuilder txt = new StringBuilder(); + + string currentColor = ""; + bool didWriteColor = false; + bool hasAt = false; + bool hasE = false; + + for(int i = 0; i < orig.Length; i++) + { + switch(orig[i]) + { + case '@': + { + if(hasAt) + { + if(!didWriteColor) + { + txt.Append(currentColor); + didWriteColor = true; + } + + txt.Append("@@"); + hasAt = false; + } + else + { + hasAt = true; + } + } break; + + case ' ': + case '\r': + case '\n': + case '\t': + txt.Append(orig[i]); + break; + + default: + { + if(hasAt) + { + if(orig[i] == 'e') + { + txt.Append("@e"); + hasAt = false; + hasE = true; + continue; + } + if(orig[i] == 'f') + { + if(i + 1 < orig.Length) + txt.Append("@f" + orig[i + 1]); + i++; + hasAt = false; + continue; + } + if(orig[i] == 'z') + { + int len; + string code = GetXTerm(orig, i - 1, out len).ToString(); + if(len > 0) + { + if(code.Length == 1) + code = "00" + code; + else if(code.Length == 2) + code = "0" + code; + txt.Append("@z" + code); + i += len; + } + hasAt = false; + continue; + } + if(orig[i] == 'x') + { + int len; + string code = GetXTerm(orig, i - 1, out len).ToString(); + if(len > 0) + { + if(code.Length == 1) + code = "00" + code; + else if(code.Length == 2) + code = "0" + code; + i += len; + if(currentColor != "@x" + code) + { + currentColor = "@x" + code; + didWriteColor = false; + } + } + hasAt = false; + continue; + } + if(currentColor != "@" + orig[i]) + { + currentColor = "@" + orig[i]; + didWriteColor = false; + } + hasAt = false; + } + else if(hasE) + { + txt.Append(orig[i]); + if(orig[i] == 'm') + hasE = false; + } + else + { + if(!didWriteColor) + { + txt.Append(currentColor); + didWriteColor = true; + } + + txt.Append(orig[i]); + } + } break; + } + } + + return txt.ToString(); + } + + /// + /// This is what we turn the @ into so we can replace colors and keep the symbol intact + /// + private const string colorEscape = "#\r\ncolor_escape_sequence\r\n#"; + + /// + /// This function will turn either ANSI color to our format or vice versa. + /// + /// String passed for color changing. + /// False means we change our format (@x) to ANSI; true means we change ANSI to our format (we don't convert XTERM colors this way though). + /// Allow replacing xterm colors? If disabled we will replace into closest ANSI. + /// + public static string FixColors(string text, bool fromRaw, bool allowXTerm) + { + if(fromRaw == false) + { + text = text.Replace("@@", colorEscape); + text = ReplaceXTerm(text, fromRaw, allowXTerm); + for(int i = 0; i < ColorEntries.Length; i++) + { + text = text.Replace("@" + ColorEntries[i].ColorChar, ColorEntries[i].ANSI); + text = text.Replace("@f" + ColorEntries[i].ColorChar, ColorEntries[i].ForeANSI); + } + text = text.Replace("@e", ""); + text = text.Replace(colorEscape, "@"); + } + else + { + text = text.Replace("@", colorEscape); + text = ReplaceXTerm(text, fromRaw, allowXTerm); + for(int i = 0; i < ColorEntries.Length; i++) + { + text = text.Replace(ColorEntries[i].ANSI, "@" + ColorEntries[i].ColorChar); + text = text.Replace(ColorEntries[i].ForeANSI, "@f" + ColorEntries[i].ColorChar); + } + text = text.Replace("", "@e"); + text = text.Replace(colorEscape, "@@"); + } + return text; + } + + /// + /// Remove dark grey color code from string and replace it with normal grey. + /// + /// String to remove dark grey from (replacing it with normal grey). + /// + public static string RemoveGray(string text) + { + text = text.Replace("@@", colorEscape); + text = text.Replace("@D", "@w"); + text = text.Replace("@fD", "@fw"); + text = text.Replace(colorEscape, "@@"); + return text; + } + + /// + /// This function will Remove all color from the string. + /// + /// String where the color is being removed. + /// True means raw color (ansi); false means our format (@x). + /// + public static string RemoveColors(string text, bool raw) + { + if(!raw) + { + text = text.Replace("@@", colorEscape); + for(int i = 0; i < ColorEntries.Length; i++) + { + text = text.Replace("@" + ColorEntries[i].ColorChar, ""); + text = text.Replace("@f" + ColorEntries[i].ColorChar, ""); + } + int j; + while((j = text.IndexOf("@x")) != -1 || (j = text.IndexOf("@z")) != -1) + text = text.Remove(j, 5); + text = text.Replace(colorEscape, "@"); + return text; + } + + for(int i = 0; i < ColorEntries.Length; i++) + { + text = text.Replace(ColorEntries[i].ANSI, ""); + text = text.Replace(ColorEntries[i].ForeANSI, ""); + } + + int k; + while((k = text.IndexOf("")) != -1) + { + int l = text.IndexOf('m', k); + if(l == -1) + break; + text = text.Remove(k, l - k); + } + return text; + } + + /// + /// Get XTerm color code from text in index (index must be at @x or @z, before it). + /// + /// Text to get color code from. + /// Index of @z or @x. + /// + public static byte GetXTerm(string text, int index, out int xlen) + { + // Skip @x or @z + index += 2; + + // Get byte number now + byte v = GetXTermCode(text, index, out xlen); + return v; + } + + /// + /// Get full escape string from string in index. + /// + /// Text to search from. + /// Index in text of @e + /// Length of the thing behind @e. + /// + public static string GetEscape(string text, int index, out int xlen) + { + index += 2; + if((xlen = text.IndexOf('m', index)) == -1) + { + xlen = 0; + return "@e[0m"; + } + + xlen++; // include the 'm' + xlen -= index; + return "@e" + text.Substring(index, xlen); + } + + /// + /// Get XTerm color code from text in index (index must be at the number not before @x or @z like the other function) + /// + /// Text to get color code from. + /// Index of number. + /// Length of the number. + /// + public static byte GetXTermCode(string text, int index, out int xlen) + { + int len = 0; + while(len < 3 && index + len < text.Length && char.IsNumber(text[index + len])) + len++; + + byte v = 0; + while(len > 0 && !byte.TryParse(text.Substring(index, len), out v)) + len--; + + if(len == 0) + v = 0; + xlen = len; + return v; + } + + /// + /// Replace XTerm color codes into real XTerm or ANSI values. + /// + /// Text to search in. + /// Replace into XTerm codes or if false then convert to closest regular ANSI. + /// + public static string ReplaceXTerm(string text, bool fromRaw, bool allowXTerm) + { + if(fromRaw == false) + { + int index = -1; + while((index = text.IndexOf("@x")) != -1) + { + int len; + byte code = GetXTerm(text, index, out len); + text = text.Remove(index, len + 2); + if(allowXTerm) + text = text.Insert(index, "[38;5;" + code.ToString() + "m"); + else + text = text.Insert(index, "@" + XTermToANSI(code)); + } + while((index = text.IndexOf("@z")) != -1) + { + int len; + byte code = GetXTerm(text, index, out len); + text = text.Remove(index, len + 2); + if(allowXTerm) + text = text.Insert(index, "[48;5;" + code.ToString() + "m"); + else + text = text.Insert(index, "@f" + XTermToANSI(code)); + } + } + else + { + int index = -1; + while((index = text.IndexOf("[38;5;")) != -1) + { + int len; + byte c = GetXTermCode(text, index + 7, out len); + string code = c.ToString(); + if(code.Length == 1) + code = "00" + code; + else if(code.Length == 2) + code = "0" + code; + text = text.Remove(index, len + 8); + if(allowXTerm) + text = text.Insert(index, "@x" + code); + else + text = text.Insert(index, "@" + XTermToANSI(c)); + } + while((index = text.IndexOf("[48;5;")) != -1) + { + int len; + byte c = GetXTermCode(text, index + 7, out len); + string code = c.ToString(); + if(code.Length == 1) + code = "00" + code; + else if(code.Length == 2) + code = "0" + code; + text = text.Remove(index, len + 8); + if(allowXTerm) + text = text.Insert(index, "@z" + code); + else + text = text.Insert(index, "@" + XTermToANSI(c)); + } + } + return text; + } + + private static readonly char[] XTermToAnsiTable = new char[256]; + + /// + /// Convert XTerm to ansi char (closest match). + /// + /// Code to convert. + /// + public static char XTermToANSI(byte code) + { + return XTermToAnsiTable[(int)code]; + } + } + + internal class ColorEntry + { + internal ColorEntry(char colorChar, string ansi, string foreansi, string name, string hex) + { + ColorChar = colorChar; + ANSI = ansi; + ForeANSI = foreansi; + Name = name; + HEX = hex; + } + + public readonly char ColorChar; + public readonly string ANSI; + public readonly string ForeANSI; + public readonly string Name; + public readonly string HEX; + } +} diff --git a/ProxyCore/Utility/Config.cs b/ProxyCore/Utility/Config.cs new file mode 100644 index 0000000..e358018 --- /dev/null +++ b/ProxyCore/Utility/Config.cs @@ -0,0 +1,333 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.IO; +using System.Text.RegularExpressions; +using System.Globalization; + +namespace ProxyCore +{ + public class ConfigFile + { + protected ConfigFile() + { + + } + + private string Filepath; + + /// + /// Did we successfully load the config file? If not then it was probably missing. + /// + public bool DidLoad + { + get; + private set; + } + + /// + /// Load a configuration file. + /// + /// Configuration name - for example "server". This should be your plugin name. + /// + internal void Load(string fileName) + { + fileName = "config." + fileName + ".txt"; + _cfgData.Clear(); + Filepath = fileName; + OnCreated(); + + if(_cfgData.Count == 0) + return; + + StreamReader f = null; + try + { + f = new StreamReader(fileName); + } + catch(FileNotFoundException) + { + SaveNew(); + return; + } + catch + { + return; + } + + string l; + while((l = f.ReadLine()) != null) + { + l = l.Trim(); + if(string.IsNullOrEmpty(l) || l.StartsWith("#") || l.StartsWith(";") || l.StartsWith("//")) + continue; + + Match m = _loadRegex.Match(l); + if(!m.Success) + continue; + + string Key = m.Groups[1].Value.ToLower(); + if(!_cfgData.ContainsKey(Key)) + continue; + + string Value = m.Groups[3].Value; + if(Value.Contains('"') && _cfgData[Key].DefaultValue is string) + Value = Value.Substring(1, Value.Length - 2); + + if(_cfgData[Key].DefaultValue is int) + { + int i; + if(!int.TryParse(Value, out i)) + continue; + + _cfgData[Key].Value = i; + } + else if(_cfgData[Key].DefaultValue is uint) + { + uint i; + if(!uint.TryParse(Value, out i)) + continue; + + _cfgData[Key].Value = i; + } + else if(_cfgData[Key].DefaultValue is long) + { + long i; + if(!long.TryParse(Value, out i)) + continue; + + _cfgData[Key].Value = i; + } + else if(_cfgData[Key].DefaultValue is ulong) + { + ulong i; + if(!ulong.TryParse(Value, out i)) + continue; + + _cfgData[Key].Value = i; + } + else if(_cfgData[Key].DefaultValue is string) + { + _cfgData[Key].Value = Value; + } + else if(_cfgData[Key].DefaultValue is float) + { + try + { + float i = Convert.ToSingle(Value, CultureInfo.InvariantCulture.NumberFormat); + _cfgData[Key].Value = i; + } + catch + { + continue; + } + } + else if(_cfgData[Key].DefaultValue is double) + { + try + { + double i = Convert.ToDouble(Value, CultureInfo.InvariantCulture.NumberFormat); + _cfgData[Key].Value = i; + } + catch + { + continue; + } + } + } + + f.Close(); + } + + /// + /// Regex pattern used to load a line from config file. + /// Groups[1]: Name of setting + /// Groups[3]: Value of setting (including "" if string) + /// + private static readonly Regex _loadRegex = new Regex("([\\w\\.]+)\\s*(=|:|-)\\s*((\".*\")|(-?\\d+\\.\\d+)|(-?\\d+))", RegexOptions.Compiled); + + /// + /// Save a new configuration file with default values. If there is an existing config file, it will be replaced. + /// + public void SaveNew() + { + if(string.IsNullOrEmpty(Filepath) || _cfgData.Count == 0) + return; + + StreamWriter f = null; + try + { + f = new StreamWriter(Filepath, false); + } + catch + { + return; + } + + foreach(KeyValuePair x in _cfgData) + { + f.WriteLine("###############################################################################"); + f.WriteLine("#"); + f.WriteLine("# " + x.Value.Key); + if(!string.IsNullOrEmpty(x.Value.Desc)) + { + string[] oDesc = Utility.WrapColored(x.Value.Desc, 70, 0); + for(int i = 0; i < oDesc.Length; i++) + f.WriteLine("# " + oDesc[i]); + } + f.WriteLine("#"); + f.WriteLine("###############################################################################"); + f.WriteLine(""); + f.WriteLine(x.Value.Key + " = " + ((x.Value.DefaultValue is string) ? ("\"" + x.Value.DefaultValue + "\"") : x.Value.DefaultValue.ToString().Replace(",", "."))); + f.WriteLine(""); + } + + f.Close(); + } + + /// + /// This will be called to populate config data with default values and descriptions. + /// + protected virtual void OnCreated() + { + } + + /// + /// Create a new setting for the file. If setting with this name already exists then skip. + /// + /// Setting name. + /// Default value for setting. Make sure to use type casting if not integer. + /// Description to write in the file for this setting. + protected void CreateSetting(string Key, object Value, string Desc) + { + if(_cfgData.ContainsKey(Key.ToLower().Trim())) + return; + + CfgEntry e = new CfgEntry() + { + Key = Key, + Value = Value, + DefaultValue = Value, + Desc = Desc + }; + + _cfgData[Key.ToLower().Trim()] = e; + } + + /// + /// Read a 32 bit integer value from configuration file. + /// + /// Name of the option. + /// Default value if config is missing this option or is invalid. + /// + public int GetInt32(string Key, int Default) + { + Key = Key.ToLower().Trim(); + if(string.IsNullOrEmpty(Key) || !_cfgData.ContainsKey(Key) || !(_cfgData[Key].Value is int)) + return Default; + + return (int)_cfgData[Key].Value; + } + + /// + /// Read a 32 bit unsigned integer value from configuration file. + /// + /// Name of the option. + /// Default value if config is missing this option or is invalid. + /// + public uint GetUInt32(string Key, uint Default) + { + Key = Key.ToLower().Trim(); + if(string.IsNullOrEmpty(Key) || !_cfgData.ContainsKey(Key) || !(_cfgData[Key].Value is uint)) + return Default; + + return (uint)_cfgData[Key].Value; + } + + /// + /// Read a 64 bit integer value from configuration file. + /// + /// Name of the option. + /// Default value if config is missing this option or is invalid. + /// + public long GetInt64(string Key, long Default) + { + Key = Key.ToLower().Trim(); + if(string.IsNullOrEmpty(Key) || !_cfgData.ContainsKey(Key) || !(_cfgData[Key].Value is long)) + return Default; + + return (long)_cfgData[Key].Value; + } + + /// + /// Read a 64 bit unsigned integer value from configuration file. + /// + /// Name of the option. + /// Default value if config is missing this option or is invalid. + /// + public ulong GetUInt64(string Key, ulong Default) + { + Key = Key.ToLower().Trim(); + if(string.IsNullOrEmpty(Key) || !_cfgData.ContainsKey(Key) || !(_cfgData[Key].Value is ulong)) + return Default; + + return (ulong)_cfgData[Key].Value; + } + + /// + /// Read a float value from configuration file. + /// + /// Name of the option. + /// Default value if config is missing this option or is invalid. + /// + public float GetFloat(string Key, float Default) + { + Key = Key.ToLower().Trim(); + if(string.IsNullOrEmpty(Key) || !_cfgData.ContainsKey(Key) || !(_cfgData[Key].Value is float)) + return Default; + + return (float)_cfgData[Key].Value; + } + + /// + /// Read a double value from configuration file. + /// + /// Name of the option. + /// Default value if config is missing this option or is invalid. + /// + public double GetDouble(string Key, double Default) + { + Key = Key.ToLower().Trim(); + if(string.IsNullOrEmpty(Key) || !_cfgData.ContainsKey(Key) || !(_cfgData[Key].Value is double)) + return Default; + + return (double)_cfgData[Key].Value; + } + + /// + /// Read a string value from configuration file. + /// + /// Name of the option. + /// Default value if config is missing this option or is invalid. + /// + public string GetString(string Key, string Default) + { + Key = Key.ToLower().Trim(); + if(string.IsNullOrEmpty(Key) || !_cfgData.ContainsKey(Key) || !(_cfgData[Key].Value is string)) + return Default; + + return (string)_cfgData[Key].Value; + } + + private Dictionary _cfgData = new Dictionary(); + + private class CfgEntry + { + public string Key; + public object Value; + public object DefaultValue; + public string Desc; + } + } +} diff --git a/ProxyCore/Utility/JSON.cs b/ProxyCore/Utility/JSON.cs new file mode 100644 index 0000000..f13972c --- /dev/null +++ b/ProxyCore/Utility/JSON.cs @@ -0,0 +1,54 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Jayrock.Json; +using Jayrock.Json.Conversion; + +namespace ProxyCore +{ + internal static class JSON + { + internal static bool Parse(string msg, string module, List> data) + { + try + { + JsonObject obj = (JsonObject)JsonConvert.Import(msg); + Explore(module, obj, data); + } + catch + { + //data.Clear(); + return false; + } + return true; + } + + private static void Explore(string nameSpace, JsonObject obj, List> x) + { + var keys = obj.Names; + foreach(string i in keys) + ExplorePair(nameSpace + "." + i, obj[i], x); + } + + private static void ExplorePair(string nameSpace, object obj, List> x) + { + if((obj is JsonNumber) || + (obj is JsonNull) || + (obj is string) || + (obj is JsonBoolean) || + (obj is JsonString)) + x.Add(new KeyValuePair(nameSpace, obj.ToString())); + else if(obj is JsonArray) + { + foreach(JsonObject i in (JsonArray)obj) + Explore(nameSpace, i, x); + } + else if(obj is JsonObject) + Explore(nameSpace, (JsonObject)obj, x); + else if(obj == null) + x.Add(new KeyValuePair(nameSpace, "null")); + else throw new Exception(); + } + } +} diff --git a/ProxyCore/Utility/ServerConfig.cs b/ProxyCore/Utility/ServerConfig.cs new file mode 100644 index 0000000..4bd043f --- /dev/null +++ b/ProxyCore/Utility/ServerConfig.cs @@ -0,0 +1,46 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using ProxyCore; + +namespace ProxyCore +{ + public class ServerConfig : ConfigFile + { + public ServerConfig() + { + Load("server"); + } + + protected override void OnCreated() + { + base.OnCreated(); + + CreateSetting("Listen.Address", "127.0.0.1", "This is the address that the proxy program will be listening on. You will have to connect to this address with your MUD client. Enter 127.0.0.1 to listen only on current computer, enter LAN IP to listen only in your home network or enter 0.0.0.0 to listen on all addresses (even remote)."); + CreateSetting("Listen.Port", 4000, "This is the port that the proxy program will be listening on. You will have to enter this port in your MUD client. If you want remote connections you may have to open this port (TCP) in your firewall."); + CreateSetting("MUD.Address", "aardmud.org", "This is the address for MUD connection."); + CreateSetting("MUD.Port", 4000, "This is the port for MUD connection."); + CreateSetting("Passwords", "", "Passwords for the proxy and their user levels. For example: \"abc->1,def->2,ghi321->1\". If user enters def as password they will get user level 2. Enter as many passwords as you like. If you leave this empty, the proxy will not ask for a password and user will be authed with level 1. The password values should be between 1 and 64."); + CreateSetting("GMCP.Supports", "Core=1, Char=1, Room=1, Comm=1", "What GMCP options do we have on by default? These are modules only needed for the proxy. If your client needs another module it will enable it itself - no need to change here."); + CreateSetting("AutoConnect", 0, "Proxy program will always automatically (re)connect to MUD if there is a client online in the proxy. If there is no client online the proxy will not automatically connect. Enabling this option will force the proxy to always auto (re)connect."); + CreateSetting("ClientCompression", 1, "Enable compression for connected clients (MUD compression will always be on, even if you disable this option). Don't disable unless you are having problems with compression and can't disable client side."); + } + } + + public class CoreConfig : ConfigFile + { + public CoreConfig() + { + Load("core"); + } + + protected override void OnCreated() + { + base.OnCreated(); + + CreateSetting("Updates.Core", 1, "Automatically check updates for core."); + CreateSetting("Updates.Plugins", 1, "Automatically check updates for plugins."); + } + } +} diff --git a/ProxyCore/Utility/Wrap.cs b/ProxyCore/Utility/Wrap.cs new file mode 100644 index 0000000..b73ed1a --- /dev/null +++ b/ProxyCore/Utility/Wrap.cs @@ -0,0 +1,141 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace ProxyCore +{ + public partial class Utility + { + public static string[] WrapColored(string text, int maxLength, int IndentSize) + { + if(maxLength <= 2) + return null; + + if(text.Length <= maxLength) + return new string[1] { text }; + + StringBuilder wrapBuilder = new StringBuilder(); + int count = 0; + bool printed = false; + int lastOk = 0; + int realLength = 0; + int fakeIndex = 0; + text = text.TrimEnd(); + bool didAt = false; + bool doNow = false; + for(int i = 0; i < text.Length; i++) + { + switch(text[i]) + { + case ' ': + /*case ',': + case '.': + case '?': + case '!': + case ':': + case ';': + case ')': + case ']': + case '}': + case '-':*/ + case '\t': + lastOk = i; + realLength++; + break; + + case '\n': + case '\r': + doNow = true; + lastOk = i; + realLength++; + break; + + case '@': + if(didAt) + realLength++; + didAt = !didAt; + break; + + default: + if(!didAt) + realLength++; + else + didAt = false; + break; + } + + if(realLength >= maxLength || doNow) + { + if(printed && IndentSize > 0) + wrapBuilder.Append(' ', IndentSize); + if(lastOk > 0) + { + wrapBuilder.Append(text.Substring(fakeIndex, lastOk - fakeIndex + 1).TrimEnd() + Environment.NewLine); + i = lastOk; + } + else + wrapBuilder.Append(text.Substring(fakeIndex, i - fakeIndex + 1).TrimEnd() + Environment.NewLine); + + fakeIndex = lastOk > 0 ? lastOk + 1 : i + 1; + lastOk = 0; + realLength = IndentSize; + printed = true; + count++; + doNow = false; + } + } + + if(fakeIndex < text.Length - 1) + { + if(printed && IndentSize > 0) + wrapBuilder.Append(' ', IndentSize); + wrapBuilder.Append(text.Substring(fakeIndex, text.Length - fakeIndex).TrimEnd() + Environment.NewLine); + count++; + } + + List lp = wrapBuilder.ToString().Split(new[] { Environment.NewLine }, StringSplitOptions.None).ToList(); + lp.RemoveAt(lp.Count - 1); + return lp.ToArray(); + } + + public static string FormatColoredString(string msg, int len) + { + StringBuilder str = new StringBuilder(); + int real = 0; + bool at = false; + for(int i = 0; i < msg.Length; i++) + { + if(msg[i] == '@') + { + if(at) + { + real++; + str.Append("@@"); + } + at = !at; + } + else if(at) + { + str.Append("@" + msg[i].ToString()); + at = false; + } + else + { + str.Append(msg[i]); + real++; + } + } + + if(real < Math.Abs(len)) + { + if(len < 0) + str.Append(' ', Math.Abs(len) - real); + else + str.Insert(0, " ", len - real); + } + + return str.ToString(); + } + } +} diff --git a/ProxyCore/Utility/desktop.ini b/ProxyCore/Utility/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/ProxyCore/Utility/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/ProxyCore/World.cs b/ProxyCore/World.cs new file mode 100644 index 0000000..b04b185 --- /dev/null +++ b/ProxyCore/World.cs @@ -0,0 +1,647 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using ProxyCore.Input; +using ProxyCore.Output; +using ProxyCore.Messages; +using ProxyCore.Scripting; +using System.Net; +using System.IO; +using System.Text.RegularExpressions; + +namespace ProxyCore +{ + public class World + { + public World() + { + Instance = this; + Log.Write("Loading plugins..."); + PluginMgr.LoadAll(); + TriggerHandler.RegisterTrigger("core.login", @"^\$gmcp\.char\.vitals\.hp ", _GMCPHP); + InputHandler.RegisterCommand("commands", "", _Commands, CMDFlags.None, null, 0, ulong.MaxValue, "core", 8); + InputHandler.RegisterCommand("lastlines", @"^(\d+)$", _LineInfo, CMDFlags.None, null, 0, ulong.MaxValue, "core", 8); + InputHandler.RegisterCommand("plugins", @"^(\w+)(\s+full)?", _PluginInfo, CMDFlags.None, null, 0, ulong.MaxValue, "core", 6); + InputHandler.RegisterCommand("shutdown", "", _Shutdown, CMDFlags.None, null, 0, ulong.MaxValue, "core", 8); + } + + private bool _Shutdown(InputData i) + { + _doShutdown = true; + return true; + } + + private bool _Commands(InputData i) + { + SendMessage("@wCommands in @Wcore@w:", i.ClientMask); + int c = WriteCommands(InputHandler.Commands, "core", i.ClientMask); + SendMessage("@C" + c + " @wcommand" + (c == 1 ? "" : "s") + " found."); + + foreach(KeyValuePair p in PluginMgr.Plugins) + { + SendMessage("", i.ClientMask); + SendMessage("@wCommands in @W" + p.Key + "@w:", i.ClientMask); + c = WriteCommands(InputHandler.Commands, p.Key, i.ClientMask); + SendMessage("@C" + c + " @wcommand" + (c == 1 ? "" : "s") + " found."); + } + + SendMessage("", i.ClientMask); + SendMessage("@WThese are commands for the proxy. If you want to see MUD commands type command.", i.ClientMask); + return true; + } + + private int WriteCommands(SortedDictionary y, string plugin, uint[] clientMask) + { + if(y == null || y.Count == 0) + return 0; + + int c = 0; + foreach(KeyValuePair x in y) + { + if(x.Value.Plugin != plugin) + continue; + if((x.Value.Flags & (CMDFlags.Disabled | CMDFlags.Hidden)) != CMDFlags.None) + continue; + string cmd = ""; + InputEntry p = x.Value.Parent; + while(p != null) + { + cmd = cmd.Insert(0, p.Command + " "); + p = p.Parent; + } + SendMessage("@Y" + cmd, clientMask); + c++; + + c += WriteCommands(x.Value.Subcommands, plugin, clientMask); + } + + return c; + } + + /// + /// Game world instance. + /// + public static World Instance + { + get; + private set; + } + + /// + /// Handle text line as if we received it from Aardwolf. + /// + /// + public void _OnReceived(string Msg) + { + TriggerHandler.HandleText(Msg, this); + } + + public void _OnConnected(bool connected) + { + isWorldReady = false; + foreach(KeyValuePair x in PluginMgr.Plugins) + { +#if !DEBUG + try + { +#endif + if(connected) + x.Value.OnConnect(); + else + x.Value.OnDisconnect(); +#if !DEBUG + } + catch(Exception e) + { + Log.Crash(e, x.Key); + } +#endif + } + } + + private bool _GMCPHP(TriggerData t) + { + if(!isWorldReady) + { + isWorldReady = true; + foreach(KeyValuePair x in PluginMgr.Plugins) + { +#if !DEBUG + try + { +#endif + x.Value.OnLogin(); +#if !DEBUG + } + catch(Exception e) + { + Log.Crash(e, x.Key); + } +#endif + } + CheckUpdatesNow = MSTime + 5000; + } + return false; + } + + private long CheckUpdatesNow = 0; + + private bool _LineInfo(InputData i) + { + int j = 10; + if(i.Arguments.Success) + { + if(!int.TryParse(i.Arguments.Groups[1].Value, out j)) + j = 10; + } + + if(j > 100) + j = 100; + else if(j < 1) + j = 1; + + SendMessage("@wDisplaying last @Y" + j + " @wline" + (j != 1 ? "s" : "") + ":", i.ClientMask); + j = lastLine.Count - j; + if(j < 0) + j = 0; + for(; j < lastLine.Count; j++) + SendMessage(lastLine[j].Replace("@", "@@"), i.ClientMask); + if(j == 10) + SendMessage("@wType '@Wlastlines @w' to see amount of lines.", i.ClientMask); + return true; + } + + internal List lastLine = new List(); + + private bool _PluginInfo(InputData i) + { + if(!i.Arguments.Success) + { + SendMessage("@wYou have the following plugins installed:", i.ClientMask); + foreach(KeyValuePair x in PluginMgr.Plugins) + SendMessage("@Y" + string.Format("{0,-20}", x.Value.Keyword.Trim()) + " @w- " + x.Value.Name + ", version " + x.Value.Version.ToString(), i.ClientMask); + if(PluginMgr.Plugins.Count == 0) + SendMessage("@RYou have no plugins installed.", i.ClientMask); + else + { + SendMessage("", i.ClientMask); + SendMessage("@C" + PluginMgr.Plugins.Count + " @wplugin" + (PluginMgr.Plugins.Count != 1 ? "s" : "") + " found."); + SendMessage("@wUse '@Wplugin @w' for more information about a plugin.", i.ClientMask); + SendMessage("@wUse '@Wplugin full@w' for all information about a plugin.", i.ClientMask); + //SendMessage("@wUse '@Wplugin write@w' to write all information about plugin to a file.", i.ClientMask); + } + } + else + { + Plugin p = PluginMgr.Plugins.ContainsKey(i.Arguments.Groups[1].Value.ToLower().Trim()) ? PluginMgr.Plugins[i.Arguments.Groups[1].Value.ToLower().Trim()] : null; + if(p == null) + { + SendMessage("@wNo such plugin (@W" + i.Arguments.Groups[1].Value.ToLower().Trim() + "@w).", i.ClientMask); + SendMessage("@wType '@Wplugins@w' for a list of installed plugins.", i.ClientMask); + return true; + } + + SendMessage("@w+----------------------------------------------------------------------+", i.ClientMask); + SendMessage("@w|@R" + p.Name.Substring(0, p.Name.Length / 2).PadLeft(35, ' ') + + p.Name.Substring(p.Name.Length / 2).PadRight(35, ' ') + "@w|", i.ClientMask); + SendMessage("@w+----------------------------------------------------------------------+", i.ClientMask); + SendMessage("@w| @WKeyword @w: @g" + string.Format("{0,-55}", p.Keyword) + "@w|", i.ClientMask); + SendMessage("@w| @WAuthor @w: @g" + string.Format("{0,-55}", !string.IsNullOrEmpty(p.Author) ? p.Author : "Unknown") + "@w|", i.ClientMask); + SendMessage("@w| @WVersion @w: @Y" + string.Format("{0,-55}", p.Version) + "@w|", i.ClientMask); + if(!string.IsNullOrEmpty(p.Website)) + SendMessage("@w| @WWebsite @w: @Y" + string.Format("{0,-55}", p.Website) + "@w|", i.ClientMask); + SendMessage("@w| @WClass name @w: @g" + string.Format("{0,-55}", p.ClassName) + "@w|", i.ClientMask); + if(!string.IsNullOrEmpty(p.Description)) + { + string[] desc = Utility.WrapColored(p.Description, 54, 0); + for(int j = 0; j < desc.Length; j++) + { + SendMessage( + j == 0 + ? ("@w| @WDescription @w: @C" + string.Format("{0,-55}", desc[j]) + "@w|") + : ("@w| : @C" + string.Format("{0,-55}", desc[j]) + "@w|"), i.ClientMask); + } + } + if(p.RequiredPlayerConfig.Count != 0) + { + for(int j = 0; j < p.RequiredPlayerConfig.Count; j++) + { + SendMessage( + j == 0 + ? ("@w| @WReq. config @w: " + string.Format("{0,-55}", p.RequiredPlayerConfig[j]) + + "@w|") + : ("@w| : " + string.Format("{0,-55}", p.RequiredPlayerConfig[j]) + "@w|"), + i.ClientMask); + } + } + SendMessage("@w+----------------------------------------------------------------------+", i.ClientMask); + if(i.Arguments.Groups[2].Length > 0 || i.Arguments.Groups[3].Length > 0) + { + int j = _PluginInfoWriteCommands(0, InputHandler.Commands, p.Keyword.ToLower().Trim(), i.ClientMask); + + int k = 0; + foreach(KeyValuePair x in TriggerHandler.TriggersName) + { + if(x.Value.Plugin != p.Keyword.ToLower().Trim()) + continue; + + if(k == 0) + { + SendMessage( + "@w| @WTriggers @w: \"" + + Utility.FormatColoredString(x.Value.PatternStr.Replace("@", "@@") + "\"", -54) + "@w|", + i.ClientMask); + } + else + { + SendMessage( + "@w| : \"" + + Utility.FormatColoredString(x.Value.PatternStr.Replace("@", "@@") + "\"", -54) + "@w|", + i.ClientMask); + } + k++; + } + + if(j != 0 || k != 0) + { + SendMessage("@w+----------------------------------------------------------------------+", + i.ClientMask); + } + } + } + + return true; + } + + private int _PluginInfoWriteCommands(int j, SortedDictionary y, string plugin, uint[] clientMask) + { + foreach(KeyValuePair x in y) + { + if(x.Value.Plugin != plugin) + continue; + + string cmd = x.Key; + InputEntry parent = x.Value.Parent; + while(parent != null) + { + cmd = cmd.Insert(0, parent.Command + " "); + parent = parent.Parent; + } + + if(j == 0) + SendMessage("@w| @WCommands @w: @c" + string.Format("{0,-55}", cmd) + "@w|", clientMask); + else + SendMessage("@w| : @c" + string.Format("{0,-55}", cmd) + "@w|", clientMask); + j++; + + if(x.Value.Subcommands != null) + j = _PluginInfoWriteCommands(j, x.Value.Subcommands, plugin, clientMask); + } + + return j; + } + + private bool isWorldReady = false; + + /// + /// Handle GMCP data that we received from Aardwolf. + /// + /// GMCP data received. + public void _OnReceived(byte[] Data) + { + string Msg = Encoding.Default.GetString(Data); + string Module = Msg.Trim().ToLower(); + if(Module.Contains(' ')) + Module = Module.Substring(0, Module.IndexOf(' ')); + Message m = new Message(true); + m.Clients = null; + m.Flags |= MessageFlags.GMCP; + m.Msg = Module; + m.MsgData = Data; + _SendMessage(m); + TriggerHandler.HandleGMCP(Msg); + } + + /// + /// This is called from proxy when it shuts down. Do NOT call from a plugin. + /// + public void Shutdown() + { + foreach(KeyValuePair x in PluginMgr.Plugins) + { +#if !DEBUG + try + { +#endif + x.Value.Shutdown(); +#if !DEBUG + } + catch(Exception e) + { + Log.Crash(e, x.Key); + } +#endif + } + + _doShutdown = true; + } + + /// + /// Enter input as if a client entered it. Meaning we parse it. Consider using the Execute command instead. + /// + /// Input entered. + /// Which client is this from? Enter 0 to set not from a client. + /// Authlevel of client who entered command (1...64) + public void _OnSent(string Msg, uint ClientId, int AuthLevel) + { + foreach(KeyValuePair x in PluginMgr.Plugins) + { +#if !DEBUG + try + { +#endif + x.Value.OnEnteredCommandBefore(ref Msg, ClientId, AuthLevel); +#if !DEBUG + } + catch(Exception e) + { + Log.Crash(e, x.Key); + } +#endif + if(Msg == null) + return; + } + + InputData i = InputHandler.HandleInput(Msg, Msg, ClientId, AuthLevel, null, this); + if(i != null) + { +#if !DEBUG + try + { +#endif + if(i.Function.Func(i)) + return; +#if !DEBUG + } + catch(Exception e) + { + Log.Crash(e, i.Function.Plugin); + } +#endif + Msg = i.Command; + } + + if(Msg != null) + { + foreach(KeyValuePair x in PluginMgr.Plugins) + { +#if !DEBUG + try + { +#endif + x.Value.OnEnteredCommandAfter(ref Msg, ClientId, AuthLevel); +#if !DEBUG + } + catch(Exception e) + { + Log.Crash(e, x.Value.Keyword); + } +#endif + if(Msg == null) + return; + } + _SendMessage(Msg, new uint[] {0}, ClientId != 0); + } + } + + internal void _SendMessage(string Msg, uint[] Clients, bool Natural) + { + _SendMessage(Msg, Clients, Natural, MessageFlags.None); + } + + internal void _SendMessage(string Msg, uint[] Clients, bool Natural, MessageFlags Flags) + { + _SendMessage(Msg, Clients, Natural, Flags, ulong.MaxValue); + } + + internal void _SendMessage(string Msg, uint[] Clients, bool Natural, MessageFlags Flags, ulong AuthMask) + { + Message m = new Message(Natural); + m.Clients = Clients; + m.Msg = Msg; + m.Flags = Flags; + m.AuthMask = AuthMask; + _SendMessage(m); + } + + internal void _SendMessage(Message msg) + { + _MessageData.Add(msg); + } + + /// + /// Send message to specified clients. + /// + /// Message to send. + /// Clients to send it to. Enter null to send to all connected clients. + /// Enter 0 as client to send it as a command to Aardwolf (we don't parse it though, if you want + /// parsed input use the Execute command). + public void SendMessage(string Msg, uint[] Clients) + { + _SendMessage(Msg, Clients, false); + } + + /// + /// Send a message to all connected authorized clients. + /// + /// Message to send to all authorized clients. + public void SendMessage(string Msg) + { + SendMessage(Msg, null); + } + + /// + /// Send a message to all connected authorized clients. + /// + /// Message to send to all authorized clients. + /// Authorization levels required to see this message. This is a mask. + public void SendMessage(string Msg, ulong AuthMask) + { + _SendMessage(Msg, null, false, MessageFlags.None, AuthMask); + } + + /// + /// Execute a command. + /// + /// Command to execute. + /// Allow parsing it for aliases and such, or send it directly to Aardwolf? + public void Execute(string Msg, bool allowParse) + { + Execute(Msg, allowParse, 1); + } + + /// + /// Execute a command. + /// + /// Command to execute. + /// Allow parsing it for aliases and such, or send it directly to Aardwolf? + /// Auth level that executes this command. (1...64) + public void Execute(string Msg, bool allowParse, int AuthLevel) + { + if(Msg == null) + return; + + if(allowParse) + _OnSent(Msg, uint.MaxValue, Math.Max(1, Math.Min(64, AuthLevel))); + else + _SendMessage(Msg, new uint[] { 0 }, false); + } + + /// + /// Send raw bytes to MUD. + /// + /// Bytes to send. + public void Send(byte[] Data) + { + if(Data == null) + return; + + Message m = new Message(false); + m.Clients = new uint[] { 0 }; + m.MsgData = Data; + _SendMessage(m); + } + + /// + /// Internal command for updating the world. DO NOT CALL FROM A PLUGIN! + /// + /// New mstime. + public bool Update(long msTime) + { + MSTime = msTime; + foreach(KeyValuePair x in PluginMgr.Plugins) + { +#if !DEBUG + try + { +#endif + x.Value.Update(msTime); +#if !DEBUG + } + catch(Exception e) + { + Log.Crash(e, x.Key); + } +#endif + } + + if(CheckUpdatesNow != 0 && msTime > CheckUpdatesNow) + { + CheckUpdatesNow = 0; + CheckUpdates(Config.GetInt32("Updates.Core", 1) != 0, Config.GetInt32("Updates.Plugins", 1) != 0, false); + } + + return _doShutdown; + } + + private bool _doShutdown = false; + + /// + /// This is messages for networking to handle. Don't touch unless you know what you are doing. + /// + public readonly List _MessageData = new List(256); + + internal CoreConfig Config = new CoreConfig(); + + /// + /// Version of Proxy. + /// + public const int Version = 7; + public const string CoreUrl = "www.duckbat.com/plugins/update.core.txt"; + public const string CoreUrl2 = "code.google.com/p/proxymud/"; + + private int GetVersion(string Url) + { + if(!_urlRegex.Match(Url).Success) + Url = "http://" + Url; + WebClient w = new WebClient(); + byte[] d = w.DownloadData(Url); + string s = Encoding.Default.GetString(d); + s = s.Replace("\r", ""); + s = s.Replace(" ", ""); + s = s.Replace("\n", ""); + return int.Parse(s); + } + + private static Regex _urlRegex = new Regex(@"^\w+://", RegexOptions.Compiled); + + /// + /// Milliseconds since program startup. + /// + public long MSTime + { + get; + private set; + } + + /// + /// Check for updates and report to all connected users if there are any. + /// + /// Check core update. + /// Check plugin updates. + /// Should we report if no updates were found? + public void CheckUpdates(bool Core, bool Plugins, bool ReportNoUpdates) + { +#if DEBUG + return; +#endif + bool s = false; + if(Core) + { + try + { + int coreVer = GetVersion(CoreUrl); + if(coreVer > Version) + { + SendMessage("@GUPDATE: @wThere is a newer version of @Wcore @wavailable. (@W" + coreVer + "@w)"); + SendMessage(" @wGo to @W" + CoreUrl2 + " @wto see more."); + s = true; + } + } + catch + { + } + } + + if(Plugins) + { + foreach(KeyValuePair x in PluginMgr.Plugins) + { + if(string.IsNullOrEmpty(x.Value.Website) || string.IsNullOrEmpty(x.Value.UpdateUrl)) + continue; + + try + { + int ver = GetVersion(x.Value.UpdateUrl); + if(ver > x.Value.Version) + { + if(s) + SendMessage(""); + SendMessage("@GUPDATE: @wThere is a newer version of @W" + x.Value.Keyword.ToLower().Trim() + " @wavailable. (@W" + ver + "@w)"); + SendMessage(" @wGo to @W" + x.Value.Website + " @wto see more."); + s = true; + } + } + catch + { + continue; + } + } + } + + if(ReportNoUpdates && !s) + SendMessage("@GUPDATE: @wNo updates found."); + } + } +} diff --git a/ProxyCore/desktop.ini b/ProxyCore/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/ProxyCore/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/ProxyMud.exe b/ProxyMud.exe new file mode 100644 index 0000000..ea36ec7 Binary files /dev/null and b/ProxyMud.exe differ diff --git a/ProxyMud.sln b/ProxyMud.sln new file mode 100644 index 0000000..153d3fb --- /dev/null +++ b/ProxyMud.sln @@ -0,0 +1,124 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.26403.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ProxyMud", "ProxyMud\ProxyMud.csproj", "{B5F8F4E3-630A-420D-8461-420C36BB865C}" + ProjectSection(ProjectDependencies) = postProject + {7863FE6F-E27F-4DBA-B2CC-EDEFE4AE8382} = {7863FE6F-E27F-4DBA-B2CC-EDEFE4AE8382} + EndProjectSection +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ProxyCore", "ProxyCore\ProxyCore.csproj", "{7863FE6F-E27F-4DBA-B2CC-EDEFE4AE8382}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CommandEcho", "CommandEcho\CommandEcho.csproj", "{A51883B5-8A7B-414F-92A9-A171A9846411}" + ProjectSection(ProjectDependencies) = postProject + {7863FE6F-E27F-4DBA-B2CC-EDEFE4AE8382} = {7863FE6F-E27F-4DBA-B2CC-EDEFE4AE8382} + EndProjectSection +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CPHelper", "CPHelper\CPHelper.csproj", "{11D11063-A123-4F02-9C20-FB76C49A4B52}" + ProjectSection(ProjectDependencies) = postProject + {8A7FE055-E1B4-4967-9C76-CA46BA854E73} = {8A7FE055-E1B4-4967-9C76-CA46BA854E73} + {9D34EF7A-07C1-43C5-9DAA-B1DE9F8EAA7D} = {9D34EF7A-07C1-43C5-9DAA-B1DE9F8EAA7D} + EndProjectSection +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GMCPEcho", "GMCPEcho\GMCPEcho.csproj", "{86B2AA8D-5B03-4128-9C77-9E94F71CFFEE}" + ProjectSection(ProjectDependencies) = postProject + {7863FE6F-E27F-4DBA-B2CC-EDEFE4AE8382} = {7863FE6F-E27F-4DBA-B2CC-EDEFE4AE8382} + EndProjectSection +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Mapper", "Mapper\Mapper.csproj", "{9D34EF7A-07C1-43C5-9DAA-B1DE9F8EAA7D}" + ProjectSection(ProjectDependencies) = postProject + {7863FE6F-E27F-4DBA-B2CC-EDEFE4AE8382} = {7863FE6F-E27F-4DBA-B2CC-EDEFE4AE8382} + {B5F8F4E3-630A-420D-8461-420C36BB865C} = {B5F8F4E3-630A-420D-8461-420C36BB865C} + EndProjectSection +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MobDB", "MobDB\MobDB.csproj", "{8A7FE055-E1B4-4967-9C76-CA46BA854E73}" + ProjectSection(ProjectDependencies) = postProject + {7863FE6F-E27F-4DBA-B2CC-EDEFE4AE8382} = {7863FE6F-E27F-4DBA-B2CC-EDEFE4AE8382} + {9D34EF7A-07C1-43C5-9DAA-B1DE9F8EAA7D} = {9D34EF7A-07C1-43C5-9DAA-B1DE9F8EAA7D} + EndProjectSection +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GQPredict", "GQPredict\GQPredict.csproj", "{BE332B80-9B00-4B31-A3D9-15E85B2BEA83}" + ProjectSection(ProjectDependencies) = postProject + {7863FE6F-E27F-4DBA-B2CC-EDEFE4AE8382} = {7863FE6F-E27F-4DBA-B2CC-EDEFE4AE8382} + EndProjectSection +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MudLog", "MudLog\MudLog.csproj", "{2268C185-E9CC-409D-BE6F-A50ED4B900D7}" + ProjectSection(ProjectDependencies) = postProject + {7863FE6F-E27F-4DBA-B2CC-EDEFE4AE8382} = {7863FE6F-E27F-4DBA-B2CC-EDEFE4AE8382} + EndProjectSection +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MoonScript", "MoonScript\MoonScript.csproj", "{884C4C56-29D1-4761-B3B8-3DC2BF19D54C}" + ProjectSection(ProjectDependencies) = postProject + {7863FE6F-E27F-4DBA-B2CC-EDEFE4AE8382} = {7863FE6F-E27F-4DBA-B2CC-EDEFE4AE8382} + EndProjectSection +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MySQL", "MySQL\MySQL.csproj", "{A0D29A29-FE11-4CB2-B256-B6EDD3B03A85}" + ProjectSection(ProjectDependencies) = postProject + {7863FE6F-E27F-4DBA-B2CC-EDEFE4AE8382} = {7863FE6F-E27F-4DBA-B2CC-EDEFE4AE8382} + EndProjectSection +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StayAlive", "StayAlive\StayAlive.csproj", "{CBD347BC-6BF8-417B-92B1-0BD44532A971}" + ProjectSection(ProjectDependencies) = postProject + {7863FE6F-E27F-4DBA-B2CC-EDEFE4AE8382} = {7863FE6F-E27F-4DBA-B2CC-EDEFE4AE8382} + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {B5F8F4E3-630A-420D-8461-420C36BB865C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B5F8F4E3-630A-420D-8461-420C36BB865C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B5F8F4E3-630A-420D-8461-420C36BB865C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B5F8F4E3-630A-420D-8461-420C36BB865C}.Release|Any CPU.Build.0 = Release|Any CPU + {7863FE6F-E27F-4DBA-B2CC-EDEFE4AE8382}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7863FE6F-E27F-4DBA-B2CC-EDEFE4AE8382}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7863FE6F-E27F-4DBA-B2CC-EDEFE4AE8382}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7863FE6F-E27F-4DBA-B2CC-EDEFE4AE8382}.Release|Any CPU.Build.0 = Release|Any CPU + {A51883B5-8A7B-414F-92A9-A171A9846411}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A51883B5-8A7B-414F-92A9-A171A9846411}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A51883B5-8A7B-414F-92A9-A171A9846411}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A51883B5-8A7B-414F-92A9-A171A9846411}.Release|Any CPU.Build.0 = Release|Any CPU + {11D11063-A123-4F02-9C20-FB76C49A4B52}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {11D11063-A123-4F02-9C20-FB76C49A4B52}.Debug|Any CPU.Build.0 = Debug|Any CPU + {11D11063-A123-4F02-9C20-FB76C49A4B52}.Release|Any CPU.ActiveCfg = Release|Any CPU + {11D11063-A123-4F02-9C20-FB76C49A4B52}.Release|Any CPU.Build.0 = Release|Any CPU + {86B2AA8D-5B03-4128-9C77-9E94F71CFFEE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {86B2AA8D-5B03-4128-9C77-9E94F71CFFEE}.Debug|Any CPU.Build.0 = Debug|Any CPU + {86B2AA8D-5B03-4128-9C77-9E94F71CFFEE}.Release|Any CPU.ActiveCfg = Release|Any CPU + {86B2AA8D-5B03-4128-9C77-9E94F71CFFEE}.Release|Any CPU.Build.0 = Release|Any CPU + {9D34EF7A-07C1-43C5-9DAA-B1DE9F8EAA7D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9D34EF7A-07C1-43C5-9DAA-B1DE9F8EAA7D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9D34EF7A-07C1-43C5-9DAA-B1DE9F8EAA7D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9D34EF7A-07C1-43C5-9DAA-B1DE9F8EAA7D}.Release|Any CPU.Build.0 = Release|Any CPU + {8A7FE055-E1B4-4967-9C76-CA46BA854E73}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8A7FE055-E1B4-4967-9C76-CA46BA854E73}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8A7FE055-E1B4-4967-9C76-CA46BA854E73}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8A7FE055-E1B4-4967-9C76-CA46BA854E73}.Release|Any CPU.Build.0 = Release|Any CPU + {BE332B80-9B00-4B31-A3D9-15E85B2BEA83}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {BE332B80-9B00-4B31-A3D9-15E85B2BEA83}.Debug|Any CPU.Build.0 = Debug|Any CPU + {BE332B80-9B00-4B31-A3D9-15E85B2BEA83}.Release|Any CPU.ActiveCfg = Release|Any CPU + {BE332B80-9B00-4B31-A3D9-15E85B2BEA83}.Release|Any CPU.Build.0 = Release|Any CPU + {2268C185-E9CC-409D-BE6F-A50ED4B900D7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2268C185-E9CC-409D-BE6F-A50ED4B900D7}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2268C185-E9CC-409D-BE6F-A50ED4B900D7}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2268C185-E9CC-409D-BE6F-A50ED4B900D7}.Release|Any CPU.Build.0 = Release|Any CPU + {884C4C56-29D1-4761-B3B8-3DC2BF19D54C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {884C4C56-29D1-4761-B3B8-3DC2BF19D54C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {884C4C56-29D1-4761-B3B8-3DC2BF19D54C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {884C4C56-29D1-4761-B3B8-3DC2BF19D54C}.Release|Any CPU.Build.0 = Release|Any CPU + {A0D29A29-FE11-4CB2-B256-B6EDD3B03A85}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A0D29A29-FE11-4CB2-B256-B6EDD3B03A85}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A0D29A29-FE11-4CB2-B256-B6EDD3B03A85}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A0D29A29-FE11-4CB2-B256-B6EDD3B03A85}.Release|Any CPU.Build.0 = Release|Any CPU + {CBD347BC-6BF8-417B-92B1-0BD44532A971}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {CBD347BC-6BF8-417B-92B1-0BD44532A971}.Debug|Any CPU.Build.0 = Debug|Any CPU + {CBD347BC-6BF8-417B-92B1-0BD44532A971}.Release|Any CPU.ActiveCfg = Release|Any CPU + {CBD347BC-6BF8-417B-92B1-0BD44532A971}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/ProxyMud/.svn/all-wcprops b/ProxyMud/.svn/all-wcprops new file mode 100644 index 0000000..f53ff3f --- /dev/null +++ b/ProxyMud/.svn/all-wcprops @@ -0,0 +1,17 @@ +K 25 +svn:wc:ra_dav:version-url +V 31 +/svn/!svn/ver/57/trunk/ProxyMud +END +ProxyMud.csproj +K 25 +svn:wc:ra_dav:version-url +V 46 +/svn/!svn/ver/2/trunk/ProxyMud/ProxyMud.csproj +END +Program.cs +K 25 +svn:wc:ra_dav:version-url +V 42 +/svn/!svn/ver/54/trunk/ProxyMud/Program.cs +END diff --git a/ProxyMud/.svn/desktop.ini b/ProxyMud/.svn/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/ProxyMud/.svn/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/ProxyMud/.svn/dir-prop-base b/ProxyMud/.svn/dir-prop-base new file mode 100644 index 0000000..f1b96ea --- /dev/null +++ b/ProxyMud/.svn/dir-prop-base @@ -0,0 +1,5 @@ +K 14 +bugtraq:number +V 4 +true +END diff --git a/ProxyMud/.svn/entries b/ProxyMud/.svn/entries new file mode 100644 index 0000000..70faeb2 --- /dev/null +++ b/ProxyMud/.svn/entries @@ -0,0 +1,102 @@ +10 + +dir +58 +http://proxymud.googlecode.com/svn/trunk/ProxyMud +http://proxymud.googlecode.com/svn + + + +2012-02-08T08:41:07.654540Z +57 +default8p@gmail.com +has-props + + + + + + + + + + + + + +8a6e9f07-fe1d-2472-fcf8-0b435762827a + +ProxyMud.csproj +file + + + + +2016-03-25T22:18:43.164138Z +d7be9a55f4f5a3486ffb5a351d3e4883 +2012-01-17T10:55:35.805502Z +2 +default8p@gmail.com + + + + + + + + + + + + + + + + + + + + + +3182 + +Network +dir + +Program.cs +file + + + + +2016-03-25T22:18:43.164138Z +3df4edbd957132d9c4c5d36b317d00b6 +2012-02-02T08:38:33.263906Z +54 +default8p@gmail.com + + + + + + + + + + + + + + + + + + + + + +4419 + +Properties +dir + diff --git a/ProxyMud/.svn/prop-base/desktop.ini b/ProxyMud/.svn/prop-base/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/ProxyMud/.svn/prop-base/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/ProxyMud/.svn/props/desktop.ini b/ProxyMud/.svn/props/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/ProxyMud/.svn/props/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/ProxyMud/.svn/text-base/Program.cs.svn-base b/ProxyMud/.svn/text-base/Program.cs.svn-base new file mode 100644 index 0000000..801d342 --- /dev/null +++ b/ProxyMud/.svn/text-base/Program.cs.svn-base @@ -0,0 +1,151 @@ +//#define MONO +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Runtime.InteropServices; +using System.Threading; +using System.Globalization; +using System.Diagnostics; +using ProxyCore; + +namespace ProxyMud +{ + class Program + { + internal static ServerConfig Config; + + static void Main(string[] args) + { +#if !MONO + _handler += new EventHandler(Handler); + SetConsoleCtrlHandler(_handler, true); +#endif + + // Set US culture so config and other formats are universal + Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture("en-US"); + Config = new ServerConfig(); + + Stopwatch watch = new Stopwatch(); + watch.Start(); + + // This is the main loop of the server program + while(canContinue) + { + // The main loop time + const uint sleepTime = 5; + + long time; + + // This is the main loop of the game world + while(canContinue) + { + // Get time before loop + time = watch.ElapsedMilliseconds; + + // Start server if needed + if(Server == null) + { +#if !DEBUG + try + { +#endif + Server = new Network.NetworkServer(); + Server.Start(); +#if !DEBUG + } + catch(Exception e) + { + Log.Error("Failed creating server: " + e.Message); + Shutdown(); + break; + } +#endif + } + + // Update server and everything +#if !DEBUG + try + { +#endif + if(Server.Update(watch.ElapsedMilliseconds)) + Shutdown(); +#if !DEBUG + } + catch(Exception e) + { + Log.Crash(e, "server"); + Shutdown(); + break; + } +#endif + + // Now check time after loop and see how long we should sleep to fill loop time + time = watch.ElapsedMilliseconds - time; + + // Need to sleep some time until next update + if(time <= sleepTime) + { + time = sleepTime - time; + Thread.Sleep((int)time); + } + else + Thread.Sleep(0); // Sleep at least 0 every time so program wouldn't hog CPU + } + + // Loop ended save and shut down + if(Server != null) + Server.Stop(); + } + + isFinished = true; + } + + private static Network.NetworkServer Server = null; + +#region CloseEvent +#if !MONO + [DllImport("Kernel32")] + private static extern bool SetConsoleCtrlHandler(EventHandler handler, bool add); + + private delegate bool EventHandler(CtrlType sig); + static EventHandler _handler; + + enum CtrlType + { + CTRL_C_EVENT = 0, + CTRL_BREAK_EVENT = 1, + CTRL_CLOSE_EVENT = 2, + CTRL_LOGOFF_EVENT = 5, + CTRL_SHUTDOWN_EVENT = 6 + } + + private static bool Handler(CtrlType sig) + { + switch(sig) + { + case CtrlType.CTRL_C_EVENT: + case CtrlType.CTRL_LOGOFF_EVENT: + case CtrlType.CTRL_SHUTDOWN_EVENT: + case CtrlType.CTRL_CLOSE_EVENT: + Shutdown(); + break; + default: + break; + } + while(!isFinished) + Thread.Sleep(10); + return false; + } +#endif + private static bool canContinue = true; + private static bool isFinished = false; + + private static void Shutdown() + { + canContinue = false; + } +#endregion + } +} diff --git a/ProxyMud/.svn/text-base/ProxyMud.csproj.svn-base b/ProxyMud/.svn/text-base/ProxyMud.csproj.svn-base new file mode 100644 index 0000000..9492b6a --- /dev/null +++ b/ProxyMud/.svn/text-base/ProxyMud.csproj.svn-base @@ -0,0 +1,72 @@ + + + + Debug + AnyCPU + 9.0.30729 + 2.0 + {B5F8F4E3-630A-420D-8461-420C36BB865C} + Exe + Properties + ProxyMud + ProxyMud + v3.5 + 512 + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + False + ..\ProxyCore\bin\ProxyCore.dll + + + + 3.5 + + + 3.5 + + + 3.5 + + + + + False + ..\Resources\zlib.dll + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ProxyMud/.svn/text-base/desktop.ini b/ProxyMud/.svn/text-base/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/ProxyMud/.svn/text-base/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/ProxyMud/.svn/tmp/desktop.ini b/ProxyMud/.svn/tmp/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/ProxyMud/.svn/tmp/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/ProxyMud/.svn/tmp/prop-base/desktop.ini b/ProxyMud/.svn/tmp/prop-base/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/ProxyMud/.svn/tmp/prop-base/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/ProxyMud/.svn/tmp/props/desktop.ini b/ProxyMud/.svn/tmp/props/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/ProxyMud/.svn/tmp/props/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/ProxyMud/.svn/tmp/text-base/desktop.ini b/ProxyMud/.svn/tmp/text-base/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/ProxyMud/.svn/tmp/text-base/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/ProxyMud/Network/.svn/all-wcprops b/ProxyMud/Network/.svn/all-wcprops new file mode 100644 index 0000000..cedebc0 --- /dev/null +++ b/ProxyMud/Network/.svn/all-wcprops @@ -0,0 +1,35 @@ +K 25 +svn:wc:ra_dav:version-url +V 39 +/svn/!svn/ver/57/trunk/ProxyMud/Network +END +NetworkServer.cs +K 25 +svn:wc:ra_dav:version-url +V 56 +/svn/!svn/ver/54/trunk/ProxyMud/Network/NetworkServer.cs +END +TelnetPacket.cs +K 25 +svn:wc:ra_dav:version-url +V 54 +/svn/!svn/ver/2/trunk/ProxyMud/Network/TelnetPacket.cs +END +NetworkBase.cs +K 25 +svn:wc:ra_dav:version-url +V 53 +/svn/!svn/ver/2/trunk/ProxyMud/Network/NetworkBase.cs +END +NetworkClient.cs +K 25 +svn:wc:ra_dav:version-url +V 55 +/svn/!svn/ver/2/trunk/ProxyMud/Network/NetworkClient.cs +END +NetworkAardwolf.cs +K 25 +svn:wc:ra_dav:version-url +V 58 +/svn/!svn/ver/57/trunk/ProxyMud/Network/NetworkAardwolf.cs +END diff --git a/ProxyMud/Network/.svn/desktop.ini b/ProxyMud/Network/.svn/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/ProxyMud/Network/.svn/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/ProxyMud/Network/.svn/dir-prop-base b/ProxyMud/Network/.svn/dir-prop-base new file mode 100644 index 0000000..f1b96ea --- /dev/null +++ b/ProxyMud/Network/.svn/dir-prop-base @@ -0,0 +1,5 @@ +K 14 +bugtraq:number +V 4 +true +END diff --git a/ProxyMud/Network/.svn/entries b/ProxyMud/Network/.svn/entries new file mode 100644 index 0000000..ba60197 --- /dev/null +++ b/ProxyMud/Network/.svn/entries @@ -0,0 +1,198 @@ +10 + +dir +58 +http://proxymud.googlecode.com/svn/trunk/ProxyMud/Network +http://proxymud.googlecode.com/svn + + + +2012-02-08T08:41:07.654540Z +57 +default8p@gmail.com +has-props + + + + + + + + + + + + + +8a6e9f07-fe1d-2472-fcf8-0b435762827a + +NetworkServer.cs +file + + + + +2016-03-25T22:18:43.160138Z +10756e3ae397eea8fabb4ef2ff990c40 +2012-02-02T08:38:33.263906Z +54 +default8p@gmail.com + + + + + + + + + + + + + + + + + + + + + +9610 + +TelnetPacket.cs +file + + + + +2016-03-25T22:18:43.160138Z +56a9b9577cc5aa54970eec03cc21ab5d +2012-01-17T10:55:35.805502Z +2 +default8p@gmail.com + + + + + + + + + + + + + + + + + + + + + +1252 + +NetworkBase.cs +file + + + + +2016-03-25T22:18:43.160138Z +8dffc14d23ee8e7db1ecaf5a9d0f7eb7 +2012-01-17T10:55:35.805502Z +2 +default8p@gmail.com + + + + + + + + + + + + + + + + + + + + + +12319 + +NetworkClient.cs +file + + + + +2016-03-25T22:18:43.160138Z +37d0be0ab4975e29880953e6a5ea9315 +2012-01-17T10:55:35.805502Z +2 +default8p@gmail.com + + + + + + + + + + + + + + + + + + + + + +9233 + +NetworkAardwolf.cs +file + + + + +2016-03-25T22:18:43.160138Z +0e90b02a2bd8fe59a7e49845e86f9c28 +2012-02-08T08:41:07.654540Z +57 +default8p@gmail.com + + + + + + + + + + + + + + + + + + + + + +6389 + diff --git a/ProxyMud/Network/.svn/prop-base/desktop.ini b/ProxyMud/Network/.svn/prop-base/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/ProxyMud/Network/.svn/prop-base/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/ProxyMud/Network/.svn/props/desktop.ini b/ProxyMud/Network/.svn/props/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/ProxyMud/Network/.svn/props/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/ProxyMud/Network/.svn/text-base/NetworkAardwolf.cs.svn-base b/ProxyMud/Network/.svn/text-base/NetworkAardwolf.cs.svn-base new file mode 100644 index 0000000..ac11ccc --- /dev/null +++ b/ProxyMud/Network/.svn/text-base/NetworkAardwolf.cs.svn-base @@ -0,0 +1,191 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Net.Sockets; +using ComponentAce.Compression.Libs.zlib; +using ProxyCore; +using System.Text.RegularExpressions; + +namespace ProxyMud.Network +{ + internal class NetworkAardwolf : NetworkBase + { + internal NetworkAardwolf(Socket socket, NetworkServer server) + : base(socket, server, 131072) + { + + } + + #region Variables + protected string LineBuffer = string.Empty; + protected long LineBufferTimeout = 0; + #endregion + + #region Packet + protected override void HandlePacket() + { + if(inIndex >= inMaxIndex) + { + if(inStream.Length > 0) + { + OnReceived(Encoding.Default.GetString(inStream.ToArray()), inMaxIndex >= 1024); + inStream.SetLength(0); + } + return; + } + + if(zStream != null) + { + Decompress(zlibConst.Z_FULL_FLUSH); + HandlePacket(zStream_Out, 0, zStream_Length); + HandlePacket(); + return; + } + + inIndex = HandlePacket(inData, inIndex, inMaxIndex); + HandlePacket(); + } + + protected override void WriteInStream(byte[] Buf, int Index, int MaxIndex) + { + inStream.Write(Buf, Index, MaxIndex - Index); + } + #endregion + + private StringBuilder strLine = new StringBuilder(8192); + + protected override void OnReceived(string Msg, bool bigPacket) + { + if(LineBuffer.Length != 0) + { + Msg = LineBuffer + Msg; + LineBuffer = string.Empty; + } + + while(Msg.Length > 0) + { + strLine.Remove(0, strLine.Length); + int k = 0; + int i = 0; + for(; i < Msg.Length; i++) + { + if(Msg[i] == '\r') + k |= 1; + else if(Msg[i] == '\n') + k |= 2; + else + strLine.Append(Msg[i]); + + if((k & 3) == 3) + { + i++; + break; + } + } + + Msg = Msg.Substring(i); + if((k & 3) != 3) + { + LineBuffer = strLine.ToString(); + LineBufferTimeout = LastMSTime + (!bigPacket ? -1 : 500); + } + else + { + Server.World._OnReceived(Colors.FixColors(strLine.ToString(), true, true)); + } + } + } + + internal override void Update(long msTime) + { + base.Update(msTime); + + if(LineBuffer.Length != 0 && LineBufferTimeout < msTime) + { + string Msg = LineBuffer; + LineBuffer = string.Empty; + OnReceived(Msg + "\n\r", false); + } + } + + protected override void HandlePacket(TelnetPacket pkt) + { + base.HandlePacket(pkt); + + if(pkt.Type == TelnetOpcodes.GMCP && pkt.Header == TelnetOpcodes.SB && pkt.Data.Length > 0) + { + if(inStream.Length != 0) + { + OnReceived(Encoding.Default.GetString(inStream.ToArray()), false); + inStream.SetLength(0); + } + Server.World._OnReceived(pkt.Data.ToArray()); + return; + } + + if(pkt.Type == TelnetOpcodes.GMCP && pkt.Header == TelnetOpcodes.WILL) + { + Send(new[] { (byte)TelnetOpcodes.IAC, (byte)TelnetOpcodes.DO, (byte)TelnetOpcodes.GMCP }); + SendGMCP(Encoding.Default.GetBytes("Core.Hello { \"client\": \"ProxyMud\", \"version\": \"" + World.Version + "\" }")); + { + if(Server.GMCPModules.Count > 0) + { + StringBuilder strModule = new StringBuilder(); + foreach(KeyValuePair x in Server.GMCPModules) + { + if(strModule.Length > 0) + strModule.Append(", "); + strModule.Append("\"" + x.Key + " " + x.Value.ToString() + "\""); + } + SendGMCP(Encoding.Default.GetBytes("Core.Supports.Set [ " + strModule.ToString() + " ]")); + } + } + return; + } + + if(pkt.Type == TelnetOpcodes.TTYPE) + { + NetworkClient c = null; + foreach(NetworkClient x in Server.Clients) + { + if(x.AuthLevel >= 1 && (c == null || x.AuthLevel > c.AuthLevel)) + c = x; + } + if(c != null) + c.Send(pkt); + return; + } + + if(pkt.Type == TelnetOpcodes.MCCP_V2) + { + if(pkt.Header == TelnetOpcodes.WILL) + Send(new[] { (byte)TelnetOpcodes.IAC, (byte)TelnetOpcodes.DO, (byte)TelnetOpcodes.MCCP_V2 }); + return; + } + + if(pkt.Type == TelnetOpcodes.MCCP_V1) + { + if(pkt.Header == TelnetOpcodes.WILL) + Send(new[] { (byte)TelnetOpcodes.IAC, (byte)TelnetOpcodes.DONT, (byte)TelnetOpcodes.MCCP_V1 }); + return; + } + + foreach(NetworkClient x in Server.Clients) + { + if(x.AuthLevel >= 1) + x.Send(pkt); + } + } + + internal void SendGMCP(byte[] Data) + { + byte[] b = new[] { (byte)TelnetOpcodes.IAC, + (byte)TelnetOpcodes.SB, + (byte)TelnetOpcodes.GMCP }; + byte[] c = new[] { (byte)TelnetOpcodes.IAC, + (byte)TelnetOpcodes.SE }; + Send(b.Concat(Data).Concat(c).ToArray()); + } + } +} diff --git a/ProxyMud/Network/.svn/text-base/NetworkBase.cs.svn-base b/ProxyMud/Network/.svn/text-base/NetworkBase.cs.svn-base new file mode 100644 index 0000000..575014e --- /dev/null +++ b/ProxyMud/Network/.svn/text-base/NetworkBase.cs.svn-base @@ -0,0 +1,344 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Net.Sockets; +using System.IO; +using ComponentAce.Compression.Libs.zlib; +using ProxyCore; + +namespace ProxyMud.Network +{ + internal class NetworkBase + { + protected NetworkBase(Socket socket, NetworkServer server, int inBufferSize) + { + Server = server; + Socket = socket; + inStream = new MemoryStream(inBufferSize); + Socket.Blocking = false; + } + + #region Variables + protected readonly NetworkServer Server; + protected Socket Socket; + protected MemoryStream inStream; + protected TelnetPacket telnetPacket; + protected ZStream zStream; + protected static int zStream_Length; + protected static byte[] zStream_Out = new byte[65536]; + protected static int inIndex; + protected static int inMaxIndex; + protected static byte[] inData = new byte[65536]; + #endregion + + #region Networking + internal bool Receive() + { + if(Socket == null) + return false; + + SocketError err; + inMaxIndex = Socket.Receive(inData, 0, inData.Length, SocketFlags.None, out err); + if(err != SocketError.WouldBlock && inMaxIndex == 0) + { + Socket.Close(); + Socket = null; + return false; + } + + if(inMaxIndex == 0) + return true; + + inIndex = 0; + HandlePacket(); + return true; + } + + internal void Send(byte[] Data) + { + if(Socket == null) + return; + + if(zStream != null && this is NetworkClient) + { + Compress(Data, zlibConst.Z_FULL_FLUSH); + if(zStream_Length > 0) + Socket.Send(zStream_Out, zStream_Length, SocketFlags.None); + } + else + Socket.Send(Data, SocketFlags.None); + } + + internal void Send(TelnetPacket pkt) + { + if(Socket == null) + return; + + if(pkt.Header == TelnetOpcodes.SB && pkt.Data.Length != 0) + Send(new[] { (byte)TelnetOpcodes.IAC, (byte)TelnetOpcodes.SB, (byte)pkt.Type }.Concat( + pkt.Data.ToArray()).Concat(new[] { (byte)TelnetOpcodes.IAC, (byte)TelnetOpcodes.SE }).ToArray()); + else + Send(new[] { (byte)TelnetOpcodes.IAC, (byte)pkt.Header, (byte)pkt.Type }); + } + + internal void Disconnect() + { + if(Socket == null) + return; + + Socket.Close(); + Socket = null; + } + #endregion + + #region Compression + protected bool StartCompression(TelnetOpcodes type) + { + if(this is NetworkAardwolf) + throw new Exception("Trying to start compression on Aardwolf connection!"); + + if(zStream != null) + return false; + + if(type == TelnetOpcodes.MCCP_V1) + Send(new[] { (byte)TelnetOpcodes.IAC, (byte)TelnetOpcodes.SB, (byte)TelnetOpcodes.MCCP_V1, + (byte)TelnetOpcodes.WILL, (byte)TelnetOpcodes.SE }); + else + Send(new[] { (byte)TelnetOpcodes.IAC, (byte)TelnetOpcodes.SB, (byte)TelnetOpcodes.MCCP_V2, + (byte)TelnetOpcodes.IAC, (byte)TelnetOpcodes.SE }); + + zStream = new ZStream(); + zStream.deflateInit(6); + return true; + } + + protected void EndCompression() + { + if(this is NetworkAardwolf) + throw new Exception("Trying to end compression on Aardwolf connection!"); + + if(zStream == null) + return; + + byte[] d = new byte[0]; + Compress(d, zlibConst.Z_FINISH); + if(zStream_Length > 0) + Socket.Send(zStream_Out, zStream_Length, SocketFlags.None); + + zStream.deflateEnd(); + zStream.free(); + zStream = null; + } + + private void StartDecompression() + { + if(this is NetworkClient) + throw new Exception("Trying to start decompression on Client connection!"); + + if(zStream != null) + return; + + zStream = new ZStream(); + zStream.inflateInit(); + } + + internal void Compress(byte[] Data, int type) + { + if(this is NetworkAardwolf) + throw new Exception("Trying to compress data on Aardwolf connection!"); + + zStream_Length = 0; + + zStream.avail_in = Data.Length; + zStream.next_in = Data; + zStream.next_in_index = 0; + + zStream.next_out = zStream_Out; + zStream.next_out_index = 0; + zStream.avail_out = zStream_Out.Length; + + switch(zStream.deflate(type)) + { + case zlibConst.Z_OK: + //inIndex = zStream.next_in_index; + zStream_Length = (int)zStream.total_out; + zStream.total_out = 0; + zStream.next_in = null; + break; + + case zlibConst.Z_STREAM_END: + //inIndex = zStream.next_in_index; + zStream_Length = (int)zStream.total_out; + zStream.deflateEnd(); + zStream.free(); + zStream = null; + break; + + default: + //case zlibConst.Z_STREAM_ERROR: + throw new Exception("Error while compressing: " + (zStream.msg ?? "unknown error") + "!"); + } + } + + internal void Decompress(int type) + { + if(this is NetworkClient) + throw new Exception("Trying to decompress data on Client connection!"); + + zStream_Length = 0; + + zStream.avail_in = inMaxIndex - inIndex; + zStream.next_in = inData; + zStream.next_in_index = inIndex; + + zStream.next_out = zStream_Out; + zStream.next_out_index = 0; + zStream.avail_out = zStream_Out.Length; + + switch(zStream.inflate(type)) + { + case zlibConst.Z_OK: + inIndex = zStream.next_in_index; + zStream_Length = (int)zStream.total_out; + zStream.total_out = 0; + break; + + case zlibConst.Z_STREAM_END: + inIndex = zStream.next_in_index; + zStream_Length = (int)zStream.total_out; + zStream.inflateEnd(); + zStream.free(); + zStream = null; + break; + + default: + //case zlibConst.Z_STREAM_ERROR: + throw new Exception("Error while decompressing: " + (zStream.msg ?? "unknown error") + "!"); + } + } + #endregion + + #region Packet + protected virtual void HandlePacket() + { + + } + + protected virtual void HandlePacket(TelnetPacket pkt) + { + + } + + protected int HandlePacket(byte[] Buf, int Index, int MaxIndex) + { + if(Index >= MaxIndex) + return MaxIndex; + + if(telnetPacket != null) + { + switch(telnetPacket.State) + { + case TelnetStates.None: + telnetPacket.Header = (TelnetOpcodes)Buf[Index]; + telnetPacket.State = TelnetStates.Header; + return HandlePacket(Buf, Index + 1, MaxIndex); + + case TelnetStates.Header: + telnetPacket.Type = (TelnetOpcodes)Buf[Index]; + telnetPacket.State = telnetPacket.Header == TelnetOpcodes.SB ? TelnetStates.Data : TelnetStates.End; + if(telnetPacket.State == TelnetStates.End) + { + HandlePacket(telnetPacket); + telnetPacket = null; + } + else + telnetPacket.Data = new MemoryStream(512); + return HandlePacket(Buf, Index + 1, MaxIndex); + + case TelnetStates.Data: + { + for(int i = Index; i < MaxIndex; i++) + { + if(telnetPacket.HadIAC && Buf[i] == (byte)TelnetOpcodes.SE) + { + telnetPacket.State = TelnetStates.End; + HandlePacket(telnetPacket); + if(zStream == null && (telnetPacket.Type == TelnetOpcodes.MCCP_V1 || telnetPacket.Type == TelnetOpcodes.MCCP_V2)) + { + telnetPacket = null; + StartDecompression(); + return i + 1; + } + telnetPacket = null; + return HandlePacket(Buf, i + 1, MaxIndex); + } + if(Buf[i] == (byte)TelnetOpcodes.IAC || (Buf[i] == (byte)TelnetOpcodes.WILL && telnetPacket.Type == TelnetOpcodes.MCCP_V1)) + { + if(!telnetPacket.HadIAC) + { + if(i - Index > 0) + { + telnetPacket.Data.Write(Buf, Index, i - Index); + Index = i; + } + telnetPacket.HadIAC = true; + } + else + telnetPacket.Data.Write(new[] { (byte)TelnetOpcodes.IAC }, 0, 1); + } + else + { + if(telnetPacket.HadIAC) + { + telnetPacket.HadIAC = false; + telnetPacket.Data.Write(new[] { (byte)TelnetOpcodes.IAC }, 0, 1); + } + } + } + + if(Index < MaxIndex) + { + if(Buf[MaxIndex - 1] != (byte)TelnetOpcodes.IAC) + telnetPacket.Data.Write(Buf, Index, MaxIndex - Index); + } + return MaxIndex; + } + } + } + + for(int i = Index; i < MaxIndex; i++) + { + if(Buf[i] == (byte)TelnetOpcodes.IAC) + { + if(i - Index > 0) + WriteInStream(Buf, Index, i); + telnetPacket = new TelnetPacket(); + return HandlePacket(Buf, i + 1, MaxIndex); + } + } + + if(MaxIndex - Index > 0) + WriteInStream(Buf, Index, MaxIndex); + return MaxIndex; + } + + protected virtual void WriteInStream(byte[] Buf, int Index, int MaxIndex) + { + + } + + protected virtual void OnReceived(string Msg, bool bigPacket) + { + + } + #endregion + + protected long LastMSTime; + + internal virtual void Update(long msTime) + { + LastMSTime = msTime; + } + } +} diff --git a/ProxyMud/Network/.svn/text-base/NetworkClient.cs.svn-base b/ProxyMud/Network/.svn/text-base/NetworkClient.cs.svn-base new file mode 100644 index 0000000..5f882a9 --- /dev/null +++ b/ProxyMud/Network/.svn/text-base/NetworkClient.cs.svn-base @@ -0,0 +1,227 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Net.Sockets; +using ComponentAce.Compression.Libs.zlib; +using System.IO; + +namespace ProxyMud.Network +{ + internal class NetworkClient : NetworkBase + { + internal NetworkClient(Socket socket, NetworkServer server) + : base(socket, server, 4096) + { + Id = ++_highId; + } + + #region Variables + private static uint _highId = 0; + internal readonly uint Id; + internal List GMCPModules = new List(); + internal int AuthLevel = -1; + private TelnetOpcodes CompressionType = TelnetOpcodes.IAC; + #endregion + + #region Packet + protected override void HandlePacket() + { + if(inIndex >= inMaxIndex) + return; + + inIndex = HandlePacket(inData, inIndex, inMaxIndex); + HandlePacket(); + } + protected override void WriteInStream(byte[] Buf, int Index, int MaxIndex) + { + for(int i = Index; i < MaxIndex; i++) + { + if(Buf[i] == 0x8) + { + if(inStream.Length > 0) + inStream.SetLength(inStream.Length - 1); + } + else if(Buf[i] == 0xA) + { + continue; + } + else if(Buf[i] == 0xD) + { + OnReceived(Encoding.Default.GetString(inStream.ToArray()), false); + inStream.SetLength(0); + } + else + inStream.WriteByte(Buf[i]); + } + } + #endregion + + protected override void OnReceived(string Msg, bool bigPacket) + { + if(AuthLevel >= 1) + { + Server.World._OnSent(Msg, Id, AuthLevel); + return; + } + + if(Server.Passwords.ContainsKey(Msg)) + { + AuthLevel = Server.Passwords[Msg]; + OnAuthed(); + } + } + + internal bool HasGMCPModule(string mod) + { + if(GMCPModules.Contains(mod)) + return true; + + string[] m = mod.Split(new[] { '.' }, StringSplitOptions.RemoveEmptyEntries); + string n = string.Empty; + for(int i = 0; i < m.Length; i++) + { + n += (i != 0 ? "." : "") + m[i]; + if(GMCPModules.Contains(n)) + return true; + } + + return false; + } + + internal void OnAuthed() + { + Send(new[] { (byte)TelnetOpcodes.IAC, + (byte)TelnetOpcodes.WILL, + (byte)TelnetOpcodes.GMCP }); + Send(Encoding.Default.GetBytes("You are now connected to ProxyMud.\n\r")); + } + + protected override void HandlePacket(TelnetPacket pkt) + { + base.HandlePacket(pkt); + + if(pkt.Header == TelnetOpcodes.SB && pkt.Type == TelnetOpcodes.GMCP && pkt.Data.Length > 0) + { + string Msg = Encoding.Default.GetString(pkt.Data.ToArray()).ToLower(); + if(!Msg.StartsWith("core.supports.") && !Msg.StartsWith("core.hello")) + { + if(Server.Aardwolf != null) + Server.Aardwolf.SendGMCP(pkt.Data.ToArray()); + } + else if(Msg.StartsWith("core.supports.")) + { + try + { + Msg = Msg.Substring("core.supports.".Length); + if(Msg.StartsWith("add ")) + { + string[] v = + Msg.ToLower().Substring(Msg.IndexOf(' ') + 1).Replace("[", "").Replace("]", "").Replace( + "\"", "").Replace(" ", "").Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries); + foreach(string x in v) + { + if(!x.EndsWith("0")) + { + if(!GMCPModules.Contains(x.Substring(0, x.Length - 1))) + { + GMCPModules.Add(x.Substring(0, x.Length - 1)); + string b = x.Substring(0, x.Length - 1); + if(b.Contains('.')) + b = b.Substring(0, b.IndexOf('.')); + if(!Server.GMCPModules.ContainsKey(b) || Server.GMCPModules[b] == 0) + { + if(Server.Aardwolf != null) + Server.Aardwolf.SendGMCP(Encoding.Default.GetBytes("Core.Supports.Add [ \"" + b + " " + x[x.Length - 1].ToString() + "\" ]")); + } + } + } + else + GMCPModules.Remove(x.Substring(0, x.Length - 1)); + } + } + else if(Msg.StartsWith("set ")) + { + string[] v = + Msg.ToLower().Substring(Msg.IndexOf(' ') + 1).Replace("[", "").Replace("]", "").Replace( + "\"", "").Replace(" ", "").Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries); + foreach(string x in v) + { + if(!x.EndsWith("0")) + { + if(!GMCPModules.Contains(x.Substring(0, x.Length - 1))) + { + GMCPModules.Add(x.Substring(0, x.Length - 1)); + string b = x.Substring(0, x.Length - 1); + if(b.Contains('.')) + b = b.Substring(0, b.IndexOf('.')); + if(!Server.GMCPModules.ContainsKey(b) || Server.GMCPModules[b] == 0) + { + if(Server.Aardwolf != null) + Server.Aardwolf.SendGMCP(Encoding.Default.GetBytes("Core.Supports.Add [ \"" + b + " " + x[x.Length - 1].ToString() + "\" ]")); + } + } + } + else + GMCPModules.Remove(x.Substring(0, x.Length - 1)); + } + } + else if(Msg.StartsWith("remove ")) + { + string[] v = + Msg.ToLower().Substring(Msg.IndexOf(' ') + 1).Replace("[", "").Replace("]", "").Replace( + "\"", "").Replace(" ", "").Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries); + foreach(string x in v) + GMCPModules.Remove(x); + } + } + catch + { + } + } + } + + if(pkt.Type == TelnetOpcodes.GMCP) + return; + + if(pkt.Type == TelnetOpcodes.MCCP_V2) + { + if(pkt.Header == TelnetOpcodes.DO) + { + if(StartCompression(TelnetOpcodes.MCCP_V2)) + CompressionType = TelnetOpcodes.MCCP_V2; + } + else if(pkt.Header == TelnetOpcodes.DONT) + { + if(CompressionType == TelnetOpcodes.MCCP_V2) + { + EndCompression(); + CompressionType = TelnetOpcodes.IAC; + } + } + return; + } + + if(pkt.Type == TelnetOpcodes.MCCP_V1) + { + if(pkt.Header == TelnetOpcodes.DO) + { + if(StartCompression(TelnetOpcodes.MCCP_V1)) + CompressionType = TelnetOpcodes.MCCP_V1; + } + else if(pkt.Header == TelnetOpcodes.DONT) + { + if(CompressionType == TelnetOpcodes.MCCP_V1) + { + EndCompression(); + CompressionType = TelnetOpcodes.IAC; + } + } + return; + } + + if(Server.Aardwolf != null) + Server.Aardwolf.Send(pkt); + } + } +} diff --git a/ProxyMud/Network/.svn/text-base/NetworkServer.cs.svn-base b/ProxyMud/Network/.svn/text-base/NetworkServer.cs.svn-base new file mode 100644 index 0000000..9f99fb6 --- /dev/null +++ b/ProxyMud/Network/.svn/text-base/NetworkServer.cs.svn-base @@ -0,0 +1,257 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using ProxyCore; +using System.Net.Sockets; +using System.IO; +using System.Net; +using ProxyCore.Messages; +using System.Text.RegularExpressions; + +namespace ProxyMud.Network +{ + internal class NetworkServer + { + internal NetworkServer() + { + string support = Program.Config.GetString("GMCP.Supports", "Core=1, Char=1, Room=1, Comm=1"); + Match m; + while((m = _loadSupport.Match(support)).Success) + { + support = support.Substring(m.Groups[0].Length); + int i; + if(!int.TryParse(m.Groups[2].Value, out i)) + continue; + GMCPModules[m.Groups[1].Value.ToLower()] = i; + } + } + + private static readonly Regex _loadSupport = new Regex(@"^([\w\.]+)\s*=\s*(\d+),?\s*", RegexOptions.Compiled); + internal Dictionary GMCPModules = new Dictionary(); + internal World World = new World(); + internal List Clients = new List(); + internal NetworkAardwolf Aardwolf = null; + internal TcpListener Server = null; + private readonly MemoryStream strMessage = new MemoryStream(131072); + internal Dictionary Passwords = new Dictionary(); + private static Regex _loadPw = new Regex(@"(.+?)\s*->\s*(\d+),?\s*", RegexOptions.Compiled); + + internal void Start() + { + IPAddress ip = IPAddress.Parse(Program.Config.GetString("Listen.Address", "127.0.0.1")); + if(Server == null) + Server = new TcpListener(ip, Program.Config.GetInt32("Listen.Port", 4000)); + { + Passwords.Clear(); + string pw = Program.Config.GetString("Passwords", ""); + if(!string.IsNullOrEmpty(pw)) + { + Match m; + while((m = _loadPw.Match(pw)).Success) + { + pw = pw.Substring(m.Groups[0].Value.Length); + int i; + if(!int.TryParse(m.Groups[2].Value, out i)) + continue; + if(i < 1) + i = 1; + else if(i > 64) + i = 64; + Passwords[m.Groups[1].Value] = i; + } + } + } + Server.Start(); + + Log.Write("Starting core, version " + World.Version + "."); + Log.Write("Waiting for connections on " + Program.Config.GetString("Listen.Address", "127.0.0.1") + ":" + Program.Config.GetInt32("Listen.Port", 4000) + "."); + } + + internal void Stop() + { + try + { + Server.Stop(); + } + catch + { + } + + World.Shutdown(); + } + + internal void DisconnectAll() + { + if(Aardwolf != null) + { + Aardwolf.Disconnect(); + Aardwolf = null; + World._OnConnected(false); + } + + foreach(NetworkClient x in Clients) + x.Disconnect(); + Clients.Clear(); + } + + internal bool Update(long msTime) + { + if(Server != null && Server.Pending()) + { + NetworkClient c = new NetworkClient(Server.AcceptSocket(), this); + Clients.Add(c); + if(Program.Config.GetInt32("ClientCompression", 1) != 0) + { + c.Send(new[] + { + (byte) TelnetOpcodes.IAC, + (byte) TelnetOpcodes.WILL, + (byte) TelnetOpcodes.MCCP_V2, + (byte) TelnetOpcodes.IAC, + (byte) TelnetOpcodes.WILL, + (byte) TelnetOpcodes.MCCP_V1 + }); + } + if(Passwords.Count != 0) + c.Send(Encoding.Default.GetBytes("Proxy password?\n\r")); + else + { + c.AuthLevel = 1; + c.OnAuthed(); + } + } + + bool r = World.Update(msTime); + + if(Aardwolf != null) + { + if(!Aardwolf.Receive()) + { + Aardwolf = null; + World._OnConnected(false); + } + else + Aardwolf.Update(msTime); + } + + bool hadAuthedClient = false; + for(int i = Clients.Count - 1; i >= 0; i--) + { + if(!Clients[i].Receive()) + { + Clients.RemoveAt(i); + continue; + } + + if(Clients[i].AuthLevel >= 1) + hadAuthedClient = true; + } + + if(Aardwolf == null && (hadAuthedClient || Program.Config.GetInt32("AutoConnect", 0) != 0)) + { + Log.Write("Connecting to " + Program.Config.GetString("MUD.Address", "aardmud.org") + ":" + Program.Config.GetInt32("MUD.Port", 4000).ToString()); + try + { + TcpClient t = new TcpClient(Program.Config.GetString("MUD.Address", "aardmud.org"), + Program.Config.GetInt32("MUD.Port", 4000)); + Aardwolf = new NetworkAardwolf(t.Client, this); + World._OnConnected(true); + } + catch(Exception e) + { + Log.Write("Failed connection to Aardwolf: " + e.Message); + } + } + + if(Aardwolf != null) + { + if(strMessage.Length > 0) + strMessage.SetLength(0); + foreach(Message m in World._MessageData) + { + if(m.Clients == null || !m.Clients.Contains((uint)0)) + continue; + + if((m.Flags & MessageFlags.GMCP) != MessageFlags.None) + { + if(m.MsgData == null || m.MsgData.Length == 0) + continue; + + strMessage.Write(new byte[] { + (byte)TelnetOpcodes.IAC, + (byte)TelnetOpcodes.SB, + (byte)TelnetOpcodes.GMCP + }, 0, 3); + strMessage.Write(m.MsgData, 0, m.MsgData.Length); + strMessage.Write(new byte[] { + (byte)TelnetOpcodes.IAC, + (byte)TelnetOpcodes.SE}, 0, 2); + } + else + { + byte[] data = m.MsgData ?? Encoding.Default.GetBytes(m.Msg + m.LineEnding); + strMessage.Write(data, 0, data.Length); + } + } + + if(strMessage.Length != 0) + Aardwolf.Send(strMessage.ToArray()); + } + + for(int i = Clients.Count - 1; i >= 0; i--) + { + if(strMessage.Length > 0) + strMessage.SetLength(0); + + Clients[i].Update(msTime); + + if(Clients[i].AuthLevel < 1) + continue; + + foreach(Message m in World._MessageData) + { + if(m.Clients != null && !m.Clients.Contains(Clients[i].Id)) + continue; + + if((m.AuthMask & ((ulong)1 << (Clients[i].AuthLevel - 1))) == 0) + continue; + + if((m.Flags & MessageFlags.GMCP) != MessageFlags.None) + { + if(!Clients[i].HasGMCPModule(m.Msg.ToLower())) + continue; + + if(m.MsgData == null || m.MsgData.Length == 0) + continue; + + strMessage.Write(new[] { + (byte)TelnetOpcodes.IAC, + (byte)TelnetOpcodes.SB, + (byte)TelnetOpcodes.GMCP + }, 0, 3); + strMessage.Write(m.MsgData, 0, m.MsgData.Length); + strMessage.Write(new[] { + (byte)TelnetOpcodes.IAC, + (byte)TelnetOpcodes.SE}, 0, 2); + } + else + { + string msg = m.Msg; + msg = Colors.FixColors(msg, false, true); + byte[] data = Encoding.Default.GetBytes(msg + m.LineEnding); + strMessage.Write(data, 0, data.Length); + } + } + + if(strMessage.Length == 0) + continue; + + Clients[i].Send(strMessage.ToArray()); + } + + World._MessageData.Clear(); + return r; + } + } +} diff --git a/ProxyMud/Network/.svn/text-base/TelnetPacket.cs.svn-base b/ProxyMud/Network/.svn/text-base/TelnetPacket.cs.svn-base new file mode 100644 index 0000000..9920e90 --- /dev/null +++ b/ProxyMud/Network/.svn/text-base/TelnetPacket.cs.svn-base @@ -0,0 +1,61 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.IO; + +namespace ProxyMud.Network +{ + internal enum TelnetOpcodes : byte + { + SE = 240, + SB = 250, + WILL = 251, + WONT = 252, + DO = 253, + DONT = 254, + IAC = 255, + + TTYPE = 24, + MCCP_V1 = 85, + MCCP_V2 = 86, + GMCP = 201, + } + + internal class TelnetPacket + { + internal TelnetStates State; + internal TelnetOpcodes Header; + internal TelnetOpcodes Type; + internal MemoryStream Data; + internal bool HadIAC = false; + } + + internal enum TelnetStates + { + /// + /// Just received IAC, nothing else. + /// + None, + + /// + /// Have header (what packet does). + /// + Header, + + /// + /// Have type of packet. + /// + Type, + + /// + /// Gathering data right now waiting for IAC SE. + /// + Data, + + /// + /// Finished packet. + /// + End, + } +} diff --git a/ProxyMud/Network/.svn/text-base/desktop.ini b/ProxyMud/Network/.svn/text-base/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/ProxyMud/Network/.svn/text-base/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/ProxyMud/Network/.svn/tmp/desktop.ini b/ProxyMud/Network/.svn/tmp/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/ProxyMud/Network/.svn/tmp/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/ProxyMud/Network/.svn/tmp/prop-base/desktop.ini b/ProxyMud/Network/.svn/tmp/prop-base/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/ProxyMud/Network/.svn/tmp/prop-base/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/ProxyMud/Network/.svn/tmp/props/desktop.ini b/ProxyMud/Network/.svn/tmp/props/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/ProxyMud/Network/.svn/tmp/props/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/ProxyMud/Network/.svn/tmp/text-base/desktop.ini b/ProxyMud/Network/.svn/tmp/text-base/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/ProxyMud/Network/.svn/tmp/text-base/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/ProxyMud/Network/NetworkAardwolf.cs b/ProxyMud/Network/NetworkAardwolf.cs new file mode 100644 index 0000000..ac11ccc --- /dev/null +++ b/ProxyMud/Network/NetworkAardwolf.cs @@ -0,0 +1,191 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Net.Sockets; +using ComponentAce.Compression.Libs.zlib; +using ProxyCore; +using System.Text.RegularExpressions; + +namespace ProxyMud.Network +{ + internal class NetworkAardwolf : NetworkBase + { + internal NetworkAardwolf(Socket socket, NetworkServer server) + : base(socket, server, 131072) + { + + } + + #region Variables + protected string LineBuffer = string.Empty; + protected long LineBufferTimeout = 0; + #endregion + + #region Packet + protected override void HandlePacket() + { + if(inIndex >= inMaxIndex) + { + if(inStream.Length > 0) + { + OnReceived(Encoding.Default.GetString(inStream.ToArray()), inMaxIndex >= 1024); + inStream.SetLength(0); + } + return; + } + + if(zStream != null) + { + Decompress(zlibConst.Z_FULL_FLUSH); + HandlePacket(zStream_Out, 0, zStream_Length); + HandlePacket(); + return; + } + + inIndex = HandlePacket(inData, inIndex, inMaxIndex); + HandlePacket(); + } + + protected override void WriteInStream(byte[] Buf, int Index, int MaxIndex) + { + inStream.Write(Buf, Index, MaxIndex - Index); + } + #endregion + + private StringBuilder strLine = new StringBuilder(8192); + + protected override void OnReceived(string Msg, bool bigPacket) + { + if(LineBuffer.Length != 0) + { + Msg = LineBuffer + Msg; + LineBuffer = string.Empty; + } + + while(Msg.Length > 0) + { + strLine.Remove(0, strLine.Length); + int k = 0; + int i = 0; + for(; i < Msg.Length; i++) + { + if(Msg[i] == '\r') + k |= 1; + else if(Msg[i] == '\n') + k |= 2; + else + strLine.Append(Msg[i]); + + if((k & 3) == 3) + { + i++; + break; + } + } + + Msg = Msg.Substring(i); + if((k & 3) != 3) + { + LineBuffer = strLine.ToString(); + LineBufferTimeout = LastMSTime + (!bigPacket ? -1 : 500); + } + else + { + Server.World._OnReceived(Colors.FixColors(strLine.ToString(), true, true)); + } + } + } + + internal override void Update(long msTime) + { + base.Update(msTime); + + if(LineBuffer.Length != 0 && LineBufferTimeout < msTime) + { + string Msg = LineBuffer; + LineBuffer = string.Empty; + OnReceived(Msg + "\n\r", false); + } + } + + protected override void HandlePacket(TelnetPacket pkt) + { + base.HandlePacket(pkt); + + if(pkt.Type == TelnetOpcodes.GMCP && pkt.Header == TelnetOpcodes.SB && pkt.Data.Length > 0) + { + if(inStream.Length != 0) + { + OnReceived(Encoding.Default.GetString(inStream.ToArray()), false); + inStream.SetLength(0); + } + Server.World._OnReceived(pkt.Data.ToArray()); + return; + } + + if(pkt.Type == TelnetOpcodes.GMCP && pkt.Header == TelnetOpcodes.WILL) + { + Send(new[] { (byte)TelnetOpcodes.IAC, (byte)TelnetOpcodes.DO, (byte)TelnetOpcodes.GMCP }); + SendGMCP(Encoding.Default.GetBytes("Core.Hello { \"client\": \"ProxyMud\", \"version\": \"" + World.Version + "\" }")); + { + if(Server.GMCPModules.Count > 0) + { + StringBuilder strModule = new StringBuilder(); + foreach(KeyValuePair x in Server.GMCPModules) + { + if(strModule.Length > 0) + strModule.Append(", "); + strModule.Append("\"" + x.Key + " " + x.Value.ToString() + "\""); + } + SendGMCP(Encoding.Default.GetBytes("Core.Supports.Set [ " + strModule.ToString() + " ]")); + } + } + return; + } + + if(pkt.Type == TelnetOpcodes.TTYPE) + { + NetworkClient c = null; + foreach(NetworkClient x in Server.Clients) + { + if(x.AuthLevel >= 1 && (c == null || x.AuthLevel > c.AuthLevel)) + c = x; + } + if(c != null) + c.Send(pkt); + return; + } + + if(pkt.Type == TelnetOpcodes.MCCP_V2) + { + if(pkt.Header == TelnetOpcodes.WILL) + Send(new[] { (byte)TelnetOpcodes.IAC, (byte)TelnetOpcodes.DO, (byte)TelnetOpcodes.MCCP_V2 }); + return; + } + + if(pkt.Type == TelnetOpcodes.MCCP_V1) + { + if(pkt.Header == TelnetOpcodes.WILL) + Send(new[] { (byte)TelnetOpcodes.IAC, (byte)TelnetOpcodes.DONT, (byte)TelnetOpcodes.MCCP_V1 }); + return; + } + + foreach(NetworkClient x in Server.Clients) + { + if(x.AuthLevel >= 1) + x.Send(pkt); + } + } + + internal void SendGMCP(byte[] Data) + { + byte[] b = new[] { (byte)TelnetOpcodes.IAC, + (byte)TelnetOpcodes.SB, + (byte)TelnetOpcodes.GMCP }; + byte[] c = new[] { (byte)TelnetOpcodes.IAC, + (byte)TelnetOpcodes.SE }; + Send(b.Concat(Data).Concat(c).ToArray()); + } + } +} diff --git a/ProxyMud/Network/NetworkBase.cs b/ProxyMud/Network/NetworkBase.cs new file mode 100644 index 0000000..575014e --- /dev/null +++ b/ProxyMud/Network/NetworkBase.cs @@ -0,0 +1,344 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Net.Sockets; +using System.IO; +using ComponentAce.Compression.Libs.zlib; +using ProxyCore; + +namespace ProxyMud.Network +{ + internal class NetworkBase + { + protected NetworkBase(Socket socket, NetworkServer server, int inBufferSize) + { + Server = server; + Socket = socket; + inStream = new MemoryStream(inBufferSize); + Socket.Blocking = false; + } + + #region Variables + protected readonly NetworkServer Server; + protected Socket Socket; + protected MemoryStream inStream; + protected TelnetPacket telnetPacket; + protected ZStream zStream; + protected static int zStream_Length; + protected static byte[] zStream_Out = new byte[65536]; + protected static int inIndex; + protected static int inMaxIndex; + protected static byte[] inData = new byte[65536]; + #endregion + + #region Networking + internal bool Receive() + { + if(Socket == null) + return false; + + SocketError err; + inMaxIndex = Socket.Receive(inData, 0, inData.Length, SocketFlags.None, out err); + if(err != SocketError.WouldBlock && inMaxIndex == 0) + { + Socket.Close(); + Socket = null; + return false; + } + + if(inMaxIndex == 0) + return true; + + inIndex = 0; + HandlePacket(); + return true; + } + + internal void Send(byte[] Data) + { + if(Socket == null) + return; + + if(zStream != null && this is NetworkClient) + { + Compress(Data, zlibConst.Z_FULL_FLUSH); + if(zStream_Length > 0) + Socket.Send(zStream_Out, zStream_Length, SocketFlags.None); + } + else + Socket.Send(Data, SocketFlags.None); + } + + internal void Send(TelnetPacket pkt) + { + if(Socket == null) + return; + + if(pkt.Header == TelnetOpcodes.SB && pkt.Data.Length != 0) + Send(new[] { (byte)TelnetOpcodes.IAC, (byte)TelnetOpcodes.SB, (byte)pkt.Type }.Concat( + pkt.Data.ToArray()).Concat(new[] { (byte)TelnetOpcodes.IAC, (byte)TelnetOpcodes.SE }).ToArray()); + else + Send(new[] { (byte)TelnetOpcodes.IAC, (byte)pkt.Header, (byte)pkt.Type }); + } + + internal void Disconnect() + { + if(Socket == null) + return; + + Socket.Close(); + Socket = null; + } + #endregion + + #region Compression + protected bool StartCompression(TelnetOpcodes type) + { + if(this is NetworkAardwolf) + throw new Exception("Trying to start compression on Aardwolf connection!"); + + if(zStream != null) + return false; + + if(type == TelnetOpcodes.MCCP_V1) + Send(new[] { (byte)TelnetOpcodes.IAC, (byte)TelnetOpcodes.SB, (byte)TelnetOpcodes.MCCP_V1, + (byte)TelnetOpcodes.WILL, (byte)TelnetOpcodes.SE }); + else + Send(new[] { (byte)TelnetOpcodes.IAC, (byte)TelnetOpcodes.SB, (byte)TelnetOpcodes.MCCP_V2, + (byte)TelnetOpcodes.IAC, (byte)TelnetOpcodes.SE }); + + zStream = new ZStream(); + zStream.deflateInit(6); + return true; + } + + protected void EndCompression() + { + if(this is NetworkAardwolf) + throw new Exception("Trying to end compression on Aardwolf connection!"); + + if(zStream == null) + return; + + byte[] d = new byte[0]; + Compress(d, zlibConst.Z_FINISH); + if(zStream_Length > 0) + Socket.Send(zStream_Out, zStream_Length, SocketFlags.None); + + zStream.deflateEnd(); + zStream.free(); + zStream = null; + } + + private void StartDecompression() + { + if(this is NetworkClient) + throw new Exception("Trying to start decompression on Client connection!"); + + if(zStream != null) + return; + + zStream = new ZStream(); + zStream.inflateInit(); + } + + internal void Compress(byte[] Data, int type) + { + if(this is NetworkAardwolf) + throw new Exception("Trying to compress data on Aardwolf connection!"); + + zStream_Length = 0; + + zStream.avail_in = Data.Length; + zStream.next_in = Data; + zStream.next_in_index = 0; + + zStream.next_out = zStream_Out; + zStream.next_out_index = 0; + zStream.avail_out = zStream_Out.Length; + + switch(zStream.deflate(type)) + { + case zlibConst.Z_OK: + //inIndex = zStream.next_in_index; + zStream_Length = (int)zStream.total_out; + zStream.total_out = 0; + zStream.next_in = null; + break; + + case zlibConst.Z_STREAM_END: + //inIndex = zStream.next_in_index; + zStream_Length = (int)zStream.total_out; + zStream.deflateEnd(); + zStream.free(); + zStream = null; + break; + + default: + //case zlibConst.Z_STREAM_ERROR: + throw new Exception("Error while compressing: " + (zStream.msg ?? "unknown error") + "!"); + } + } + + internal void Decompress(int type) + { + if(this is NetworkClient) + throw new Exception("Trying to decompress data on Client connection!"); + + zStream_Length = 0; + + zStream.avail_in = inMaxIndex - inIndex; + zStream.next_in = inData; + zStream.next_in_index = inIndex; + + zStream.next_out = zStream_Out; + zStream.next_out_index = 0; + zStream.avail_out = zStream_Out.Length; + + switch(zStream.inflate(type)) + { + case zlibConst.Z_OK: + inIndex = zStream.next_in_index; + zStream_Length = (int)zStream.total_out; + zStream.total_out = 0; + break; + + case zlibConst.Z_STREAM_END: + inIndex = zStream.next_in_index; + zStream_Length = (int)zStream.total_out; + zStream.inflateEnd(); + zStream.free(); + zStream = null; + break; + + default: + //case zlibConst.Z_STREAM_ERROR: + throw new Exception("Error while decompressing: " + (zStream.msg ?? "unknown error") + "!"); + } + } + #endregion + + #region Packet + protected virtual void HandlePacket() + { + + } + + protected virtual void HandlePacket(TelnetPacket pkt) + { + + } + + protected int HandlePacket(byte[] Buf, int Index, int MaxIndex) + { + if(Index >= MaxIndex) + return MaxIndex; + + if(telnetPacket != null) + { + switch(telnetPacket.State) + { + case TelnetStates.None: + telnetPacket.Header = (TelnetOpcodes)Buf[Index]; + telnetPacket.State = TelnetStates.Header; + return HandlePacket(Buf, Index + 1, MaxIndex); + + case TelnetStates.Header: + telnetPacket.Type = (TelnetOpcodes)Buf[Index]; + telnetPacket.State = telnetPacket.Header == TelnetOpcodes.SB ? TelnetStates.Data : TelnetStates.End; + if(telnetPacket.State == TelnetStates.End) + { + HandlePacket(telnetPacket); + telnetPacket = null; + } + else + telnetPacket.Data = new MemoryStream(512); + return HandlePacket(Buf, Index + 1, MaxIndex); + + case TelnetStates.Data: + { + for(int i = Index; i < MaxIndex; i++) + { + if(telnetPacket.HadIAC && Buf[i] == (byte)TelnetOpcodes.SE) + { + telnetPacket.State = TelnetStates.End; + HandlePacket(telnetPacket); + if(zStream == null && (telnetPacket.Type == TelnetOpcodes.MCCP_V1 || telnetPacket.Type == TelnetOpcodes.MCCP_V2)) + { + telnetPacket = null; + StartDecompression(); + return i + 1; + } + telnetPacket = null; + return HandlePacket(Buf, i + 1, MaxIndex); + } + if(Buf[i] == (byte)TelnetOpcodes.IAC || (Buf[i] == (byte)TelnetOpcodes.WILL && telnetPacket.Type == TelnetOpcodes.MCCP_V1)) + { + if(!telnetPacket.HadIAC) + { + if(i - Index > 0) + { + telnetPacket.Data.Write(Buf, Index, i - Index); + Index = i; + } + telnetPacket.HadIAC = true; + } + else + telnetPacket.Data.Write(new[] { (byte)TelnetOpcodes.IAC }, 0, 1); + } + else + { + if(telnetPacket.HadIAC) + { + telnetPacket.HadIAC = false; + telnetPacket.Data.Write(new[] { (byte)TelnetOpcodes.IAC }, 0, 1); + } + } + } + + if(Index < MaxIndex) + { + if(Buf[MaxIndex - 1] != (byte)TelnetOpcodes.IAC) + telnetPacket.Data.Write(Buf, Index, MaxIndex - Index); + } + return MaxIndex; + } + } + } + + for(int i = Index; i < MaxIndex; i++) + { + if(Buf[i] == (byte)TelnetOpcodes.IAC) + { + if(i - Index > 0) + WriteInStream(Buf, Index, i); + telnetPacket = new TelnetPacket(); + return HandlePacket(Buf, i + 1, MaxIndex); + } + } + + if(MaxIndex - Index > 0) + WriteInStream(Buf, Index, MaxIndex); + return MaxIndex; + } + + protected virtual void WriteInStream(byte[] Buf, int Index, int MaxIndex) + { + + } + + protected virtual void OnReceived(string Msg, bool bigPacket) + { + + } + #endregion + + protected long LastMSTime; + + internal virtual void Update(long msTime) + { + LastMSTime = msTime; + } + } +} diff --git a/ProxyMud/Network/NetworkClient.cs b/ProxyMud/Network/NetworkClient.cs new file mode 100644 index 0000000..5f882a9 --- /dev/null +++ b/ProxyMud/Network/NetworkClient.cs @@ -0,0 +1,227 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Net.Sockets; +using ComponentAce.Compression.Libs.zlib; +using System.IO; + +namespace ProxyMud.Network +{ + internal class NetworkClient : NetworkBase + { + internal NetworkClient(Socket socket, NetworkServer server) + : base(socket, server, 4096) + { + Id = ++_highId; + } + + #region Variables + private static uint _highId = 0; + internal readonly uint Id; + internal List GMCPModules = new List(); + internal int AuthLevel = -1; + private TelnetOpcodes CompressionType = TelnetOpcodes.IAC; + #endregion + + #region Packet + protected override void HandlePacket() + { + if(inIndex >= inMaxIndex) + return; + + inIndex = HandlePacket(inData, inIndex, inMaxIndex); + HandlePacket(); + } + protected override void WriteInStream(byte[] Buf, int Index, int MaxIndex) + { + for(int i = Index; i < MaxIndex; i++) + { + if(Buf[i] == 0x8) + { + if(inStream.Length > 0) + inStream.SetLength(inStream.Length - 1); + } + else if(Buf[i] == 0xA) + { + continue; + } + else if(Buf[i] == 0xD) + { + OnReceived(Encoding.Default.GetString(inStream.ToArray()), false); + inStream.SetLength(0); + } + else + inStream.WriteByte(Buf[i]); + } + } + #endregion + + protected override void OnReceived(string Msg, bool bigPacket) + { + if(AuthLevel >= 1) + { + Server.World._OnSent(Msg, Id, AuthLevel); + return; + } + + if(Server.Passwords.ContainsKey(Msg)) + { + AuthLevel = Server.Passwords[Msg]; + OnAuthed(); + } + } + + internal bool HasGMCPModule(string mod) + { + if(GMCPModules.Contains(mod)) + return true; + + string[] m = mod.Split(new[] { '.' }, StringSplitOptions.RemoveEmptyEntries); + string n = string.Empty; + for(int i = 0; i < m.Length; i++) + { + n += (i != 0 ? "." : "") + m[i]; + if(GMCPModules.Contains(n)) + return true; + } + + return false; + } + + internal void OnAuthed() + { + Send(new[] { (byte)TelnetOpcodes.IAC, + (byte)TelnetOpcodes.WILL, + (byte)TelnetOpcodes.GMCP }); + Send(Encoding.Default.GetBytes("You are now connected to ProxyMud.\n\r")); + } + + protected override void HandlePacket(TelnetPacket pkt) + { + base.HandlePacket(pkt); + + if(pkt.Header == TelnetOpcodes.SB && pkt.Type == TelnetOpcodes.GMCP && pkt.Data.Length > 0) + { + string Msg = Encoding.Default.GetString(pkt.Data.ToArray()).ToLower(); + if(!Msg.StartsWith("core.supports.") && !Msg.StartsWith("core.hello")) + { + if(Server.Aardwolf != null) + Server.Aardwolf.SendGMCP(pkt.Data.ToArray()); + } + else if(Msg.StartsWith("core.supports.")) + { + try + { + Msg = Msg.Substring("core.supports.".Length); + if(Msg.StartsWith("add ")) + { + string[] v = + Msg.ToLower().Substring(Msg.IndexOf(' ') + 1).Replace("[", "").Replace("]", "").Replace( + "\"", "").Replace(" ", "").Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries); + foreach(string x in v) + { + if(!x.EndsWith("0")) + { + if(!GMCPModules.Contains(x.Substring(0, x.Length - 1))) + { + GMCPModules.Add(x.Substring(0, x.Length - 1)); + string b = x.Substring(0, x.Length - 1); + if(b.Contains('.')) + b = b.Substring(0, b.IndexOf('.')); + if(!Server.GMCPModules.ContainsKey(b) || Server.GMCPModules[b] == 0) + { + if(Server.Aardwolf != null) + Server.Aardwolf.SendGMCP(Encoding.Default.GetBytes("Core.Supports.Add [ \"" + b + " " + x[x.Length - 1].ToString() + "\" ]")); + } + } + } + else + GMCPModules.Remove(x.Substring(0, x.Length - 1)); + } + } + else if(Msg.StartsWith("set ")) + { + string[] v = + Msg.ToLower().Substring(Msg.IndexOf(' ') + 1).Replace("[", "").Replace("]", "").Replace( + "\"", "").Replace(" ", "").Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries); + foreach(string x in v) + { + if(!x.EndsWith("0")) + { + if(!GMCPModules.Contains(x.Substring(0, x.Length - 1))) + { + GMCPModules.Add(x.Substring(0, x.Length - 1)); + string b = x.Substring(0, x.Length - 1); + if(b.Contains('.')) + b = b.Substring(0, b.IndexOf('.')); + if(!Server.GMCPModules.ContainsKey(b) || Server.GMCPModules[b] == 0) + { + if(Server.Aardwolf != null) + Server.Aardwolf.SendGMCP(Encoding.Default.GetBytes("Core.Supports.Add [ \"" + b + " " + x[x.Length - 1].ToString() + "\" ]")); + } + } + } + else + GMCPModules.Remove(x.Substring(0, x.Length - 1)); + } + } + else if(Msg.StartsWith("remove ")) + { + string[] v = + Msg.ToLower().Substring(Msg.IndexOf(' ') + 1).Replace("[", "").Replace("]", "").Replace( + "\"", "").Replace(" ", "").Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries); + foreach(string x in v) + GMCPModules.Remove(x); + } + } + catch + { + } + } + } + + if(pkt.Type == TelnetOpcodes.GMCP) + return; + + if(pkt.Type == TelnetOpcodes.MCCP_V2) + { + if(pkt.Header == TelnetOpcodes.DO) + { + if(StartCompression(TelnetOpcodes.MCCP_V2)) + CompressionType = TelnetOpcodes.MCCP_V2; + } + else if(pkt.Header == TelnetOpcodes.DONT) + { + if(CompressionType == TelnetOpcodes.MCCP_V2) + { + EndCompression(); + CompressionType = TelnetOpcodes.IAC; + } + } + return; + } + + if(pkt.Type == TelnetOpcodes.MCCP_V1) + { + if(pkt.Header == TelnetOpcodes.DO) + { + if(StartCompression(TelnetOpcodes.MCCP_V1)) + CompressionType = TelnetOpcodes.MCCP_V1; + } + else if(pkt.Header == TelnetOpcodes.DONT) + { + if(CompressionType == TelnetOpcodes.MCCP_V1) + { + EndCompression(); + CompressionType = TelnetOpcodes.IAC; + } + } + return; + } + + if(Server.Aardwolf != null) + Server.Aardwolf.Send(pkt); + } + } +} diff --git a/ProxyMud/Network/NetworkServer.cs b/ProxyMud/Network/NetworkServer.cs new file mode 100644 index 0000000..dae01ff --- /dev/null +++ b/ProxyMud/Network/NetworkServer.cs @@ -0,0 +1,259 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using ProxyCore; +using System.Net.Sockets; +using System.IO; +using System.Net; +using ProxyCore.Messages; +using System.Text.RegularExpressions; + +namespace ProxyMud.Network +{ + internal class NetworkServer + { + internal NetworkServer() + { + //string support = Program.Config.GetString("GMCP.Supports", "Core=1, Char=1, Room=1, Comm=1, Rawcolor=1"); + string support = Program.Config.GetString("GMCP.Supports", "Core=1, Char=1, Room=1, Comm=1"); + Match m; + while((m = _loadSupport.Match(support)).Success) + { + support = support.Substring(m.Groups[0].Length); + int i; + if(!int.TryParse(m.Groups[2].Value, out i)) + continue; + GMCPModules[m.Groups[1].Value.ToLower()] = i; + } + } + + private static readonly Regex _loadSupport = new Regex(@"^([\w\.]+)\s*=\s*(\d+),?\s*", RegexOptions.Compiled); + internal Dictionary GMCPModules = new Dictionary(); + internal World World = new World(); + internal List Clients = new List(); + internal NetworkAardwolf Aardwolf = null; + internal TcpListener Server = null; + private readonly MemoryStream strMessage = new MemoryStream(131072); + internal Dictionary Passwords = new Dictionary(); + private static Regex _loadPw = new Regex(@"(.+?)\s*->\s*(\d+),?\s*", RegexOptions.Compiled); + + internal void Start() + { + IPAddress ip = IPAddress.Parse(Program.Config.GetString("Listen.Address", "127.0.0.1")); + if(Server == null) + Server = new TcpListener(ip, Program.Config.GetInt32("Listen.Port", 4000)); + { + Passwords.Clear(); + string pw = Program.Config.GetString("Passwords", ""); + if(!string.IsNullOrEmpty(pw)) + { + Match m; + while((m = _loadPw.Match(pw)).Success) + { + pw = pw.Substring(m.Groups[0].Value.Length); + int i; + if(!int.TryParse(m.Groups[2].Value, out i)) + continue; + if(i < 1) + i = 1; + else if(i > 64) + i = 64; + Passwords[m.Groups[1].Value] = i; + } + } + } + Server.Start(); + + Log.Write("Starting core, version " + World.Version + "."); + Log.Write("Waiting for connections on " + Program.Config.GetString("Listen.Address", "127.0.0.1") + ":" + Program.Config.GetInt32("Listen.Port", 4000) + "."); + } + + internal void Stop() + { + try + { + Server.Stop(); + } + catch + { + } + + World.Shutdown(); + } + + internal void DisconnectAll() + { + if(Aardwolf != null) + { + Aardwolf.Disconnect(); + Aardwolf = null; + World._OnConnected(false); + } + + foreach(NetworkClient x in Clients) + x.Disconnect(); + Clients.Clear(); + } + + internal bool Update(long msTime) + { + if(Server != null && Server.Pending()) + { + NetworkClient c = new NetworkClient(Server.AcceptSocket(), this); + Clients.Add(c); + if(Program.Config.GetInt32("ClientCompression", 1) != 0) + { + c.Send(new[] + { + (byte) TelnetOpcodes.IAC, + (byte) TelnetOpcodes.WILL, + (byte) TelnetOpcodes.MCCP_V2, + (byte) TelnetOpcodes.IAC, + (byte) TelnetOpcodes.WILL, + (byte) TelnetOpcodes.MCCP_V1 + }); + } + if(Passwords.Count != 0) + c.Send(Encoding.Default.GetBytes("Proxy password?\n\r")); + else + { + c.AuthLevel = 1; + c.OnAuthed(); + } + } + + bool r = World.Update(msTime); + + if(Aardwolf != null) + { + if(!Aardwolf.Receive()) + { + Aardwolf = null; + World._OnConnected(false); + } + else + Aardwolf.Update(msTime); + } + + bool hadAuthedClient = false; + for(int i = Clients.Count - 1; i >= 0; i--) + { + if(!Clients[i].Receive()) + { + Clients.RemoveAt(i); + continue; + } + + if(Clients[i].AuthLevel >= 1) + hadAuthedClient = true; + } + + if(Aardwolf == null && (hadAuthedClient || Program.Config.GetInt32("AutoConnect", 0) != 0)) + { + Log.Write("Connecting to " + Program.Config.GetString("MUD.Address", "aardmud.org") + ":" + Program.Config.GetInt32("MUD.Port", 4000).ToString()); + try + { + TcpClient t = new TcpClient(Program.Config.GetString("MUD.Address", "aardmud.org"), + Program.Config.GetInt32("MUD.Port", 4000)); + Aardwolf = new NetworkAardwolf(t.Client, this); + World._OnConnected(true); + } + catch(Exception e) + { + Log.Write("Failed connection to Aardwolf: " + e.Message); + } + } + + if(Aardwolf != null) + { + if(strMessage.Length > 0) + strMessage.SetLength(0); + foreach(Message m in World._MessageData) + { + if(m.Clients == null || !m.Clients.Contains((uint)0)) + continue; + + if((m.Flags & MessageFlags.GMCP) != MessageFlags.None) + { + if(m.MsgData == null || m.MsgData.Length == 0) + continue; + + strMessage.Write(new byte[] { + (byte)TelnetOpcodes.IAC, + (byte)TelnetOpcodes.SB, + (byte)TelnetOpcodes.GMCP + }, 0, 3); + strMessage.Write(m.MsgData, 0, m.MsgData.Length); + strMessage.Write(new byte[] { + (byte)TelnetOpcodes.IAC, + (byte)TelnetOpcodes.SE}, 0, 2); + } + else + { + byte[] data = m.MsgData ?? Encoding.Default.GetBytes(m.Msg + m.LineEnding); + strMessage.Write(data, 0, data.Length); + } + } + + if(strMessage.Length != 0) + Aardwolf.Send(strMessage.ToArray()); + } + + for(int i = Clients.Count - 1; i >= 0; i--) + { + if(strMessage.Length > 0) + strMessage.SetLength(0); + + Clients[i].Update(msTime); + + if(Clients[i].AuthLevel < 1) + continue; + + foreach(Message m in World._MessageData) + { + if(m.Clients != null && !m.Clients.Contains(Clients[i].Id)) + continue; + + if((m.AuthMask & ((ulong)1 << (Clients[i].AuthLevel - 1))) == 0) + continue; +//The problem is between here and next comment -- or at least this is what controls the GMCP shit that gets sent to the client. + if((m.Flags & MessageFlags.GMCP) != MessageFlags.None) + { + if(!Clients[i].HasGMCPModule(m.Msg.ToLower())) + continue; + + if(m.MsgData == null || m.MsgData.Length == 0) + continue; + + strMessage.Write(new[] { + (byte)TelnetOpcodes.IAC, + (byte)TelnetOpcodes.SB, + (byte)TelnetOpcodes.GMCP + }, 0, 3); + strMessage.Write(m.MsgData, 0, m.MsgData.Length); + strMessage.Write(new[] { + (byte)TelnetOpcodes.IAC, + (byte)TelnetOpcodes.SE}, 0, 2); + } + else + { + string msg = m.Msg; + msg = Colors.FixColors(msg, false, true); + byte[] data = Encoding.Default.GetBytes(msg + m.LineEnding); + strMessage.Write(data, 0, data.Length); + } +//BLAH + } + + if(strMessage.Length == 0) + continue; + + Clients[i].Send(strMessage.ToArray()); + } + + World._MessageData.Clear(); + return r; + } + } +} diff --git a/ProxyMud/Network/TelnetPacket.cs b/ProxyMud/Network/TelnetPacket.cs new file mode 100644 index 0000000..9920e90 --- /dev/null +++ b/ProxyMud/Network/TelnetPacket.cs @@ -0,0 +1,61 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.IO; + +namespace ProxyMud.Network +{ + internal enum TelnetOpcodes : byte + { + SE = 240, + SB = 250, + WILL = 251, + WONT = 252, + DO = 253, + DONT = 254, + IAC = 255, + + TTYPE = 24, + MCCP_V1 = 85, + MCCP_V2 = 86, + GMCP = 201, + } + + internal class TelnetPacket + { + internal TelnetStates State; + internal TelnetOpcodes Header; + internal TelnetOpcodes Type; + internal MemoryStream Data; + internal bool HadIAC = false; + } + + internal enum TelnetStates + { + /// + /// Just received IAC, nothing else. + /// + None, + + /// + /// Have header (what packet does). + /// + Header, + + /// + /// Have type of packet. + /// + Type, + + /// + /// Gathering data right now waiting for IAC SE. + /// + Data, + + /// + /// Finished packet. + /// + End, + } +} diff --git a/ProxyMud/Network/desktop.ini b/ProxyMud/Network/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/ProxyMud/Network/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/ProxyMud/Program.cs b/ProxyMud/Program.cs new file mode 100644 index 0000000..801d342 --- /dev/null +++ b/ProxyMud/Program.cs @@ -0,0 +1,151 @@ +//#define MONO +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Runtime.InteropServices; +using System.Threading; +using System.Globalization; +using System.Diagnostics; +using ProxyCore; + +namespace ProxyMud +{ + class Program + { + internal static ServerConfig Config; + + static void Main(string[] args) + { +#if !MONO + _handler += new EventHandler(Handler); + SetConsoleCtrlHandler(_handler, true); +#endif + + // Set US culture so config and other formats are universal + Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture("en-US"); + Config = new ServerConfig(); + + Stopwatch watch = new Stopwatch(); + watch.Start(); + + // This is the main loop of the server program + while(canContinue) + { + // The main loop time + const uint sleepTime = 5; + + long time; + + // This is the main loop of the game world + while(canContinue) + { + // Get time before loop + time = watch.ElapsedMilliseconds; + + // Start server if needed + if(Server == null) + { +#if !DEBUG + try + { +#endif + Server = new Network.NetworkServer(); + Server.Start(); +#if !DEBUG + } + catch(Exception e) + { + Log.Error("Failed creating server: " + e.Message); + Shutdown(); + break; + } +#endif + } + + // Update server and everything +#if !DEBUG + try + { +#endif + if(Server.Update(watch.ElapsedMilliseconds)) + Shutdown(); +#if !DEBUG + } + catch(Exception e) + { + Log.Crash(e, "server"); + Shutdown(); + break; + } +#endif + + // Now check time after loop and see how long we should sleep to fill loop time + time = watch.ElapsedMilliseconds - time; + + // Need to sleep some time until next update + if(time <= sleepTime) + { + time = sleepTime - time; + Thread.Sleep((int)time); + } + else + Thread.Sleep(0); // Sleep at least 0 every time so program wouldn't hog CPU + } + + // Loop ended save and shut down + if(Server != null) + Server.Stop(); + } + + isFinished = true; + } + + private static Network.NetworkServer Server = null; + +#region CloseEvent +#if !MONO + [DllImport("Kernel32")] + private static extern bool SetConsoleCtrlHandler(EventHandler handler, bool add); + + private delegate bool EventHandler(CtrlType sig); + static EventHandler _handler; + + enum CtrlType + { + CTRL_C_EVENT = 0, + CTRL_BREAK_EVENT = 1, + CTRL_CLOSE_EVENT = 2, + CTRL_LOGOFF_EVENT = 5, + CTRL_SHUTDOWN_EVENT = 6 + } + + private static bool Handler(CtrlType sig) + { + switch(sig) + { + case CtrlType.CTRL_C_EVENT: + case CtrlType.CTRL_LOGOFF_EVENT: + case CtrlType.CTRL_SHUTDOWN_EVENT: + case CtrlType.CTRL_CLOSE_EVENT: + Shutdown(); + break; + default: + break; + } + while(!isFinished) + Thread.Sleep(10); + return false; + } +#endif + private static bool canContinue = true; + private static bool isFinished = false; + + private static void Shutdown() + { + canContinue = false; + } +#endregion + } +} diff --git a/ProxyMud/Properties/.svn/all-wcprops b/ProxyMud/Properties/.svn/all-wcprops new file mode 100644 index 0000000..cbed7e5 --- /dev/null +++ b/ProxyMud/Properties/.svn/all-wcprops @@ -0,0 +1,11 @@ +K 25 +svn:wc:ra_dav:version-url +V 41 +/svn/!svn/ver/2/trunk/ProxyMud/Properties +END +AssemblyInfo.cs +K 25 +svn:wc:ra_dav:version-url +V 57 +/svn/!svn/ver/2/trunk/ProxyMud/Properties/AssemblyInfo.cs +END diff --git a/ProxyMud/Properties/.svn/desktop.ini b/ProxyMud/Properties/.svn/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/ProxyMud/Properties/.svn/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/ProxyMud/Properties/.svn/dir-prop-base b/ProxyMud/Properties/.svn/dir-prop-base new file mode 100644 index 0000000..f1b96ea --- /dev/null +++ b/ProxyMud/Properties/.svn/dir-prop-base @@ -0,0 +1,5 @@ +K 14 +bugtraq:number +V 4 +true +END diff --git a/ProxyMud/Properties/.svn/entries b/ProxyMud/Properties/.svn/entries new file mode 100644 index 0000000..3f7c3f7 --- /dev/null +++ b/ProxyMud/Properties/.svn/entries @@ -0,0 +1,62 @@ +10 + +dir +58 +http://proxymud.googlecode.com/svn/trunk/ProxyMud/Properties +http://proxymud.googlecode.com/svn + + + +2012-01-17T10:55:35.805502Z +2 +default8p@gmail.com +has-props + + + + + + + + + + + + + +8a6e9f07-fe1d-2472-fcf8-0b435762827a + +AssemblyInfo.cs +file + + + + +2016-03-25T22:18:43.164138Z +eb69874c56b495a6b43efc4f598952f0 +2012-01-17T10:55:35.805502Z +2 +default8p@gmail.com + + + + + + + + + + + + + + + + + + + + + +1452 + diff --git a/ProxyMud/Properties/.svn/prop-base/desktop.ini b/ProxyMud/Properties/.svn/prop-base/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/ProxyMud/Properties/.svn/prop-base/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/ProxyMud/Properties/.svn/props/desktop.ini b/ProxyMud/Properties/.svn/props/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/ProxyMud/Properties/.svn/props/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/ProxyMud/Properties/.svn/text-base/AssemblyInfo.cs.svn-base b/ProxyMud/Properties/.svn/text-base/AssemblyInfo.cs.svn-base new file mode 100644 index 0000000..7abfb3e --- /dev/null +++ b/ProxyMud/Properties/.svn/text-base/AssemblyInfo.cs.svn-base @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("ProxyMapper")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("Microsoft")] +[assembly: AssemblyProduct("ProxyMapper")] +[assembly: AssemblyCopyright("Copyright © Microsoft 2011")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("4ee0393c-9059-4583-9bc5-aeccdc239008")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/ProxyMud/Properties/.svn/text-base/desktop.ini b/ProxyMud/Properties/.svn/text-base/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/ProxyMud/Properties/.svn/text-base/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/ProxyMud/Properties/.svn/tmp/desktop.ini b/ProxyMud/Properties/.svn/tmp/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/ProxyMud/Properties/.svn/tmp/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/ProxyMud/Properties/.svn/tmp/prop-base/desktop.ini b/ProxyMud/Properties/.svn/tmp/prop-base/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/ProxyMud/Properties/.svn/tmp/prop-base/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/ProxyMud/Properties/.svn/tmp/props/desktop.ini b/ProxyMud/Properties/.svn/tmp/props/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/ProxyMud/Properties/.svn/tmp/props/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/ProxyMud/Properties/.svn/tmp/text-base/desktop.ini b/ProxyMud/Properties/.svn/tmp/text-base/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/ProxyMud/Properties/.svn/tmp/text-base/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/ProxyMud/Properties/AssemblyInfo.cs b/ProxyMud/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..977f0f6 --- /dev/null +++ b/ProxyMud/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("Koop-Proxy")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("Microsoft")] +[assembly: AssemblyProduct("Koop-Proxy")] +[assembly: AssemblyCopyright("Copyright © Microsoft 2011")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("4ee0393c-9059-4583-9bc5-aeccdc239008")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/ProxyMud/Properties/desktop.ini b/ProxyMud/Properties/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/ProxyMud/Properties/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/ProxyMud/ProxyMud.csproj b/ProxyMud/ProxyMud.csproj new file mode 100644 index 0000000..8149d3b --- /dev/null +++ b/ProxyMud/ProxyMud.csproj @@ -0,0 +1,99 @@ + + + + Debug + AnyCPU + 9.0.30729 + 2.0 + {B5F8F4E3-630A-420D-8461-420C36BB865C} + Exe + Properties + ProxyMud + ProxyMud + v3.5 + 512 + + + + + 3.5 + publish\ + true + Disk + false + Foreground + 7 + Days + false + false + true + 0 + 1.0.0.%2a + false + false + true + + + true + full + false + ..\..\..\..\Desktop\MushProxy-Build\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + ..\..\..\..\Desktop\MushProxy-Build\ + TRACE + prompt + 4 + + + + False + ..\ProxyCore\bin\ProxyCore.dll + + + + 3.5 + + + 3.5 + + + 3.5 + + + + + False + ..\Resources\zlib.dll + + + + + + + + + + + + + + False + .NET Framework 3.5 SP1 + true + + + + + \ No newline at end of file diff --git a/ProxyMud/desktop.ini b/ProxyMud/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/ProxyMud/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/Resources/.svn/all-wcprops b/Resources/.svn/all-wcprops new file mode 100644 index 0000000..b2f5ec9 --- /dev/null +++ b/Resources/.svn/all-wcprops @@ -0,0 +1,23 @@ +K 25 +svn:wc:ra_dav:version-url +V 31 +/svn/!svn/ver/2/trunk/Resources +END +Jayrock.Json.dll +K 25 +svn:wc:ra_dav:version-url +V 48 +/svn/!svn/ver/2/trunk/Resources/Jayrock.Json.dll +END +zlib.dll +K 25 +svn:wc:ra_dav:version-url +V 40 +/svn/!svn/ver/2/trunk/Resources/zlib.dll +END +Jayrock.dll +K 25 +svn:wc:ra_dav:version-url +V 43 +/svn/!svn/ver/2/trunk/Resources/Jayrock.dll +END diff --git a/Resources/.svn/desktop.ini b/Resources/.svn/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/Resources/.svn/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/Resources/.svn/dir-prop-base b/Resources/.svn/dir-prop-base new file mode 100644 index 0000000..f1b96ea --- /dev/null +++ b/Resources/.svn/dir-prop-base @@ -0,0 +1,5 @@ +K 14 +bugtraq:number +V 4 +true +END diff --git a/Resources/.svn/entries b/Resources/.svn/entries new file mode 100644 index 0000000..21a7e3a --- /dev/null +++ b/Resources/.svn/entries @@ -0,0 +1,130 @@ +10 + +dir +58 +http://proxymud.googlecode.com/svn/trunk/Resources +http://proxymud.googlecode.com/svn + + + +2012-01-17T10:55:35.805502Z +2 +default8p@gmail.com +has-props + + + + + + + + + + + + + +8a6e9f07-fe1d-2472-fcf8-0b435762827a + +Jayrock.Json.dll +file + + + + +2016-03-25T22:18:43.180138Z +459fa765f9ba953efe528a01e8db0646 +2012-01-17T10:55:35.805502Z +2 +default8p@gmail.com +has-props + + + + + + + + + + + + + + + + + + + + +86016 + +zlib.dll +file + + + + +2016-03-25T22:18:43.180138Z +df39bd70ee5b2357b65256d75be7640d +2012-01-17T10:55:35.805502Z +2 +default8p@gmail.com +has-props + + + + + + + + + + + + + + + + + + + + +65536 + +Jayrock.dll +file + + + + +2016-03-25T22:18:43.180138Z +17fa422f0022b511cd53b04ca946e74d +2012-01-17T10:55:35.805502Z +2 +default8p@gmail.com +has-props + + + + + + + + + + + + + + + + + + + + +86016 + diff --git a/Resources/.svn/prop-base/Jayrock.Json.dll.svn-base b/Resources/.svn/prop-base/Jayrock.Json.dll.svn-base new file mode 100644 index 0000000..5e9587e --- /dev/null +++ b/Resources/.svn/prop-base/Jayrock.Json.dll.svn-base @@ -0,0 +1,5 @@ +K 13 +svn:mime-type +V 24 +application/octet-stream +END diff --git a/Resources/.svn/prop-base/Jayrock.dll.svn-base b/Resources/.svn/prop-base/Jayrock.dll.svn-base new file mode 100644 index 0000000..5e9587e --- /dev/null +++ b/Resources/.svn/prop-base/Jayrock.dll.svn-base @@ -0,0 +1,5 @@ +K 13 +svn:mime-type +V 24 +application/octet-stream +END diff --git a/Resources/.svn/prop-base/desktop.ini b/Resources/.svn/prop-base/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/Resources/.svn/prop-base/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/Resources/.svn/prop-base/zlib.dll.svn-base b/Resources/.svn/prop-base/zlib.dll.svn-base new file mode 100644 index 0000000..5e9587e --- /dev/null +++ b/Resources/.svn/prop-base/zlib.dll.svn-base @@ -0,0 +1,5 @@ +K 13 +svn:mime-type +V 24 +application/octet-stream +END diff --git a/Resources/.svn/props/desktop.ini b/Resources/.svn/props/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/Resources/.svn/props/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/Resources/.svn/text-base/Jayrock.Json.dll.svn-base b/Resources/.svn/text-base/Jayrock.Json.dll.svn-base new file mode 100644 index 0000000..eb1a3fa Binary files /dev/null and b/Resources/.svn/text-base/Jayrock.Json.dll.svn-base differ diff --git a/Resources/.svn/text-base/Jayrock.dll.svn-base b/Resources/.svn/text-base/Jayrock.dll.svn-base new file mode 100644 index 0000000..6a7aaa5 Binary files /dev/null and b/Resources/.svn/text-base/Jayrock.dll.svn-base differ diff --git a/Resources/.svn/text-base/desktop.ini b/Resources/.svn/text-base/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/Resources/.svn/text-base/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/Resources/.svn/text-base/zlib.dll.svn-base b/Resources/.svn/text-base/zlib.dll.svn-base new file mode 100644 index 0000000..2f5b3c7 Binary files /dev/null and b/Resources/.svn/text-base/zlib.dll.svn-base differ diff --git a/Resources/.svn/tmp/desktop.ini b/Resources/.svn/tmp/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/Resources/.svn/tmp/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/Resources/.svn/tmp/prop-base/desktop.ini b/Resources/.svn/tmp/prop-base/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/Resources/.svn/tmp/prop-base/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/Resources/.svn/tmp/props/desktop.ini b/Resources/.svn/tmp/props/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/Resources/.svn/tmp/props/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/Resources/.svn/tmp/text-base/desktop.ini b/Resources/.svn/tmp/text-base/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/Resources/.svn/tmp/text-base/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/Resources/Jayrock.Json.dll b/Resources/Jayrock.Json.dll new file mode 100644 index 0000000..eb1a3fa Binary files /dev/null and b/Resources/Jayrock.Json.dll differ diff --git a/Resources/Jayrock.dll b/Resources/Jayrock.dll new file mode 100644 index 0000000..6a7aaa5 Binary files /dev/null and b/Resources/Jayrock.dll differ diff --git a/Resources/desktop.ini b/Resources/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/Resources/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/Resources/zlib.dll b/Resources/zlib.dll new file mode 100644 index 0000000..2f5b3c7 Binary files /dev/null and b/Resources/zlib.dll differ diff --git a/StayAlive/.svn/all-wcprops b/StayAlive/.svn/all-wcprops new file mode 100644 index 0000000..2fd9254 --- /dev/null +++ b/StayAlive/.svn/all-wcprops @@ -0,0 +1,17 @@ +K 25 +svn:wc:ra_dav:version-url +V 32 +/svn/!svn/ver/54/trunk/StayAlive +END +StayAlive.csproj +K 25 +svn:wc:ra_dav:version-url +V 48 +/svn/!svn/ver/3/trunk/StayAlive/StayAlive.csproj +END +StayAlive.cs +K 25 +svn:wc:ra_dav:version-url +V 45 +/svn/!svn/ver/54/trunk/StayAlive/StayAlive.cs +END diff --git a/StayAlive/.svn/desktop.ini b/StayAlive/.svn/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/StayAlive/.svn/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/StayAlive/.svn/dir-prop-base b/StayAlive/.svn/dir-prop-base new file mode 100644 index 0000000..f1b96ea --- /dev/null +++ b/StayAlive/.svn/dir-prop-base @@ -0,0 +1,5 @@ +K 14 +bugtraq:number +V 4 +true +END diff --git a/StayAlive/.svn/entries b/StayAlive/.svn/entries new file mode 100644 index 0000000..9613668 --- /dev/null +++ b/StayAlive/.svn/entries @@ -0,0 +1,99 @@ +10 + +dir +58 +http://proxymud.googlecode.com/svn/trunk/StayAlive +http://proxymud.googlecode.com/svn + + + +2012-02-02T08:38:33.263906Z +54 +default8p@gmail.com +has-props + + + + + + + + + + + + + +8a6e9f07-fe1d-2472-fcf8-0b435762827a + +Properties +dir + +StayAlive.csproj +file + + + + +2016-03-25T22:18:42.960135Z +8fb7bea03e6fc9c40a71f9d881d65d6d +2012-01-17T11:22:55.097115Z +3 +default8p@gmail.com + + + + + + + + + + + + + + + + + + + + + +2721 + +StayAlive.cs +file + + + + +2016-03-25T22:18:42.960135Z +c15494448574a9115f0a324c00ad5dcd +2012-02-02T08:38:33.263906Z +54 +default8p@gmail.com + + + + + + + + + + + + + + + + + + + + + +3527 + diff --git a/StayAlive/.svn/prop-base/desktop.ini b/StayAlive/.svn/prop-base/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/StayAlive/.svn/prop-base/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/StayAlive/.svn/props/desktop.ini b/StayAlive/.svn/props/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/StayAlive/.svn/props/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/StayAlive/.svn/text-base/StayAlive.cs.svn-base b/StayAlive/.svn/text-base/StayAlive.cs.svn-base new file mode 100644 index 0000000..e60ed52 --- /dev/null +++ b/StayAlive/.svn/text-base/StayAlive.cs.svn-base @@ -0,0 +1,110 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using ProxyCore; +using ProxyCore.Output; +using ProxyCore.Scripting; + +namespace StayAlive +{ + public class StayAlive : Plugin + { + public StayAlive() + : base("stayalive", "Stay logged in") + { + Author = "Duckbat"; + Version = 4; + Description = "Automatically stays logged in."; + UpdateUrl = "www.duckbat.com/plugins/update.stayalive.txt"; + Website = "code.google.com/p/proxymud/"; + + Config = new StayAliveConfig(); + + RegisterTrigger("autologin.name", "What be thy name, adventurer?", TriggerUsername); + RegisterTrigger("autologin.pass", "Existing profile loaded - please enter your password.", TriggerPassword); + } + + public override void OnConnect() + { + base.OnConnect(); + + CanEnterUsername = 1; + } + + private bool TriggerUsername(TriggerData t) + { + if(CanEnterUsername != 1) + return false; + + string n = Config.GetString("AutoLogin.User", "").Trim(); + if(string.IsNullOrEmpty(n)) + { + CanEnterUsername = 0; + return false; + } + + string p = Config.GetString("AutoLogin.Pass", "").Trim(); + if(string.IsNullOrEmpty(p)) + { + CanEnterUsername = 0; + return false; + } + + CanEnterUsername = 2; + World.Instance.Execute(n, false); + return false; + } + + private bool TriggerPassword(TriggerData t) + { + if(CanEnterUsername != 2) + return false; + + string p = Config.GetString("AutoLogin.Pass", "").Trim(); + if(string.IsNullOrEmpty(p)) + { + CanEnterUsername = 0; + return false; + } + + CanEnterUsername = 0; + World.Instance.Execute(p, false); + + World.Instance.Execute("", false); + return false; + } + + private int CanEnterUsername = 0; + + public override void OnLoadedConfig(bool Success) + { + base.OnLoadedConfig(Success); + + string n = Config.GetString("StayAlive.Line", "@wYour eyes glaze over."); + if(string.IsNullOrEmpty(n)) + return; + + RegisterTrigger("line", n, TriggerLine, TriggerFlags.NotRegex); + } + + private bool TriggerLine(TriggerData t) + { + World.Instance.Execute(Config.GetString("StayAlive.Command", ""), false); + return false; + } + } + + public class StayAliveConfig : ConfigFile + { + protected override void OnCreated() + { + base.OnCreated(); + + CreateSetting("StayAlive.Command", "", "What to send to MUD when we receive line about being idle. You can leave this blank to just send enter key."); + CreateSetting("StayAlive.Line", "@wYour eyes glaze over.", "On what line do we send command? Default: \"@wYour eyes glaze over.\""); + CreateSetting("AutoLogin.User", "", "User name to automatically log in with. Leave blank to disable this feature."); + CreateSetting("AutoLogin.Pass", "", "Password to automatically log in with. Leave blank to disable this feature."); + } + } +} diff --git a/StayAlive/.svn/text-base/StayAlive.csproj.svn-base b/StayAlive/.svn/text-base/StayAlive.csproj.svn-base new file mode 100644 index 0000000..ef89212 --- /dev/null +++ b/StayAlive/.svn/text-base/StayAlive.csproj.svn-base @@ -0,0 +1,63 @@ + + + + Debug + AnyCPU + 9.0.30729 + 2.0 + {CBD347BC-6BF8-417B-92B1-0BD44532A971} + Library + Properties + StayAlive + StayAlive + v3.5 + 512 + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + False + ..\ProxyCore\bin\ProxyCore.dll + + + + 3.5 + + + 3.5 + + + 3.5 + + + + + + + + + + + \ No newline at end of file diff --git a/StayAlive/.svn/text-base/desktop.ini b/StayAlive/.svn/text-base/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/StayAlive/.svn/text-base/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/StayAlive/.svn/tmp/desktop.ini b/StayAlive/.svn/tmp/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/StayAlive/.svn/tmp/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/StayAlive/.svn/tmp/prop-base/desktop.ini b/StayAlive/.svn/tmp/prop-base/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/StayAlive/.svn/tmp/prop-base/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/StayAlive/.svn/tmp/props/desktop.ini b/StayAlive/.svn/tmp/props/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/StayAlive/.svn/tmp/props/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/StayAlive/.svn/tmp/text-base/desktop.ini b/StayAlive/.svn/tmp/text-base/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/StayAlive/.svn/tmp/text-base/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/StayAlive/Properties/.svn/all-wcprops b/StayAlive/Properties/.svn/all-wcprops new file mode 100644 index 0000000..45485b5 --- /dev/null +++ b/StayAlive/Properties/.svn/all-wcprops @@ -0,0 +1,11 @@ +K 25 +svn:wc:ra_dav:version-url +V 42 +/svn/!svn/ver/3/trunk/StayAlive/Properties +END +AssemblyInfo.cs +K 25 +svn:wc:ra_dav:version-url +V 58 +/svn/!svn/ver/3/trunk/StayAlive/Properties/AssemblyInfo.cs +END diff --git a/StayAlive/Properties/.svn/desktop.ini b/StayAlive/Properties/.svn/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/StayAlive/Properties/.svn/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/StayAlive/Properties/.svn/dir-prop-base b/StayAlive/Properties/.svn/dir-prop-base new file mode 100644 index 0000000..f1b96ea --- /dev/null +++ b/StayAlive/Properties/.svn/dir-prop-base @@ -0,0 +1,5 @@ +K 14 +bugtraq:number +V 4 +true +END diff --git a/StayAlive/Properties/.svn/entries b/StayAlive/Properties/.svn/entries new file mode 100644 index 0000000..55dfc4c --- /dev/null +++ b/StayAlive/Properties/.svn/entries @@ -0,0 +1,62 @@ +10 + +dir +58 +http://proxymud.googlecode.com/svn/trunk/StayAlive/Properties +http://proxymud.googlecode.com/svn + + + +2012-01-17T11:22:55.097115Z +3 +default8p@gmail.com +has-props + + + + + + + + + + + + + +8a6e9f07-fe1d-2472-fcf8-0b435762827a + +AssemblyInfo.cs +file + + + + +2016-03-25T22:18:42.960135Z +0b1389d5f8259145f5e25a0538b0dd64 +2012-01-17T11:22:55.097115Z +3 +default8p@gmail.com + + + + + + + + + + + + + + + + + + + + + +1430 + diff --git a/StayAlive/Properties/.svn/prop-base/desktop.ini b/StayAlive/Properties/.svn/prop-base/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/StayAlive/Properties/.svn/prop-base/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/StayAlive/Properties/.svn/props/desktop.ini b/StayAlive/Properties/.svn/props/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/StayAlive/Properties/.svn/props/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/StayAlive/Properties/.svn/text-base/AssemblyInfo.cs.svn-base b/StayAlive/Properties/.svn/text-base/AssemblyInfo.cs.svn-base new file mode 100644 index 0000000..799566b --- /dev/null +++ b/StayAlive/Properties/.svn/text-base/AssemblyInfo.cs.svn-base @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("StayAlive")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("StayAlive")] +[assembly: AssemblyCopyright("Copyright © 2012")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("d3850c5b-f9da-47e1-9451-9228e9f49f8f")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/StayAlive/Properties/.svn/text-base/desktop.ini b/StayAlive/Properties/.svn/text-base/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/StayAlive/Properties/.svn/text-base/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/StayAlive/Properties/.svn/tmp/desktop.ini b/StayAlive/Properties/.svn/tmp/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/StayAlive/Properties/.svn/tmp/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/StayAlive/Properties/.svn/tmp/prop-base/desktop.ini b/StayAlive/Properties/.svn/tmp/prop-base/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/StayAlive/Properties/.svn/tmp/prop-base/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/StayAlive/Properties/.svn/tmp/props/desktop.ini b/StayAlive/Properties/.svn/tmp/props/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/StayAlive/Properties/.svn/tmp/props/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/StayAlive/Properties/.svn/tmp/text-base/desktop.ini b/StayAlive/Properties/.svn/tmp/text-base/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/StayAlive/Properties/.svn/tmp/text-base/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/StayAlive/Properties/AssemblyInfo.cs b/StayAlive/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..799566b --- /dev/null +++ b/StayAlive/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("StayAlive")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("StayAlive")] +[assembly: AssemblyCopyright("Copyright © 2012")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("d3850c5b-f9da-47e1-9451-9228e9f49f8f")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/StayAlive/Properties/desktop.ini b/StayAlive/Properties/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/StayAlive/Properties/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/StayAlive/StayAlive.cs b/StayAlive/StayAlive.cs new file mode 100644 index 0000000..e60ed52 --- /dev/null +++ b/StayAlive/StayAlive.cs @@ -0,0 +1,110 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using ProxyCore; +using ProxyCore.Output; +using ProxyCore.Scripting; + +namespace StayAlive +{ + public class StayAlive : Plugin + { + public StayAlive() + : base("stayalive", "Stay logged in") + { + Author = "Duckbat"; + Version = 4; + Description = "Automatically stays logged in."; + UpdateUrl = "www.duckbat.com/plugins/update.stayalive.txt"; + Website = "code.google.com/p/proxymud/"; + + Config = new StayAliveConfig(); + + RegisterTrigger("autologin.name", "What be thy name, adventurer?", TriggerUsername); + RegisterTrigger("autologin.pass", "Existing profile loaded - please enter your password.", TriggerPassword); + } + + public override void OnConnect() + { + base.OnConnect(); + + CanEnterUsername = 1; + } + + private bool TriggerUsername(TriggerData t) + { + if(CanEnterUsername != 1) + return false; + + string n = Config.GetString("AutoLogin.User", "").Trim(); + if(string.IsNullOrEmpty(n)) + { + CanEnterUsername = 0; + return false; + } + + string p = Config.GetString("AutoLogin.Pass", "").Trim(); + if(string.IsNullOrEmpty(p)) + { + CanEnterUsername = 0; + return false; + } + + CanEnterUsername = 2; + World.Instance.Execute(n, false); + return false; + } + + private bool TriggerPassword(TriggerData t) + { + if(CanEnterUsername != 2) + return false; + + string p = Config.GetString("AutoLogin.Pass", "").Trim(); + if(string.IsNullOrEmpty(p)) + { + CanEnterUsername = 0; + return false; + } + + CanEnterUsername = 0; + World.Instance.Execute(p, false); + + World.Instance.Execute("", false); + return false; + } + + private int CanEnterUsername = 0; + + public override void OnLoadedConfig(bool Success) + { + base.OnLoadedConfig(Success); + + string n = Config.GetString("StayAlive.Line", "@wYour eyes glaze over."); + if(string.IsNullOrEmpty(n)) + return; + + RegisterTrigger("line", n, TriggerLine, TriggerFlags.NotRegex); + } + + private bool TriggerLine(TriggerData t) + { + World.Instance.Execute(Config.GetString("StayAlive.Command", ""), false); + return false; + } + } + + public class StayAliveConfig : ConfigFile + { + protected override void OnCreated() + { + base.OnCreated(); + + CreateSetting("StayAlive.Command", "", "What to send to MUD when we receive line about being idle. You can leave this blank to just send enter key."); + CreateSetting("StayAlive.Line", "@wYour eyes glaze over.", "On what line do we send command? Default: \"@wYour eyes glaze over.\""); + CreateSetting("AutoLogin.User", "", "User name to automatically log in with. Leave blank to disable this feature."); + CreateSetting("AutoLogin.Pass", "", "Password to automatically log in with. Leave blank to disable this feature."); + } + } +} diff --git a/StayAlive/StayAlive.csproj b/StayAlive/StayAlive.csproj new file mode 100644 index 0000000..5be8661 --- /dev/null +++ b/StayAlive/StayAlive.csproj @@ -0,0 +1,90 @@ + + + + Debug + AnyCPU + 9.0.30729 + 2.0 + {CBD347BC-6BF8-417B-92B1-0BD44532A971} + Library + Properties + StayAlive + StayAlive + v3.5 + 512 + + + + + 3.5 + publish\ + true + Disk + false + Foreground + 7 + Days + false + false + true + 0 + 1.0.0.%2a + false + false + true + + + true + full + false + ..\..\..\..\Desktop\MushProxy-Build\Plugins\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + ..\..\..\..\Desktop\MushProxy-Build\Plugins\ + TRACE + prompt + 4 + + + + False + ..\ProxyCore\bin\ProxyCore.dll + + + + 3.5 + + + 3.5 + + + 3.5 + + + + + + + + + + + False + .NET Framework 3.5 SP1 + true + + + + + \ No newline at end of file diff --git a/StayAlive/desktop.ini b/StayAlive/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/StayAlive/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/desktop.ini b/desktop.ini new file mode 100644 index 0000000..309dea2 --- /dev/null +++ b/desktop.ini @@ -0,0 +1,5 @@ +[.ShellClassInfo] +InfoTip=This folder is shared online. +IconFile=C:\Program Files (x86)\Google\Drive\googledrivesync.exe +IconIndex=16 + \ No newline at end of file diff --git a/zlib.dll b/zlib.dll new file mode 100644 index 0000000..2f5b3c7 Binary files /dev/null and b/zlib.dll differ