fix /copylvl and /renamelvl with blockprops (thanks nosliw)

This commit is contained in:
UnknownShadow200 2017-01-25 12:08:56 +11:00
parent 5514877a20
commit fca6ae43b3
15 changed files with 233 additions and 66 deletions

View File

@ -56,7 +56,7 @@ namespace MCGalaxy.Blocks.Physics {
public static void DoFastLava(Level lvl, ref Check C) {
if (lvl.randomFlow) {
DoLavaRandowFlow(lvl, ref C, false);
if (C.data.Data != 255)
if (C.data.Data != PhysicsArgs.RemoveFromChecks)
C.data.Data = 0; // no lava delay
} else {
DoLavaUniformFlow(lvl, ref C, false);

View File

@ -143,8 +143,8 @@ namespace MCGalaxy {
public static PlayerBot FindMatches(Player pl, string name) {
int matches = 0;
return Utils.FindMatches<PlayerBot>(pl, name, out matches, Bots.Items,
b => true, b => b.name, "bots");
return Matcher.Find<PlayerBot>(pl, name, out matches, Bots.Items,
b => true, b => b.name, "bots");
}
public static PlayerBot FindMatchesPreferLevel(Player pl, string name) {

83
MCGalaxy/CmdMapsBy.cs Normal file
View File

@ -0,0 +1,83 @@
/*
Copyright 2011 MCForge
Dual-licensed under the Educational Community License, Version 2.0 and
the GNU General Public License, Version 3 (the "Licenses"); you may
not use this file except in compliance with the Licenses. You may
obtain a copy of the Licenses at
http://www.opensource.org/licenses/ecl2.php
http://www.gnu.org/licenses/gpl-3.0.html
Unless required by applicable law or agreed to in writing,
software distributed under the Licenses are distributed on an "AS IS"
BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
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.Text;
namespace MCGalaxy.Commands {
public sealed class CmdMapsBy : Command {
public override string name { get { return "mapsby"; } }
public override string shortcut { get { return "madeby"; } }
public override string type { get { return CommandTypes.Information; } }
public override bool museumUsable { get { return true; } }
public override LevelPermission defaultRank { get { return LevelPermission.Guest; } }
public override void Use(Player p, string message) {
if (message == "") { Help(p); return; }
string author = PlayerInfo.FindOfflineNameMatches(p, message);
if (author == null) return;
string[] maps = Directory.GetFiles("levels", "*.lvl");
for (int i = 0; i < maps.Length; i++) {
maps[i] = Path.GetFileNameWithoutExtension(maps[i]);
}
List<string> madeBy = new List<string>();
foreach (string map in maps) {
if (!IsOwnedBy(map, author)) continue;
madeBy.Add(map);
}
author = PlayerInfo.GetColoredName(p, author);
if (madeBy.Count == 0) {
Player.Message(p, "{0} %Shas not made any maps", author);
} else {
Player.Message(p, "{0} %Sauthored these maps: {1}", author, madeBy.Join());
}
}
static bool IsOwnedBy(string map, string name) {
if (map.CaselessStarts(name)) return true;
string file = LevelInfo.FindPropertiesFile(map);
if (file == null) return false;
string realmOwner = null;
PropertiesFile.Read(file, ref realmOwner, ProcessLine);
if (realmOwner == null) return false;
string[] owners = realmOwner.Replace(" ", "").Split(',');
foreach (string owner in owners) {
if (owner.CaselessEq(name)) return true;
}
return false;
}
static void ProcessLine(string key, string value, ref string realmOwner) {
if (key.CaselessEq("realmowner")) {
realmOwner = value;
}
}
public override void Help(Player p) {
Player.Message(p, "%T/mapsby %H[player]");
Player.Message(p, "%HLists all maps authored by the given player.");
}
}
}

View File

@ -47,11 +47,9 @@ namespace MCGalaxy.Commands {
bool cantSend = p.muted || (Server.chatmod && !p.voice);
if (p.IsAfk) {
if (cantSend) {
Player.Message(p, "You are now marked as being AFK.");
Player.Message(p, "You are now marked as being AFK.");
} else {
Chat.MessageWhere("-{0}%S- is AFK {1}",
pl => Entities.CanSee(pl, p) && !pl.listignored.Contains(p.name) && !pl.ignoreAll,
p.ColoredName, message);
MessageOthers(p, "-" + p.ColoredName + "%S- is AFK " + message);
Player.RaisePlayerAction(p, PlayerAction.AFK, message);
p.CheckForMessageSpam();
}
@ -64,15 +62,18 @@ namespace MCGalaxy.Commands {
if (cantSend) {
Player.Message(p, "You are no longer marked as being AFK.");
} else {
Chat.MessageWhere("-{0}%S- is no longer AFK",
pl => Entities.CanSee(pl, p) && !pl.listignored.Contains(p.name) && !pl.ignoreAll,
p.ColoredName);
MessageOthers(p, "-" + p.ColoredName + "%S- is no longer AFK");
Player.RaisePlayerAction(p, PlayerAction.UnAFK, message);
p.CheckForMessageSpam();
}
}
}
static void MessageOthers(Player p, string msg) {
Chat.MessageWhere(msg,
pl => Entities.CanSee(pl, p) && !pl.listignored.Contains(p.name) && !pl.ignoreAll);
}
public override void Help(Player p) {
Player.Message(p, "%T/afk <reason>");
Player.Message(p, "%HMarks yourself as AFK. Use again to mark yourself as back");

View File

@ -31,7 +31,7 @@ namespace MCGalaxy.Commands {
p.SendMessage("You have not teleported anywhere yet");
return;
}
if (p.level.name.ToLower() != p.beforeTeleportMap.ToLower())
if (!p.level.name.CaselessEq(p.beforeTeleportMap))
PlayerActions.ChangeMap(p, p.beforeTeleportMap);
p.SendPos(Entities.SelfID, p.beforeTeleportPos[0], p.beforeTeleportPos[1], p.beforeTeleportPos[2], 0, 0);
}

View File

@ -196,8 +196,8 @@ namespace MCGalaxy {
}
public static string FindMatches(Player p, string name, out int matches) {
Award award = Utils.FindMatches<Award>(p, name, out matches, AwardsList,
a => true, a => a.Name, "awards");
Award award = Matcher.Find<Award>(p, name, out matches, AwardsList,
a => true, a => a.Name, "awards");
return award == null ? null : award.Name;
}

View File

@ -30,31 +30,18 @@ namespace MCGalaxy {
/// Does not perform any unloading. </summary>
public static void Rename(string src, string dst) {
File.Move(LevelInfo.LevelPath(src), LevelInfo.LevelPath(dst));
try {
File.Move(LevelInfo.LevelPath(src) + ".backup", LevelInfo.LevelPath(dst) + ".backup");
} catch {
}
try {
File.Move("levels/level properties/" + src + ".properties",
"levels/level properties/" + dst + ".properties");
} catch {
}
SafeMove(LevelInfo.LevelPath(src) + ".backup",
LevelInfo.LevelPath(dst) + ".backup");
SafeMove("levels/level properties/" + src,
"levels/level properties/" + dst + ".properties");
SafeMove("levels/level properties/" + src + ".properties",
"levels/level properties/" + dst + ".properties");
SafeMove("blockdefs/lvl_" + src + ".json",
"blockdefs/lvl_" + dst + ".json");
SafeMove("blockprops/lvl_" + src + ".txt",
"blockprops/lvl_" + dst + ".txt");
try {
File.Move("levels/level properties/" + src,
"levels/level properties/" + dst + ".properties");
} catch {
}
try {
if (File.Exists("blockdefs/lvl_" + src + ".json")) {
File.Move("blockdefs/lvl_" + src + ".json",
"blockdefs/lvl_" + dst + ".json");
}
} catch {
}
try {
MoveBackups(src, dst);
} catch {
@ -88,6 +75,15 @@ namespace MCGalaxy {
}
}
static void SafeMove(string src, string dst) {
if (!File.Exists(src)) return;
try {
File.Move(src, dst);
} catch (Exception ex) {
Server.ErrorLog(ex);
}
}
static bool DirectoryEmpty(string dir) {
if (!Directory.Exists(dir)) return true;
if (Directory.GetDirectories(dir).Length > 0) return false;
@ -131,13 +127,11 @@ namespace MCGalaxy {
File.Move(LevelInfo.LevelPath(name), "levels/deleted/" + name + ".lvl");
}
try { File.Delete("levels/level properties/" + name + ".properties"); } catch { }
try { File.Delete("levels/level properties/" + name); } catch { }
try {
if (File.Exists("blockdefs/lvl_" + name + ".json"))
File.Delete("blockdefs/lvl_" + name + ".json");
} catch {}
SafeDelete("levels/level properties/" + name);
SafeDelete("levels/level properties/" + name + ".properties");
SafeDelete("blockdefs/lvl_" + name + ".json");
SafeDelete("blockprops/lvl_" + name + ".txt");
BotsFile.DeleteBots(name);
DeleteDatabaseTables(name);
BlockDBFile.DeleteBackingFile(name);
@ -160,6 +154,16 @@ namespace MCGalaxy {
}
}
}
static void SafeDelete(string src) {
if (!File.Exists(src)) return;
try {
File.Delete(src);
} catch (Exception ex) {
Server.ErrorLog(ex);
}
}
public static void Replace(Level old, Level lvl) {
LevelDB.SaveBlockDB(old);
@ -198,15 +202,15 @@ namespace MCGalaxy {
public static void CopyLevel(string src, string dst) {
File.Copy(LevelInfo.LevelPath(src), LevelInfo.LevelPath(dst));
if (File.Exists(LevelInfo.PropertiesPath(src))) {
File.Copy(LevelInfo.PropertiesPath(src),
LevelInfo.PropertiesPath(dst));
}
if (File.Exists("blockdefs/lvl_" + src + ".json")) {
File.Copy("blockdefs/lvl_" + src + ".json",
"blockdefs/lvl_" + dst + ".json");
}
SafeCopy("levels/level properties/" + src,
"levels/level properties/" + dst + ".properties");
SafeCopy("levels/level properties/" + src + ".properties",
"levels/level properties/" + dst + ".properties");
SafeCopy("blockdefs/lvl_" + src + ".json",
"blockdefs/lvl_" + dst + ".json");
SafeCopy("blockprops/lvl_" + src + ".txt",
"blockprops/lvl_" + dst + ".txt");
CopyDatabaseTables(src, dst);
}
@ -234,5 +238,14 @@ namespace MCGalaxy {
}
}
}
static void SafeCopy(string src, string dst) {
if (!File.Exists(src)) return;
try {
File.Copy(src, dst, true);
} catch (Exception ex) {
Server.ErrorLog(ex);
}
}
}
}

View File

@ -45,8 +45,8 @@ namespace MCGalaxy {
}
public static Level FindMatches(Player pl, string name, out int matches) {
return Utils.FindMatches<Level>(pl, name, out matches, LevelInfo.Loaded.Items,
l => true, l => l.name, "loaded levels");
return Matcher.Find<Level>(pl, name, out matches, LevelInfo.Loaded.Items,
l => true, l => l.name, "loaded levels");
}
public static string FindMapMatches(Player pl, string name) {
@ -60,8 +60,8 @@ namespace MCGalaxy {
}
string[] files = Directory.GetFiles("levels", "*.lvl");
string map = Utils.FindMatches<string>(pl, name, out matches, files,
l => true, l => Path.GetFileNameWithoutExtension(l), "levels");
string map = Matcher.Find<string>(pl, name, out matches, files,
l => true, l => Path.GetFileNameWithoutExtension(l), "levels");
if (map != null)
map = Path.GetFileNameWithoutExtension(map);
return map;

View File

@ -115,6 +115,7 @@
<Compile Include="Chat\ChatTokens.cs" />
<Compile Include="Chat\LineWrapper.cs" />
<Compile Include="Chat\ProfanityFilter.cs" />
<Compile Include="CmdMapsBy.cs" />
<Compile Include="Commands\Alias.cs" />
<Compile Include="Commands\Bots\CmdBotAdd.cs" />
<Compile Include="Commands\Bots\CmdBotAI.cs" />
@ -620,12 +621,13 @@
<Compile Include="util\Extensions\TimeExts.cs" />
<Compile Include="util\FastList.cs" />
<Compile Include="util\App.cs" />
<Compile Include="util\Formatter.cs" />
<Compile Include="util\Formatting\Formatter.cs" />
<Compile Include="util\Formatting\Matcher.cs" />
<Compile Include="util\Formatting\MultiPageOutput.cs" />
<Compile Include="util\IO\BufferedBlockSender.cs" />
<Compile Include="util\IO\Paths.cs" />
<Compile Include="util\Math\DirUtils.cs" />
<Compile Include="util\Math\Vectors.cs" />
<Compile Include="util\MultiPageOutput.cs" />
<Compile Include="util\NET_20.cs" />
<Compile Include="util\SparseBitSet.cs" />
<Compile Include="util\Threading\IReaderWriterLock.cs" />
@ -700,6 +702,7 @@
<ItemGroup>
<Folder Include="Commands\Maintenance" />
<Folder Include="Network\Packets" />
<Folder Include="util\Formatting" />
<Folder Include="util\Threading" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />

View File

@ -187,8 +187,8 @@ namespace MCGalaxy {
public static Group FindMatches(Player p, string name, out int matches) {
name = name.ToLower();
MapName(ref name);
return Utils.FindMatches<Group>(p, name, out matches,
GroupList, g => true, g => g.name, "ranks");
return Matcher.Find<Group>(p, name, out matches,
GroupList, g => true, g => g.name, "ranks");
}
/// <summary> Find the group(s) which contain the given name. </summary>

View File

@ -66,8 +66,8 @@ namespace MCGalaxy {
public string FindMatches(Player p, string name, string type, out int matches) {
lock (locker) {
return Utils.FindMatches<string>(p, name, out matches, players,
n => true, n => n, type, 20);
return Matcher.Find<string>(p, name, out matches, players,
n => true, n => n, type, 20);
}
}

View File

@ -63,9 +63,9 @@ namespace MCGalaxy {
Player.Message(pl, "\"{0}\" is not a valid player name.", name); return null;
}
return Utils.FindMatches<Player>(pl, name, out matches, Online.Items,
p => Entities.CanSee(pl, p) || !onlyCanSee,
p => p.name, "online players");
return Matcher.Find<Player>(pl, name, out matches, Online.Items,
p => Entities.CanSee(pl, p) || !onlyCanSee,
p => p.name, "online players");
}
public static string FindMatchesPreferOnline(Player p, string name) {
@ -191,8 +191,8 @@ namespace MCGalaxy {
"WHERE Name LIKE @0 LIMIT 21" + suffix,
"%" + name + "%")) {
int matches = 0;
return Utils.FindMatches<DataRow>(p, name, out matches, results.Rows,
r => true, r => r["Name"].ToString(), "players", 20);
return Matcher.Find<DataRow>(p, name, out matches, results.Rows,
r => true, r => r["Name"].ToString(), "players", 20);
}
}
}

View File

@ -0,0 +1,67 @@
/*
Copyright 2015 MCGalaxy
Dual-licensed under the Educational Community License, Version 2.0 and
the GNU General Public License, Version 3 (the "Licenses"); you may
not use this file except in compliance with the Licenses. You may
obtain a copy of the Licenses at
http://www.opensource.org/licenses/ecl2.php
http://www.gnu.org/licenses/gpl-3.0.html
Unless required by applicable law or agreed to in writing,
software distributed under the Licenses are distributed on an "AS IS"
BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
or implied. See the Licenses for the specific language governing
permissions and limitations under the Licenses.
*/
using System;
using System.Collections;
using System.Text;
namespace MCGalaxy {
public static class Matcher {
const StringComparison comp = StringComparison.OrdinalIgnoreCase;
/// <summary> Finds partial matches of 'name' against the names of the items in the 'items' enumerable. </summary>
/// <param name="pl"> The player to output messages to. </param>
/// <param name="name"> The name to perform partial matching against. </param>
/// <param name="matches"> The number of found/outputted matches. </param>
/// <param name="items"> Enumerable of items that may be matched with. </param>
/// <param name="filter"> Selects which items from 'items' are actually matched. </param>
/// <param name="nameGetter"> Gets the name of a particular item. </param>
/// <param name="type"> The type of the items. (e.g. 'players', 'commands') </param>
/// <param name="limit"> The maximum number of matches that are outputted. </param>
/// <returns> If exactly one match, the matching item. </returns>
public static T Find<T>(Player pl, string name, out int matches, IEnumerable items,
Predicate<T> filter, Func<T, string> nameGetter, string type, int limit = 5) {
T match = default(T); matches = 0;
StringBuilder nameMatches = new StringBuilder();
foreach (T item in items) {
if (!filter(item)) continue;
string itemName = nameGetter(item);
if (itemName.Equals(name, comp)) { matches = 1; return item; }
if (itemName.IndexOf(name, comp) < 0) continue;
match = item; matches++;
if (matches <= limit)
nameMatches.Append(itemName).Append(", ");
else if (matches == limit + 1)
nameMatches.Append("(and more)").Append(", ");
}
if (matches == 0) {
Player.Message(pl, "No " + type + " match \"" + name + "\"."); return default(T);
} else if (matches == 1) {
return match;
} else {
string count = matches > limit ? limit + "+ " : matches + " ";
string names = nameMatches.ToString(0, nameMatches.Length - 2);
Player.Message(pl, count + type + " match \"" + name + "\":");
Player.Message(pl, names); return default(T);
}
}
}
}