diff --git a/MCGalaxy/Bots/BotsFile.cs b/MCGalaxy/Bots/BotsFile.cs index 993e0b725..d8e1e6203 100644 --- a/MCGalaxy/Bots/BotsFile.cs +++ b/MCGalaxy/Bots/BotsFile.cs @@ -16,58 +16,59 @@ permissions and limitations under the Licenses. */ using System; -using System.Collections.Generic; using System.IO; -using Newtonsoft.Json; using MCGalaxy.Maths; +using Newtonsoft.Json; namespace MCGalaxy.Bots { /// Maintains persistent data for in-game bots. public static class BotsFile { - - public static List SavedBots = new List(); - - static readonly object locker = new object(); - - public static void Load() { - if (!File.Exists(Paths.BotsFile)) return; - lock (locker) { - string json = File.ReadAllText(Paths.BotsFile); - BotProperties[] bots = JsonConvert.DeserializeObject(json); - SavedBots = new List(bots); - - foreach (BotProperties bot in SavedBots) { - if (String.IsNullOrEmpty(bot.DisplayName)) - bot.DisplayName = bot.Name; + + public static string BotsPath(string mapName) { + return "extra/bots/" + mapName + ".json"; + } + + public static void Load(Level lvl) { + string path = BotsPath(lvl.MapName); + if (!File.Exists(path)) return; + string json = File.ReadAllText(path); + BotProperties[] bots = JsonConvert.DeserializeObject(json); + + foreach (BotProperties props in bots) { + if (String.IsNullOrEmpty(props.DisplayName)) { + props.DisplayName = props.Name; } + + PlayerBot bot = new PlayerBot(props.Name, lvl); + props.ApplyTo(bot); + + bot.ModelBB = AABB.ModelAABB(bot.Model, lvl); + LoadAi(props, bot); + PlayerBot.Add(bot, false); } } - static void Save() { - BotProperties[] bots = SavedBots.ToArray(); - string json = JsonConvert.SerializeObject(bots); + public static void Save(Level lvl) { + PlayerBot[] bots = lvl.Bots.Items; + string path = BotsPath(lvl.MapName); + if (!File.Exists(path) && bots.Length == 0) return; + + BotProperties[] props = new BotProperties[bots.Length]; + for (int i = 0; i < props.Length; i++) { + BotProperties savedProps = new BotProperties(); + savedProps.FromBot(bots[i]); + props[i] = savedProps; + } + + string json = JsonConvert.SerializeObject(props); try { - File.WriteAllText(Paths.BotsFile, json); + File.WriteAllText(path, json); } catch (Exception ex) { Logger.Log(LogType.Warning, "Failed to save bots file"); Logger.LogError(ex); } } - - public static void LoadBots(Level lvl) { - lock (locker) { - foreach (BotProperties props in SavedBots) { - if (lvl.name != props.Level) continue; - PlayerBot bot = new PlayerBot(props.Name, lvl); - props.ApplyTo(bot); - - bot.ModelBB = AABB.ModelAABB(bot.Model, lvl); - LoadAi(props, bot); - PlayerBot.Add(bot, false); - } - } - } static void LoadAi(BotProperties props, PlayerBot bot) { if (String.IsNullOrEmpty(props.AI)) return; @@ -78,96 +79,7 @@ namespace MCGalaxy.Bots { } bot.cur = props.CurInstruction; - if (bot.cur >= bot.Instructions.Count) - bot.cur = 0; - } - - public static void UnloadBots(Level lvl) { - lock (locker) { - PlayerBot[] bots = lvl.Bots.Items; - - foreach (PlayerBot bot in bots) { - DoUpdateBot(bot, false); - } - if (bots.Length > 0) Save(); - } - } - - public static void RemoveBot(PlayerBot bot) { - lock (locker) { - for (int i = 0; i < SavedBots.Count; i++) { - BotProperties props = SavedBots[i]; - if (bot.name != props.Name || bot.level.name != props.Level) continue; - SavedBots.RemoveAt(i); - Save(); - return; - } - } - } - - /// Deletes all bots which are located on the given map. - public static void DeleteBots(string level) { - lock (locker) { - int removed = 0; - for (int i = 0; i < SavedBots.Count; i++) { - BotProperties props = SavedBots[i]; - if (!props.Level.CaselessEq(level)) continue; - - SavedBots.RemoveAt(i); - removed++; i--; - } - if (removed > 0) Save(); - } - } - - /// Moves all bots located on the given source map to the destination map. - public static void MoveBots(string srcLevel, string dstLevel) { - lock (locker) { - int moved = 0; - for (int i = 0; i < SavedBots.Count; i++) { - BotProperties props = SavedBots[i]; - if (!props.Level.CaselessEq(srcLevel)) continue; - - props.Level = dstLevel; - moved++; - } - if (moved > 0) Save(); - } - } - - /// Copies all bots located on the given source map to the destination map. - public static void CopyBots(string srcLevel, string dstLevel) { - lock (locker) { - int copied = 0, count = SavedBots.Count; - for (int i = 0; i < SavedBots.Count; i++) { - BotProperties props = SavedBots[i]; - if (!props.Level.CaselessEq(srcLevel)) continue; - - BotProperties copy = props.Copy(); - copy.Level = dstLevel; - SavedBots.Add(copy); - copied++; - } - if (copied > 0) Save(); - } - } - - public static void UpdateBot(PlayerBot bot) { - lock (locker) DoUpdateBot(bot, true); - } - - static void DoUpdateBot(PlayerBot bot, bool save) { - foreach (BotProperties props in SavedBots) { - if (bot.name != props.Name || bot.level.name != props.Level) continue; - props.FromBot(bot); - if (save) Save(); - return; - } - - BotProperties newProps = new BotProperties(); - newProps.FromBot(bot); - SavedBots.Add(newProps); - if (save) Save(); + if (bot.cur >= bot.Instructions.Count) bot.cur = 0; } } @@ -208,7 +120,7 @@ namespace MCGalaxy.Bots { } public void ApplyTo(PlayerBot bot) { - bot.Pos = new Position(X, Y, Z); + bot.Pos = new Position(X, Y, Z); bot.SetYawPitch(RotX, RotY); Orientation rot = bot.Rot; rot.RotX = BodyX; rot.RotZ = BodyZ; diff --git a/MCGalaxy/Bots/PlayerBot.cs b/MCGalaxy/Bots/PlayerBot.cs index 4a1755ebe..17e1f4894 100644 --- a/MCGalaxy/Bots/PlayerBot.cs +++ b/MCGalaxy/Bots/PlayerBot.cs @@ -17,6 +17,7 @@ */ using System; using System.Collections.Generic; +using System.IO; using MCGalaxy.Bots; using MCGalaxy.Maths; using MCGalaxy.Network; @@ -71,24 +72,24 @@ namespace MCGalaxy { public static void Add(PlayerBot bot, bool save = true) { bot.level.Bots.Add(bot); bot.GlobalSpawn(); - if (save) BotsFile.UpdateBot(bot); + if (save) BotsFile.Save(bot.level); } public static void Remove(PlayerBot bot, bool save = true) { bot.level.Bots.Remove(bot); bot.GlobalDespawn(); bot.jumping = false; - if (save) BotsFile.RemoveBot(bot); + if (save) BotsFile.Save(bot.level); } public static void UnloadFromLevel(Level lvl) { - BotsFile.UnloadBots(lvl); + BotsFile.Save(lvl); RemoveLoadedBots(lvl, false); } public static void RemoveAllFromLevel(Level lvl) { - RemoveLoadedBots(lvl, true); - BotsFile.DeleteBots(lvl.name); + RemoveLoadedBots(lvl, false); + BotsFile.Save(lvl); } static void RemoveLoadedBots(Level lvl, bool save) { diff --git a/MCGalaxy/Commands/Bots/CmdBot.cs b/MCGalaxy/Commands/Bots/CmdBot.cs index e54471f1c..0e99f3d86 100644 --- a/MCGalaxy/Commands/Bots/CmdBot.cs +++ b/MCGalaxy/Commands/Bots/CmdBot.cs @@ -102,7 +102,7 @@ namespace MCGalaxy.Commands.Bots { Player.Message(p, "Set text shown when bot {0} %Sis clicked on to {1}", bot.ColoredName, text); bot.ClickedOnText = text; } - BotsFile.UpdateBot(bot); + BotsFile.Save(bot.level); } public override void Help(Player p) { diff --git a/MCGalaxy/Commands/Bots/CmdBotSet.cs b/MCGalaxy/Commands/Bots/CmdBotSet.cs index b4915d325..6190c18de 100644 --- a/MCGalaxy/Commands/Bots/CmdBotSet.cs +++ b/MCGalaxy/Commands/Bots/CmdBotSet.cs @@ -74,7 +74,7 @@ namespace MCGalaxy.Commands.Bots { static void UpdateBot(Player p, PlayerBot bot, string msg) { Player.Message(p, bot.ColoredName + "%S" + msg); Logger.Log(LogType.UserActivity, bot.name + msg); - BotsFile.UpdateBot(bot); + BotsFile.Save(bot.level); } public override void Help(Player p) { diff --git a/MCGalaxy/Commands/Bots/CmdBotSummon.cs b/MCGalaxy/Commands/Bots/CmdBotSummon.cs index 2b530be93..a9c6300a2 100644 --- a/MCGalaxy/Commands/Bots/CmdBotSummon.cs +++ b/MCGalaxy/Commands/Bots/CmdBotSummon.cs @@ -36,7 +36,7 @@ namespace MCGalaxy.Commands.Bots { if (bot == null) return; bot.Pos = p.Pos; bot.SetYawPitch(p.Rot.RotY, p.Rot.HeadX); - BotsFile.UpdateBot(bot); + BotsFile.Save(bot.level); } public override void Help(Player p) { diff --git a/MCGalaxy/Commands/CPE/CmdEntityRot.cs b/MCGalaxy/Commands/CPE/CmdEntityRot.cs index f46c756d2..f3e4c51ab 100644 --- a/MCGalaxy/Commands/CPE/CmdEntityRot.cs +++ b/MCGalaxy/Commands/CPE/CmdEntityRot.cs @@ -39,7 +39,7 @@ namespace MCGalaxy.Commands.CPE { protected override void SetBotData(Player p, PlayerBot bot, string args) { if (!ParseArgs(p, args, bot)) return; - BotsFile.UpdateBot(bot); + BotsFile.Save(bot.level); } protected override void SetPlayerData(Player p, Player who, string args) { diff --git a/MCGalaxy/Commands/CPE/CmdModel.cs b/MCGalaxy/Commands/CPE/CmdModel.cs index 3772e650e..22232df0e 100644 --- a/MCGalaxy/Commands/CPE/CmdModel.cs +++ b/MCGalaxy/Commands/CPE/CmdModel.cs @@ -45,7 +45,7 @@ namespace MCGalaxy.Commands.CPE { Entities.UpdateModel(bot, model); Player.Message(p, "You changed the model of bot " + bot.ColoredName + " %Sto a &c" + model); - BotsFile.UpdateBot(bot); + BotsFile.Save(bot.level); } protected override void SetPlayerData(Player p, Player who, string model) { diff --git a/MCGalaxy/Commands/CPE/CmdSkin.cs b/MCGalaxy/Commands/CPE/CmdSkin.cs index 312635bdb..48a25d391 100644 --- a/MCGalaxy/Commands/CPE/CmdSkin.cs +++ b/MCGalaxy/Commands/CPE/CmdSkin.cs @@ -43,7 +43,7 @@ namespace MCGalaxy.Commands.CPE { bot.GlobalDespawn(); bot.GlobalSpawn(); - BotsFile.UpdateBot(bot); + BotsFile.Save(bot.level); } protected override void SetPlayerData(Player p, Player who, string skin) { diff --git a/MCGalaxy/Commands/Chat/CmdColor.cs b/MCGalaxy/Commands/Chat/CmdColor.cs index 35077e0fe..8256ef6c4 100644 --- a/MCGalaxy/Commands/Chat/CmdColor.cs +++ b/MCGalaxy/Commands/Chat/CmdColor.cs @@ -47,7 +47,7 @@ namespace MCGalaxy.Commands.Chatting { bot.GlobalDespawn(); bot.GlobalSpawn(); - BotsFile.UpdateBot(bot); + BotsFile.Save(bot.level); } protected override void SetPlayerData(Player p, Player who, string colName) { diff --git a/MCGalaxy/Commands/Chat/CmdNick.cs b/MCGalaxy/Commands/Chat/CmdNick.cs index eeb17a831..5229a5f60 100644 --- a/MCGalaxy/Commands/Chat/CmdNick.cs +++ b/MCGalaxy/Commands/Chat/CmdNick.cs @@ -53,7 +53,7 @@ namespace MCGalaxy.Commands.Chatting { bot.GlobalDespawn(); bot.GlobalSpawn(); - BotsFile.UpdateBot(bot); + BotsFile.Save(bot.level); } protected override void SetPlayerData(Player p, Player who, string nick) { diff --git a/MCGalaxy/Levels/Level.cs b/MCGalaxy/Levels/Level.cs index 3aa426c8e..37311d298 100644 --- a/MCGalaxy/Levels/Level.cs +++ b/MCGalaxy/Levels/Level.cs @@ -337,7 +337,7 @@ namespace MCGalaxy { lvl.Config.jailroty = lvl.roty; LoadMetadata(lvl); - MCGalaxy.Bots.BotsFile.LoadBots(lvl); + MCGalaxy.Bots.BotsFile.Load(lvl); object locker = ThreadSafeCache.DBCache.GetLocker(name); lock (locker) { diff --git a/MCGalaxy/Levels/LevelActions.cs b/MCGalaxy/Levels/LevelActions.cs index 6c3ad645c..b2c1bab43 100644 --- a/MCGalaxy/Levels/LevelActions.cs +++ b/MCGalaxy/Levels/LevelActions.cs @@ -41,13 +41,14 @@ namespace MCGalaxy { "blockdefs/lvl_" + dst + ".json"); MoveIfExists("blockprops/lvl_" + src + ".txt", "blockprops/lvl_" + dst + ".txt"); + MoveIfExists(BotsFile.BotsPath(src), + BotsFile.BotsPath(dst)); try { MoveBackups(src, dst); } catch { } - BotsFile.MoveBots(src, dst); RenameDatabaseTables(src, dst); BlockDBFile.MoveBackingFile(src, dst); } @@ -132,8 +133,8 @@ namespace MCGalaxy { DeleteIfExists("levels/level properties/" + name + ".properties"); DeleteIfExists("blockdefs/lvl_" + name + ".json"); DeleteIfExists("blockprops/lvl_" + name + ".txt"); + DeleteIfExists(BotsFile.BotsPath(name)); - BotsFile.DeleteBots(name); DeleteDatabaseTables(name); BlockDBFile.DeleteBackingFile(name); } @@ -217,8 +218,9 @@ namespace MCGalaxy { "blockdefs/lvl_" + dst + ".json"); CopyIfExists("blockprops/lvl_" + src + ".txt", "blockprops/lvl_" + dst + ".txt"); + CopyIfExists(BotsFile.BotsPath(src), + BotsFile.BotsPath(dst)); - BotsFile.CopyBots(src, dst); CopyDatabaseTables(src, dst); } diff --git a/MCGalaxy/Server/Server.cs b/MCGalaxy/Server/Server.cs index cfd009251..975a698fe 100644 --- a/MCGalaxy/Server/Server.cs +++ b/MCGalaxy/Server/Server.cs @@ -128,6 +128,7 @@ namespace MCGalaxy { Background.QueueOnce(UpgradeTasks.UpgradeDBTimeSpent); Background.QueueOnce(LoadPlayerLists); Background.QueueOnce(UpgradeTasks.UpgradeOldLockdown); + Background.QueueOnce(UpgradeTasks.UpgradeBots); Background.QueueOnce(SetupSocket); Background.QueueOnce(InitTimers); @@ -163,6 +164,7 @@ namespace MCGalaxy { if (!Directory.Exists("extra")) Directory.CreateDirectory("extra"); if (!Directory.Exists("extra/Waypoints")) Directory.CreateDirectory("extra/Waypoints"); + if (!Directory.Exists("extra/bots")) Directory.CreateDirectory("extra/bots"); if (!Directory.Exists("blockdefs")) Directory.CreateDirectory("blockdefs"); } @@ -192,7 +194,6 @@ namespace MCGalaxy { zombie.LoadInfectMessages(); Colors.LoadList(); Alias.Load(); - Bots.BotsFile.Load(); BlockDefinition.LoadGlobal(); ImagePalette.Load(); diff --git a/MCGalaxy/Server/Tasks/UpgradeTasks.cs b/MCGalaxy/Server/Tasks/UpgradeTasks.cs index bc7328714..35f593119 100644 --- a/MCGalaxy/Server/Tasks/UpgradeTasks.cs +++ b/MCGalaxy/Server/Tasks/UpgradeTasks.cs @@ -15,18 +15,14 @@ or implied. See the Licenses for the specific language governing permissions and limitations under the Licenses. */ -using System; -using System.Collections.Generic; -using System.IO; -using System.Net; -using System.Threading; -using MCGalaxy.Commands.World; -using MCGalaxy.Games; -using MCGalaxy.Generator; -using MCGalaxy.DB; -using System.Data; -using System.Data.Common; -using MCGalaxy.SQL; +using System; +using System.Collections.Generic; +using System.Data; +using System.IO; +using MCGalaxy.Bots; +using MCGalaxy.DB; +using MCGalaxy.SQL; +using Newtonsoft.Json; namespace MCGalaxy.Tasks { internal static class UpgradeTasks { @@ -182,6 +178,39 @@ namespace MCGalaxy.Tasks { File.WriteAllLines(Paths.TempRanksFile, lines); } + internal static void UpgradeBots(SchedulerTask task) { + if (!File.Exists(Paths.BotsFile)) return; + string json = File.ReadAllText(Paths.BotsFile); + File.WriteAllText(Paths.BotsFile + ".bak", json); + Logger.Log(LogType.SystemActivity, "Making bots file per-level.. " + + "saved backup of global bots file to extra/bots.json.bak"); + + BotProperties[] bots = JsonConvert.DeserializeObject(json); + Dictionary> botsByLevel = new Dictionary>(); + + foreach (BotProperties bot in bots) { + List levelBots; + if (bot.Level == null || bot.Level.Length == 0) continue; + + if (!botsByLevel.TryGetValue(bot.Level, out levelBots)) { + levelBots = new List(); + botsByLevel[bot.Level] = levelBots; + } + levelBots.Add(bot); + } + + foreach (var kvp in botsByLevel) { + json = JsonConvert.SerializeObject(kvp.Value); + File.WriteAllText(BotsFile.BotsPath(kvp.Key), json); + } + + if (Server.mainLevel.Bots.Count == 0) { + BotsFile.Load(Server.mainLevel); + } + File.Delete(Paths.BotsFile); + } + + internal static void UpgradeDBTimeSpent(SchedulerTask task) { DataTable table = Database.Backend.GetRows(PlayerData.DBTable, "TimeSpent", "LIMIT 1"); if (table.Rows.Count == 0) return; // no players diff --git a/MCGalaxy/util/IO/Paths.cs b/MCGalaxy/util/IO/Paths.cs index bd0d0422e..eea448f7e 100644 --- a/MCGalaxy/util/IO/Paths.cs +++ b/MCGalaxy/util/IO/Paths.cs @@ -34,16 +34,14 @@ namespace MCGalaxy { public const string AliasesFile = "text/aliases.txt"; public const string NewsFile = "text/news.txt"; public const string WelcomeFile = "text/welcome.txt"; - public const string JokerFile = "text/joker.txt"; - + public const string JokerFile = "text/joker.txt"; public const string BlockPermsFile = "properties/block.properties"; public const string CmdPermsFile = "properties/command.properties"; public const string CmdExtraPermsFile = "properties/ExtraCommandPermissions.properties"; public const string EconomyPropsFile = "properties/economy.properties"; public const string ServerPropsFile = "properties/server.properties"; - public const string RankPropsFile = "properties/ranks.properties"; - + public const string RankPropsFile = "properties/ranks.properties"; public const string BotsFile = "extra/bots.json"; }