Refactory all brushes into Brush code and BrushFactory code.

This commit is contained in:
UnknownShadow200 2016-08-04 12:32:01 +10:00
parent b3ae2052d1
commit 3c3e16c1e3
23 changed files with 518 additions and 463 deletions

View File

@ -36,38 +36,26 @@ namespace MCGalaxy.Commands.Building {
Player.Message(p, "Your current brush is: " + p.BrushName); return;
}
string[] args = message.SplitSpaces(2);
string brush = FindBrush(args[0]);
BrushFactory brush = BrushFactory.Find(args[0]);
if (args[0].CaselessEq("list")) {
Player.Message(p, "%HAvailable brushes: %S" + AvailableBrushes);
Player.Message(p, "%HAvailable brushes: %S" + BrushFactory.Available);
} else if (brush == null) {
Player.Message(p, "No brush found with name \"" + args[0] + "\".");
Player.Message(p, "Available brushes: " + AvailableBrushes);
Player.Message(p, "No brush found with name \"{0}\".", args[0]);
Player.Message(p, "Available brushes: " + BrushFactory.Available);
} else {
Player.Message(p, "Set your brush to: " + brush);
p.BrushName = brush;
Player.Message(p, "Set your brush to: " + brush.Name);
p.BrushName = brush.Name;
p.DefaultBrushArgs = args.Length > 1 ? args[1] : "";
}
}
internal static string FindBrush(string message) {
foreach (var brush in BrushFactory.Brushes) {
if (brush.Key.CaselessEq(message))
return brush.Key;
}
return null;
}
internal static string AvailableBrushes {
get { return BrushFactory.Brushes.Keys.Join(); }
}
public override void Help(Player p) {
Player.Message(p, "%T/brush [name] <default brush args>");
Player.Message(p, "%HSets your current brush to the brush with that name.");
Player.Message(p, "%T/help brush [name]");
Player.Message(p, "%HOutputs the help for the brush with that name.");
Player.Message(p, "%HAvailable brushes: %S" + AvailableBrushes);
Player.Message(p, "%HAvailable brushes: %S" + BrushFactory.Available);
Player.Message(p, "%H- The default brush takes one argument specifying the block to draw with. " +
"If no arguments are given, draws with your currently held block.");
Player.Message(p, "%H- If \"skip\" is used for a block name, " +
@ -75,12 +63,12 @@ namespace MCGalaxy.Commands.Building {
}
public override void Help(Player p, string message) {
string brush = FindBrush(message);
BrushFactory brush = BrushFactory.Find(message);
if (brush == null) {
Player.Message(p, "No brush found with name \"{0}\".", message);
Player.Message(p, "%HAvailable brushes: %S" + AvailableBrushes);
Player.Message(p, "%HAvailable brushes: %S" + BrushFactory.Available);
} else {
Player.MessageLines(p, BrushFactory.BrushesHelp[brush]);
Player.MessageLines(p, brush.Help);
}
}
}

View File

@ -34,12 +34,12 @@ namespace MCGalaxy.Commands.Building {
DrawArgs cpos = (DrawArgs)state;
cpos.block = type; cpos.extBlock = extType;
DrawOp op = null;
Func<BrushArgs, Brush> constructor = null;
BrushFactory factory = null;
switch (cpos.mode) {
case DrawMode.solid:
op = new CuboidDrawOp();
constructor = SolidBrush.Process; break;
factory = BrushFactory.Find("normal"); break;
case DrawMode.normal:
op = new CuboidDrawOp(); break;
case DrawMode.hollow:
@ -48,16 +48,16 @@ namespace MCGalaxy.Commands.Building {
op = new CuboidWallsDrawOp(); break;
case DrawMode.holes:
op = new CuboidDrawOp();
constructor = CheckeredBrush.Process; break;
factory = BrushFactory.Find("checkered"); break;
case DrawMode.wire:
op = new CuboidWireframeDrawOp(); break;
case DrawMode.random:
op = new CuboidDrawOp();
constructor = RandomBrush.Process; break;
factory = BrushFactory.Find("random"); break;
}
int brushOffset = cpos.mode == DrawMode.normal ? 0 : 1;
Brush brush = GetBrush(p, cpos, brushOffset, constructor);
Brush brush = GetBrush(p, cpos, brushOffset, factory);
if (brush == null) return false;
return DrawOp.DoDrawOp(op, brush, p, marks);
}

View File

@ -57,10 +57,10 @@ namespace MCGalaxy.Commands.Building {
string[] args = message.Split(' ');
if (args[0].CaselessEq("not")) {
op.Exclude = ReplaceBrush.GetBlocks(p, 1, args.Length, args);
op.Exclude = ReplaceBrushFactory.GetBlocks(p, 1, args.Length, args);
if (op.Exclude == null) return false;
} else {
op.Include = ReplaceBrush.GetBlocks(p, 0, args.Length, args);
op.Include = ReplaceBrushFactory.GetBlocks(p, 0, args.Length, args);
if (op.Include == null) return false;
}
return DrawOp.DoDrawOp(op, null, p, m);

View File

@ -48,16 +48,16 @@ namespace MCGalaxy.Commands.Building {
int block = DrawCmd.GetBlock(p, parts[0], out extBlock);
if (block == -1) return false;
string brushName = CmdBrush.FindBrush(parts[1]);
if (brushName == null) {
Player.Message(p, "No brush found with name \"" + parts[1] + "\".");
Player.Message(p, "Available brushes: " + CmdBrush.AvailableBrushes);
BrushFactory factory = BrushFactory.Find(parts[1]);
if (factory == null) {
Player.Message(p, "No brush found with name \"{0}\".", parts[1]);
Player.Message(p, "Available brushes: " + BrushFactory.Available);
return false;
}
string brushMessage = parts.Length > 2 ? parts[2].ToLower() : "";
BrushArgs args = new BrushArgs(p, brushMessage, type, extType);
Brush brush = BrushFactory.Brushes[brushName](args);
Brush brush = factory.Construct(args);
if (brush == null) return false;
DrawOp drawOp = null;

View File

@ -42,11 +42,11 @@ namespace MCGalaxy.Commands.Building {
cpos.block = type; cpos.extBlock = extType;
DrawOp op = null;
Func<BrushArgs, Brush> constructor = null;
BrushFactory factory = null;
switch (cpos.mode) {
case DrawMode.solid:
op = new AdvSphereDrawOp();
constructor = SolidBrush.Process; break;
factory = BrushFactory.Find("normal"); break;
case DrawMode.hollow:
op = new AdvHollowSphereDrawOp(); break;
case DrawMode.circle:
@ -55,7 +55,7 @@ namespace MCGalaxy.Commands.Building {
op = new AdvSphereDrawOp(); break;
}
int brushOffset = cpos.mode == DrawMode.normal ? 0 : 1;
Brush brush = GetBrush(p, cpos, brushOffset, constructor);
Brush brush = GetBrush(p, cpos, brushOffset, factory);
if (brush == null) return false;
Vec3S32 p0 = m[0];

View File

@ -70,16 +70,16 @@ namespace MCGalaxy.Commands.Building {
static Brush ParseBrush(string raw, Player p, byte block, byte extBlock) {
string[] parts = raw.SplitSpaces(2);
string brushName = CmdBrush.FindBrush(parts[0]);
if (brushName == null) {
BrushFactory brush = BrushFactory.Find(parts[0]);
if (brush == null) {
Player.Message(p, "No brush found with name \"{0}\".", parts[0]);
Player.Message(p, "Available brushes: " + CmdBrush.AvailableBrushes);
Player.Message(p, "Available brushes: " + BrushFactory.Available);
return null;
}
string brushArgs = parts.Length >= 2 ? parts[1].ToLower() : "";
BrushArgs args = new BrushArgs(p, brushArgs, block, extBlock);
return BrushFactory.Brushes[brushName](args);
return brush.Construct(args);
}
struct DrawArgs { public int mode; public string brushMsg; }

View File

@ -73,7 +73,7 @@ namespace MCGalaxy.Commands.Building {
}
protected static Brush GetBrush(Player p, DrawArgs dArgs,
int usedFromEnd, Func<BrushArgs, Brush> constructor = null) {
int usedFromEnd, BrushFactory factory = null) {
int end = dArgs.message.Length;
string brushMsg = "";
for (int i = 0; i < usedFromEnd; i++) {
@ -83,9 +83,9 @@ namespace MCGalaxy.Commands.Building {
if (end >= 0) brushMsg = dArgs.message.Substring(0, end);
if (brushMsg == "") brushMsg = p.DefaultBrushArgs;
if (constructor == null) constructor = BrushFactory.Brushes[p.BrushName];
if (factory == null) factory = BrushFactory.Find(p.BrushName);
BrushArgs args = new BrushArgs(p, brushMsg, dArgs.block, dArgs.extBlock);
return constructor(args);
return factory.Construct(args);
}
protected struct DrawArgs {

View File

@ -35,7 +35,8 @@ namespace MCGalaxy.Commands.Building {
bool DoReplace(Player p, Vec3S32[] marks, object state, byte type, byte extType) {
BrushArgs args = new BrushArgs(p, (string)state, type, extType);
Brush brush = ReplaceNot ? ReplaceNotBrush.Process(args) : ReplaceBrush.Process(args);
string name = ReplaceNot ? "replacenot" : "replace";
Brush brush = BrushFactory.Find(name).Construct(args);
if (brush == null) return false;
DrawOp drawOp = new CuboidDrawOp();
@ -76,7 +77,7 @@ namespace MCGalaxy.Commands.Building {
ushort z2 = (ushort)(p.level.Length - 1);
BrushArgs args = new BrushArgs(p, message.ToLower(), 0, 0);
Brush brush = ReplaceBrush.Process(args);
Brush brush = BrushFactory.Find("replace").Construct(args);
if (brush == null) return;
DrawOp drawOp = new CuboidDrawOp();

View File

@ -31,24 +31,24 @@ namespace MCGalaxy.Drawing.Brushes {
/// <summary> Creates a brush from the given arguments,
/// returning null if invalid arguments are specified. </summary>
public abstract Brush Process(BrushArgs args);
public abstract Brush Construct(BrushArgs args);
public static Dictionary<string, Func<BrushArgs, Brush>> Brushes
= new Dictionary<string, Func<BrushArgs, Brush>> {
{ "normal", SolidBrush.Process }, { "paste", PasteBrush.Process },
{ "checkered", CheckeredBrush.Process }, { "rainbow", RainbowBrush.Process },
{ "bwrainbow", BWRainbowBrush.Process }, { "striped", StripedBrush.Process },
{ "replace", ReplaceBrush.Process }, { "replacenot", ReplaceNotBrush.Process },
{ "random", RandomBrush.Process }, { "cloudy", CloudyBrush.Process },
public static List<BrushFactory> Brushes = new List<BrushFactory>() {
new SolidBrushFactory(), new CheckeredBrushFactory(),
new StripedBrushFactory(), new PasteBrushFactory(),
new ReplaceBrushFactory(), new ReplaceNotBrushFactory(),
new RainbowBrushFactory(), new BWRainbowBrushFactory(),
new RandomBrushFactory(), new CloudyBrushFactory(),
};
public static Dictionary<string, string[]> BrushesHelp = new Dictionary<string, string[]> {
{ "normal", SolidBrush.HelpString }, { "paste", PasteBrush.HelpString },
{ "checkered", CheckeredBrush.HelpString }, { "rainbow", RainbowBrush.HelpString },
{ "bwrainbow", BWRainbowBrush.HelpString }, { "striped", StripedBrush.HelpString },
{ "replace", ReplaceBrush.HelpString }, { "replacenot", ReplaceNotBrush.HelpString },
{ "random", RandomBrush.HelpString }, { "cloudy", CloudyBrush.HelpString },
};
public static string Available { get { return Brushes.Join(b => b.Name); } }
public static BrushFactory Find(string name) {
foreach (BrushFactory brush in Brushes) {
if (brush.Name.CaselessEq(name)) return brush;
}
return null;
}
}
public struct BrushArgs {

View File

@ -0,0 +1,93 @@
/*
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;
namespace MCGalaxy.Drawing.Brushes {
public sealed class CloudyBrushFactory : BrushFactory {
public override string Name { get { return "Cloudy"; } }
public override string[] Help { get { return HelpString; } }
public static string[] HelpString = new [] {
"%TArguments: [block1/frequency] [block2] <args>..",
"%HDraws by selecting blocks from the given [blocks] using perlin noise.",
"%Hfrequency is optional (defaults to 1), and specifies the number of times " +
"the block should appear (as a fraction of the total of all the frequencies).",
"%HOptional args format: %T<first letter of argument>_<value>",
"%HArguments: %Ta%Hmplitude, %Tf%Hrequency (scale), %Ts%Heed, " +
"%To%Hctaves, %Tp%Hersistence (turbulence), %Tl%Hacunarity",
};
public override Brush Construct(BrushArgs args) {
NoiseArgs n = default(NoiseArgs);
// Constants borrowed from fCraft to match it
n.Amplitude = 1;
n.Frequency = 0.08f;
n.Octaves = 3;
n.Seed = int.MinValue;
n.Persistence = 0.75f;
n.Lacunarity = 2;
int[] count;
ExtBlock[] toAffect = FrequencyBrush.GetBlocks(args, out count,
Filter, arg => Handler(arg, args.Player, ref n));
if (toAffect == null) return null;
return new CloudyBrush(toAffect, count, n);
}
// Only want to handle non block options.
static bool Filter(string arg) {
return arg.Length < 2 || arg[1] != '_';
}
static bool Handler(string arg, Player p, ref NoiseArgs args) {
char opt = arg[0];
arg = arg.Substring(arg.IndexOf('_') + 1);
if (opt == 'l') {
if (float.TryParse(arg, out args.Lacunarity)) return true;
Player.Message(p, "\"{0}\" was not a valid decimal.", arg);
} else if (opt == 'a') {
if (float.TryParse(arg, out args.Amplitude)) return true;
Player.Message(p, "\"{0}\" was not a valid decimal.", arg);
} else if (opt == 'f') {
if (float.TryParse(arg, out args.Frequency)) return true;
Player.Message(p, "\"{0}\" was not a valid decimal.", arg);
} else if (opt == 'p') {
if (float.TryParse(arg, out args.Persistence)) return true;
Player.Message(p, "\"{0}\" was not a valid decimal.", arg);
} else if (opt == 'o') {
if (byte.TryParse(arg, out args.Octaves)
&& args.Octaves > 0 && args.Octaves <= 16) return true;
Player.Message(p, "\"{0}\" was not an integer between 1 and 16.", arg);
} else if (opt == 's') {
if (int.TryParse(arg, out args.Seed)) return true;
Player.Message(p, "\"{0}\" was not a valid integer.", arg);
} else {
Player.Message(p, "\"{0}\" was not a valid argument name.", opt);
}
return false;
}
}
public struct NoiseArgs {
public byte Octaves;
public int Seed;
public float Frequency, Amplitude, Persistence, Lacunarity;
}
}

View File

@ -1,96 +1,117 @@
/*
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 MCGalaxy.Commands.Building;
namespace MCGalaxy.Drawing.Brushes {
/// <summary> Contains helper methods for brushes that have blocks with
/// optional frequency counts (e.g. random and cloudy brushes) </summary>
public static class FrequencyBrush {
public static ExtBlock[] GetBlocks(BrushArgs args, out int[] count,
Predicate<string> filter, Predicate<string> handler) {
string[] parts = args.Message.Split(' ');
Player p = args.Player;
ExtBlock[] blocks;
GetRaw(parts, filter, args, out blocks, out count);
for (int i = 0, j = 0; i < parts.Length; i++ ) {
if (parts[i] == "") continue;
// Brush specific args
if (!filter(parts[i])) {
if (!handler(parts[i])) return null;
continue;
}
byte extType = 0;
int sepIndex = parts[i].IndexOf('/');
string block = sepIndex >= 0 ? parts[i].Substring(0, sepIndex) : parts[i];
int type = DrawCmd.GetBlock(p, block, out extType);
if (type == -1) return null;
blocks[j].Block = (byte)type; blocks[j].Ext = extType;
if (sepIndex < 0) { j++; continue; }
int chance;
if (!int.TryParse(parts[i].Substring(sepIndex + 1), out chance)
|| chance <= 0 || chance > 10000) {
Player.Message(p, "frequency must be an integer between 1 and 10,000."); return null;
}
count[j] = chance;
j++;
}
return blocks;
}
static void GetRaw(string[] parts, Predicate<string> filter, BrushArgs args,
out ExtBlock[] blocks, out int[] count) {;
int bCount = 0;
for (int i = 0; i < parts.Length; i++) {
if (parts[i] == "" || !filter(parts[i])) continue;
bCount++;
}
// For 0 or 1 blocks given, treat second block as 'unchanged'.
blocks = new ExtBlock[Math.Max(2, bCount)];
count = new int[blocks.Length];
for (int i = 0; i < count.Length; i++) {
count[i] = 1;
blocks[i] = new ExtBlock(Block.Zero, 0);
}
// No blocks given, assume first is held block
if (bCount == 0)
blocks[0] = new ExtBlock(args.Block, args.ExtBlock);
}
public static ExtBlock[] Combine(ExtBlock[] toAffect, int[] count) {
int sum = 0;
for (int i = 0; i < count.Length; i++) sum += count[i];
ExtBlock[] blocks = new ExtBlock[sum];
for (int i = 0, index = 0; i < toAffect.Length; i++) {
for (int j = 0; j < count[i]; j++)
blocks[index++] = toAffect[i];
}
return blocks;
}
}
}
/*
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 MCGalaxy.Commands.Building;
namespace MCGalaxy.Drawing.Brushes {
/// <summary> Contains helper methods for brushes that have blocks with
/// optional frequency counts (e.g. random and cloudy brushes) </summary>
public static class FrequencyBrush {
public static ExtBlock[] GetBlocks(BrushArgs args, out int[] count,
Predicate<string> filter, Predicate<string> handler) {
string[] parts = args.Message.Split(' ');
Player p = args.Player;
ExtBlock[] blocks;
GetRaw(parts, filter, args, out blocks, out count);
for (int i = 0, j = 0; i < parts.Length; i++ ) {
if (parts[i] == "") continue;
// Brush specific args
if (!filter(parts[i])) {
if (!handler(parts[i])) return null;
continue;
}
byte extType = 0;
int sepIndex = parts[i].IndexOf('/');
string block = sepIndex >= 0 ? parts[i].Substring(0, sepIndex) : parts[i];
int type = DrawCmd.GetBlock(p, block, out extType);
if (type == -1) return null;
blocks[j].Block = (byte)type; blocks[j].Ext = extType;
if (sepIndex < 0) { j++; continue; }
int chance;
if (!int.TryParse(parts[i].Substring(sepIndex + 1), out chance)
|| chance <= 0 || chance > 10000) {
Player.Message(p, "frequency must be an integer between 1 and 10,000."); return null;
}
count[j] = chance;
j++;
}
return blocks;
}
static void GetRaw(string[] parts, Predicate<string> filter, BrushArgs args,
out ExtBlock[] blocks, out int[] count) {;
int bCount = 0;
for (int i = 0; i < parts.Length; i++) {
if (parts[i] == "" || !filter(parts[i])) continue;
bCount++;
}
// For 0 or 1 blocks given, treat second block as 'unchanged'.
blocks = new ExtBlock[Math.Max(2, bCount)];
count = new int[blocks.Length];
for (int i = 0; i < count.Length; i++) {
count[i] = 1;
blocks[i] = new ExtBlock(Block.Zero, 0);
}
// No blocks given, assume first is held block
if (bCount == 0)
blocks[0] = new ExtBlock(args.Block, args.ExtBlock);
}
public static ExtBlock[] Combine(ExtBlock[] toAffect, int[] count) {
int sum = 0;
for (int i = 0; i < count.Length; i++) sum += count[i];
ExtBlock[] blocks = new ExtBlock[sum];
for (int i = 0, index = 0; i < toAffect.Length; i++) {
for (int j = 0; j < count[i]; j++)
blocks[index++] = toAffect[i];
}
return blocks;
}
}
public sealed class RandomBrushFactory : BrushFactory {
public override string Name { get { return "Random"; } }
public override string[] Help { get { return HelpString; } }
public static string[] HelpString = new [] {
"%TArguments: [block1/frequency] [block2]..",
"%HDraws by randomly selecting blocks from the given [blocks].",
"%Hfrequency is optional (defaults to 1), and specifies the number of times " +
"the block should appear (as a fraction of the total of all the frequencies).",
};
public override Brush Construct(BrushArgs args) {
int[] count;
ExtBlock[] toAffect = FrequencyBrush.GetBlocks(args, out count, P => true, null);
if (toAffect == null) return null;
ExtBlock[] blocks = FrequencyBrush.Combine(toAffect, count);
return new RandomBrush(blocks);
}
}
}

View File

@ -0,0 +1,90 @@
/*
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 MCGalaxy.Commands.Building;
namespace MCGalaxy.Drawing.Brushes {
public sealed class ReplaceBrushFactory : BrushFactory {
public override string Name { get { return "Replace"; } }
public override string[] Help { get { return HelpString; } }
public static string[] HelpString = new [] {
"%TArguments: [block1] [block2].. [new]",
"%HDraws by replacing existing blocks that are in the given [blocks] with [new]",
"%H If only [block] is given, replaces with your held block.",
};
public override Brush Construct(BrushArgs args) { return ProcessReplace(args, false); }
internal static Brush ProcessReplace(BrushArgs args, bool not) {
string[] parts = args.Message.Split(' ');
if (args.Message == "") {
args.Player.SendMessage("You need at least one block to replace."); return null;
}
int count = parts.Length == 1 ? 1 : parts.Length - 1;
ExtBlock[] toAffect = GetBlocks(args.Player, 0, count, parts);
if (toAffect == null) return null;
ExtBlock target;
if (!GetTargetBlock(args, parts, out target)) return null;
if (not) return new ReplaceNotBrush(toAffect, target);
return new ReplaceBrush(toAffect, target);
}
internal static ExtBlock[] GetBlocks(Player p, int start, int max, string[] parts) {
ExtBlock[] blocks = new ExtBlock[max - start];
for (int i = 0; i < blocks.Length; i++)
blocks[i].Block = Block.Zero;
for (int i = 0; start < max; start++, i++ ) {
byte extBlock = 0;
int block = DrawCmd.GetBlock(p, parts[start], out extBlock);
if (block == -1) return null;
blocks[i].Block = (byte)block; blocks[i].Ext = extBlock;
}
return blocks;
}
static bool GetTargetBlock(BrushArgs args, string[] parts, out ExtBlock target) {
if (parts.Length == 1) {
target = new ExtBlock(args.Block, args.ExtBlock);
return true;
}
target = default(ExtBlock);
int block = DrawCmd.GetBlock(args.Player, parts[parts.Length - 1], out target.Ext);
if (block == -1) return false;
target.Block = (byte)block;
return true;
}
}
public sealed class ReplaceNotBrushFactory : BrushFactory {
public override string Name { get { return "ReplaceNot"; } }
public override string[] Help { get { return HelpString; } }
public static string[] HelpString = new [] {
"%TArguments: [block1] [block2].. [new]",
"%HDraws by replacing existing blocks that not are in the given [blocks] with [new]",
"%H If only [block] is given, replaces with your held block.",
};
public override Brush Construct(BrushArgs args) { return ReplaceBrushFactory.ProcessReplace(args, true); }
}
}

View File

@ -0,0 +1,147 @@
/*
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 MCGalaxy.Commands.Building;
namespace MCGalaxy.Drawing.Brushes {
public sealed class SolidBrushFactory : BrushFactory {
public override string Name { get { return "Normal"; } }
public override string[] Help { get { return HelpString; } }
public static string[] HelpString = new [] {
"%TArguments: [block]",
"%HDraws using the specified block.",
"%H If block is not given, the currently held block is used.",
};
public override Brush Construct(BrushArgs args) {
if (args.Message == "")
return new SolidBrush(args.Block, args.ExtBlock);
byte extBlock;
int block = DrawCmd.GetBlock(args.Player, args.Message, out extBlock);
if (block == -1) return null;
return new SolidBrush((byte)block, extBlock);
}
}
public sealed class CheckeredBrushFactory : BrushFactory {
public override string Name { get { return "Checkered"; } }
public override string[] Help { get { return HelpString; } }
public static string[] HelpString = new [] {
"%TArguments: [block1] [block2]",
"%HDraws an alternating pattern of block1 and block2.",
"%H If block2 is not given, air is used.",
"%H If block1 is not given, the currently held block is used.",
};
public override Brush Construct(BrushArgs args) {
if (args.Message == "")
return new CheckeredBrush(args.Block, args.ExtBlock, 0, 0);
string[] parts = args.Message.Split(' ');
byte extBlock1;
int block1 = DrawCmd.GetBlock(args.Player, parts[0], out extBlock1);
if (block1 == -1) return null;
if (parts.Length == 1)
return new CheckeredBrush((byte)block1, extBlock1, Block.Zero, 0);
byte extBlock2;
int block2 = DrawCmd.GetBlock(args.Player, parts[1], out extBlock2);
if (block2 == -1) return null;
return new CheckeredBrush((byte)block1, extBlock1, (byte)block2, extBlock2);
}
}
public sealed class PasteBrushFactory : BrushFactory {
public override string Name { get { return "Paste"; } }
public override string[] Help { get { return HelpString; } }
public static string[] HelpString = new [] {
"%TArguments: none",
"%HDraws using blocks from the current copy state.",
};
public override Brush Construct(BrushArgs args) {
if (args.Player.CopyBuffer == null) {
args.Player.SendMessage("You haven't copied anything yet.");
return null;
}
return new PasteBrush(args.Player.CopyBuffer);
}
}
public sealed class StripedBrushFactory : BrushFactory {
public override string Name { get { return "Striped"; } }
public override string[] Help { get { return HelpString; } }
public static string[] HelpString = new [] {
"%TArguments: [block1] [block2]",
"%HDraws a diagonally-alternating pattern of block1 and block2.",
"%H If block2 is not given, air is used.",
"%H If block1 is not given, the currently held block is used.",
};
public override Brush Construct(BrushArgs args) {
if (args.Message == "")
return new StripedBrush(args.Block, args.ExtBlock, 0, 0);
string[] parts = args.Message.Split(' ');
byte extBlock1;
int block1 = DrawCmd.GetBlock(args.Player, parts[0], out extBlock1);
if (block1 == -1) return null;
if (parts.Length == 1)
return new StripedBrush((byte)block1, extBlock1, 0, 0);
byte extBlock2;
int block2 = DrawCmd.GetBlock(args.Player, parts[1], out extBlock2);
if (block2 == -1) return null;
return new StripedBrush((byte)block1, extBlock1, (byte)block2, extBlock2);
}
}
public sealed class RainbowBrushFactory : BrushFactory {
public override string Name { get { return "Rainbow"; } }
public override string[] Help { get { return HelpString; } }
public static string[] HelpString = new [] {
"%TArguments: <random>",
"%HIf no arguments are given, draws a diagonally repeating rainbow",
"%HIf \'random\' is given, draws by randomly selecting blocks from the rainbow pattern.",
};
public override Brush Construct(BrushArgs args) {
if (args.Message == "random") return new RandomRainbowBrush();
if (args.Message == "bw") return new BWRainbowBrush();
return new RainbowBrush();
}
}
public sealed class BWRainbowBrushFactory : BrushFactory {
public override string Name { get { return "BWRainbow"; } }
public override string[] Help { get { return HelpString; } }
public static string[] HelpString = new [] {
"%TArguments: none",
"%HDraws a diagonally repeating black-white rainbow",
};
public override Brush Construct(BrushArgs args) { return new BWRainbowBrush(); }
}
}

View File

@ -24,9 +24,6 @@ namespace MCGalaxy.Drawing.Brushes {
/// <summary> Human friendly name of this brush. </summary>
public abstract string Name { get; }
/// <summary> Description of the brush, in addition to its syntax. </summary>
public abstract string[] Help { get; }
/// <summary> Performs calcuations (if necessary) for the given drawop. </summary>
public virtual void Configure(DrawOp op, Player p) { }

View File

@ -20,8 +20,7 @@ using System.Collections.Generic;
using MCGalaxy.Commands.Building;
using MCGalaxy.Drawing.Ops;
namespace MCGalaxy.Drawing.Brushes {
namespace MCGalaxy.Drawing.Brushes {
public sealed class CheckeredBrush : Brush {
readonly byte block1, extBlock1, block2, extBlock2;
@ -32,32 +31,6 @@ namespace MCGalaxy.Drawing.Brushes {
public override string Name { get { return "Checkered"; } }
public override string[] Help { get { return HelpString; } }
public static string[] HelpString = new [] {
"%TArguments: [block1] [block2]",
"%HDraws an alternating pattern of block1 and block2.",
"%H If block2 is not given, air is used.",
"%H If block1 is not given, the currently held block is used.",
};
public static Brush Process(BrushArgs args) {
if (args.Message == "")
return new CheckeredBrush(args.Block, args.ExtBlock, 0, 0);
string[] parts = args.Message.Split(' ');
byte extBlock1;
int block1 = DrawCmd.GetBlock(args.Player, parts[0], out extBlock1);
if (block1 == -1) return null;
if (parts.Length == 1)
return new CheckeredBrush((byte)block1, extBlock1, Block.Zero, 0);
byte extBlock2;
int block2 = DrawCmd.GetBlock(args.Player, parts[1], out extBlock2);
if (block2 == -1) return null;
return new CheckeredBrush((byte)block1, extBlock1, (byte)block2, extBlock2);
}
public override byte NextBlock(DrawOp op) {
return ((op.Coords.X + op.Coords.Y + op.Coords.Z) & 1) == 0 ? block1 : block2;
}

View File

@ -45,70 +45,6 @@ namespace MCGalaxy.Drawing.Brushes {
public override string Name { get { return "Cloudy"; } }
public override string[] Help { get { return HelpString; } }
public static string[] HelpString = new [] {
"%TArguments: [block1/frequency] [block2] <args>..",
"%HDraws by selecting blocks from the given [blocks] using perlin noise.",
"%Hfrequency is optional (defaults to 1), and specifies the number of times " +
"the block should appear (as a fraction of the total of all the frequencies).",
"%HOptional args format: %T<first letter of argument>_<value>",
"%HArguments: %Ta%Hmplitude, %Tf%Hrequency (scale), %Ts%Heed, " +
"%To%Hctaves, %Tp%Hersistence (turbulence), %Tl%Hacunarity",
};
public static Brush Process(BrushArgs args) {
NoiseArgs n = default(NoiseArgs);
// Constants borrowed from fCraft to match it
n.Amplitude = 1;
n.Frequency = 0.08f;
n.Octaves = 3;
n.Seed = int.MinValue;
n.Persistence = 0.75f;
n.Lacunarity = 2;
int[] count;
ExtBlock[] toAffect = FrequencyBrush.GetBlocks(args, out count,
Filter, arg => Handler(arg, args.Player, ref n));
if (toAffect == null) return null;
return new CloudyBrush(toAffect, count, n);
}
// Only want to handle non block options.
static bool Filter(string arg) {
return arg.Length < 2 || arg[1] != '_';
}
static bool Handler(string arg, Player p, ref NoiseArgs args) {
char opt = arg[0];
arg = arg.Substring(arg.IndexOf('_') + 1);
if (opt == 'l') {
if (float.TryParse(arg, out args.Lacunarity)) return true;
Player.Message(p, "\"{0}\" was not a valid decimal.", arg);
} else if (opt == 'a') {
if (float.TryParse(arg, out args.Amplitude)) return true;
Player.Message(p, "\"{0}\" was not a valid decimal.", arg);
} else if (opt == 'f') {
if (float.TryParse(arg, out args.Frequency)) return true;
Player.Message(p, "\"{0}\" was not a valid decimal.", arg);
} else if (opt == 'p') {
if (float.TryParse(arg, out args.Persistence)) return true;
Player.Message(p, "\"{0}\" was not a valid decimal.", arg);
} else if (opt == 'o') {
if (byte.TryParse(arg, out args.Octaves)
&& args.Octaves > 0 && args.Octaves <= 16) return true;
Player.Message(p, "\"{0}\" was not an integer between 1 and 16.", arg);
} else if (opt == 's') {
if (int.TryParse(arg, out args.Seed)) return true;
Player.Message(p, "\"{0}\" was not a valid integer.", arg);
} else {
Player.Message(p, "\"{0}\" was not a valid argument name.", opt);
}
return false;
}
public unsafe override void Configure(DrawOp op, Player p) {
Player.Message(p, "Calculating noise distribution...");
// Initalise our noise histogram
@ -176,14 +112,6 @@ namespace MCGalaxy.Drawing.Brushes {
return blocks[next].Block;
}
public override byte NextExtBlock(DrawOp op) {
return blocks[next].Ext;
}
}
public struct NoiseArgs {
public byte Octaves;
public int Seed;
public float Frequency, Amplitude, Persistence, Lacunarity;
public override byte NextExtBlock(DrawOp op) { return blocks[next].Ext; }
}
}

View File

@ -20,32 +20,14 @@ using System.Collections.Generic;
using MCGalaxy.Commands;
using MCGalaxy.Drawing.Ops;
namespace MCGalaxy.Drawing.Brushes {
namespace MCGalaxy.Drawing.Brushes {
public sealed class PasteBrush : Brush {
readonly CopyState state;
public PasteBrush(CopyState state) {
this.state = state;
}
public PasteBrush(CopyState state) { this.state = state; }
public override string Name { get { return "Paste"; } }
public override string[] Help { get { return HelpString; } }
public static string[] HelpString = new [] {
"%TArguments: none",
"%HDraws using blocks from the current copy state.",
};
public static Brush Process(BrushArgs args) {
if (args.Player.CopyBuffer == null) {
args.Player.SendMessage("You haven't copied anything yet.");
return null;
}
return new PasteBrush(args.Player.CopyBuffer);
}
public override byte NextBlock(DrawOp op) {
Vec3U16 p = LocalCoords(op);
return state.Blocks[state.GetIndex(p.X, p.Y, p.Z)];

View File

@ -26,14 +26,6 @@ namespace MCGalaxy.Drawing.Brushes {
public override string Name { get { return "Rainbow"; } }
public override string[] Help { get { return HelpString; } }
public static string[] HelpString = new [] {
"%TArguments: <random>",
"%HIf no arguments are given, draws a diagonally repeating rainbow",
"%HIf \'random\' is given, draws by randomly selecting blocks from the rainbow pattern.",
};
public override byte NextBlock(DrawOp op) {
int offset = (op.Coords.X + op.Coords.Y + op.Coords.Z) % 13;
if (offset < 0) offset += 13;
@ -41,14 +33,6 @@ namespace MCGalaxy.Drawing.Brushes {
}
public override byte NextExtBlock(DrawOp op) { return 0; }
public static Brush Process(BrushArgs args) {
if (args.Message == "random")
return new RandomRainbowBrush();
if (args.Message == "bw")
return new BWRainbowBrush();
return new RainbowBrush();
}
}
public sealed class BWRainbowBrush : Brush {
@ -63,18 +47,7 @@ namespace MCGalaxy.Drawing.Brushes {
return blocks[offset];
}
public override string[] Help { get { return HelpString; } }
public static string[] HelpString = new [] {
"%TArguments: none",
"%HDraws a diagonally repeating black-white rainbow",
};
public override byte NextExtBlock(DrawOp op) { return 0; }
public static Brush Process(BrushArgs args) {
return new BWRainbowBrush();
}
}
internal sealed class RandomRainbowBrush : Brush {
@ -82,15 +55,9 @@ namespace MCGalaxy.Drawing.Brushes {
public override string Name { get { return "RandomRainbow"; } }
public override string[] Help { get { return new string[0]; } }
public RandomRainbowBrush() { rnd = new Random(); }
public RandomRainbowBrush() {
rnd = new Random();
}
public RandomRainbowBrush(int seed) {
rnd = new Random(seed);
}
public RandomRainbowBrush(int seed) { rnd = new Random(seed); }
public override byte NextBlock(DrawOp op) {
return (byte)rnd.Next(Block.red, Block.darkgrey);

View File

@ -33,24 +33,6 @@ namespace MCGalaxy.Drawing.Brushes {
public override string Name { get { return "Random"; } }
public override string[] Help { get { return HelpString; } }
public static string[] HelpString = new [] {
"%TArguments: [block1/frequency] [block2]..",
"%HDraws by randomly selecting blocks from the given [blocks].",
"%Hfrequency is optional (defaults to 1), and specifies the number of times " +
"the block should appear (as a fraction of the total of all the frequencies).",
};
public static Brush Process(BrushArgs args) {
int[] count;
ExtBlock[] toAffect = FrequencyBrush.GetBlocks(args, out count, P => true, null);
if (toAffect == null) return null;
ExtBlock[] blocks = FrequencyBrush.Combine(toAffect, count);
return new RandomBrush(blocks);
}
int next;
const int mask = 0x7fffffff;
public override byte NextBlock(DrawOp op) {

View File

@ -20,8 +20,7 @@ using System.Collections.Generic;
using MCGalaxy.Commands.Building;
using MCGalaxy.Drawing.Ops;
namespace MCGalaxy.Drawing.Brushes {
namespace MCGalaxy.Drawing.Brushes {
public sealed class ReplaceBrush : Brush {
readonly ExtBlock[] include;
readonly ExtBlock target;
@ -32,61 +31,6 @@ namespace MCGalaxy.Drawing.Brushes {
public override string Name { get { return "Replace"; } }
public override string[] Help { get { return HelpString; } }
public static string[] HelpString = new [] {
"%TArguments: [block1] [block2].. [new]",
"%HDraws by replacing existing blocks that are in the given [blocks] with [new]",
"%H If only [block] is given, replaces with your held block.",
};
public static Brush Process(BrushArgs args) {
return ProcessReplace(args, false);
}
internal static Brush ProcessReplace(BrushArgs args, bool not) {
string[] parts = args.Message.Split(' ');
if (args.Message == "") {
args.Player.SendMessage("You need at least one block to replace."); return null;
}
int count = parts.Length == 1 ? 1 : parts.Length - 1;
ExtBlock[] toAffect = GetBlocks(args.Player, 0, count, parts);
if (toAffect == null) return null;
ExtBlock target;
if (!GetTargetBlock(args, parts, out target)) return null;
if (not) return new ReplaceNotBrush(toAffect, target);
return new ReplaceBrush(toAffect, target);
}
internal static ExtBlock[] GetBlocks(Player p, int start, int max, string[] parts) {
ExtBlock[] blocks = new ExtBlock[max - start];
for (int i = 0; i < blocks.Length; i++)
blocks[i].Block = Block.Zero;
for (int i = 0; start < max; start++, i++ ) {
byte extBlock = 0;
int block = DrawCmd.GetBlock(p, parts[start], out extBlock);
if (block == -1) return null;
blocks[i].Block = (byte)block; blocks[i].Ext = extBlock;
}
return blocks;
}
static bool GetTargetBlock(BrushArgs args, string[] parts, out ExtBlock target) {
if (parts.Length == 1) {
target = new ExtBlock(args.Block, args.ExtBlock);
return true;
}
target = default(ExtBlock);
int block = DrawCmd.GetBlock(args.Player, parts[parts.Length - 1], out target.Ext);
if (block == -1) return false;
target.Block = (byte)block;
return true;
}
public override byte NextBlock(DrawOp op) {
ushort x = op.Coords.X, y = op.Coords.Y, z = op.Coords.Z;
byte tile = op.Level.GetTile(x, y, z), extTile = 0;
@ -100,9 +44,7 @@ namespace MCGalaxy.Drawing.Brushes {
return Block.Zero;
}
public override byte NextExtBlock(DrawOp op) {
return target.Ext;
}
public override byte NextExtBlock(DrawOp op) { return target.Ext; }
}
public sealed class ReplaceNotBrush : Brush {
@ -115,18 +57,6 @@ namespace MCGalaxy.Drawing.Brushes {
public override string Name { get { return "ReplaceNot"; } }
public override string[] Help { get { return HelpString; } }
public static string[] HelpString = new [] {
"%TArguments: [block1] [block2].. [new]",
"%HDraws by replacing existing blocks that not are in the given [blocks] with [new]",
"%H If only [block] is given, replaces with your held block.",
};
public static Brush Process(BrushArgs args) {
return ReplaceBrush.ProcessReplace(args, true);
}
public override byte NextBlock(DrawOp op) {
ushort x = op.Coords.X, y = op.Coords.Y, z = op.Coords.Z;
byte tile = op.Level.GetTile(x, y, z), extTile = 0;
@ -140,8 +70,6 @@ namespace MCGalaxy.Drawing.Brushes {
return target.Block;
}
public override byte NextExtBlock(DrawOp op) {
return target.Ext;
}
public override byte NextExtBlock(DrawOp op) { return target.Ext; }
}
}

View File

@ -19,37 +19,19 @@ using System;
using MCGalaxy.Commands.Building;
using MCGalaxy.Drawing.Ops;
namespace MCGalaxy.Drawing.Brushes {
namespace MCGalaxy.Drawing.Brushes {
public sealed class SolidBrush : Brush {
readonly byte type, extType;
readonly byte block, extBlock;
public SolidBrush(byte type, byte extType) {
this.type = type;
this.extType = extType;
this.block = type;
this.extBlock = extType;
}
public override string Name { get { return "Normal"; } }
public override string[] Help { get { return HelpString; } }
public override byte NextBlock(DrawOp op) { return block; }
public static string[] HelpString = new [] {
"%TArguments: [block]",
"%HDraws using the specified block.",
"%H If block is not given, the currently held block is used.",
};
public static Brush Process(BrushArgs args) {
if (args.Message == "")
return new SolidBrush(args.Block, args.ExtBlock);
byte extBlock;
int block = DrawCmd.GetBlock(args.Player, args.Message, out extBlock);
if (block == -1) return null;
return new SolidBrush((byte)block, extBlock);
}
public override byte NextBlock(DrawOp op) { return type; }
public override byte NextExtBlock(DrawOp op) { return extType; }
public override byte NextExtBlock(DrawOp op) { return extBlock; }
}
}

View File

@ -20,8 +20,7 @@ using System.Collections.Generic;
using MCGalaxy.Commands.Building;
using MCGalaxy.Drawing.Ops;
namespace MCGalaxy.Drawing.Brushes {
namespace MCGalaxy.Drawing.Brushes {
public sealed class StripedBrush : Brush {
readonly byte block1, extBlock1, block2, extBlock2;
@ -32,32 +31,6 @@ namespace MCGalaxy.Drawing.Brushes {
public override string Name { get { return "Striped"; } }
public override string[] Help { get { return HelpString; } }
public static string[] HelpString = new [] {
"%TArguments: [block1] [block2]",
"%HDraws a diagonally-alternating pattern of block1 and block2.",
"%H If block2 is not given, air is used.",
"%H If block1 is not given, the currently held block is used.",
};
public static Brush Process(BrushArgs args) {
if (args.Message == "")
return new StripedBrush(args.Block, args.ExtBlock, 0, 0);
string[] parts = args.Message.Split(' ');
byte extBlock1;
int block1 = DrawCmd.GetBlock(args.Player, parts[0], out extBlock1);
if (block1 == -1) return null;
if (parts.Length == 1)
return new StripedBrush((byte)block1, extBlock1, 0, 0);
byte extBlock2;
int block2 = DrawCmd.GetBlock(args.Player, parts[1], out extBlock2);
if (block2 == -1) return null;
return new StripedBrush((byte)block1, extBlock1, (byte)block2, extBlock2);
}
public override byte NextBlock(DrawOp op) {
return ((op.Coords.X + op.Coords.Y + op.Coords.Z) & 3) <= 1 ? block1 : block2;
}

View File

@ -415,7 +415,6 @@
<Compile Include="Database\SQLite\SQLiteParameterisedQuery.cs" />
<Compile Include="Drawing\Brushes\Brush.cs" />
<Compile Include="Drawing\Brushes\CheckeredBrush.cs" />
<Compile Include="Drawing\Brushes\FrequencyBrush.cs" />
<Compile Include="Drawing\Brushes\CloudyBrush.cs" />
<Compile Include="Drawing\Brushes\PasteBrush.cs" />
<Compile Include="Drawing\Brushes\RainbowBrush.cs" />
@ -424,6 +423,10 @@
<Compile Include="Drawing\Brushes\SolidBrush.cs" />
<Compile Include="Drawing\Brushes\StripedBrush.cs" />
<Compile Include="Drawing\BrushFactories\BrushFactory.cs" />
<Compile Include="Drawing\BrushFactories\CloudyBrush.cs" />
<Compile Include="Drawing\BrushFactories\FrequencyBrushes.cs" />
<Compile Include="Drawing\BrushFactories\ReplaceBrushes.cs" />
<Compile Include="Drawing\BrushFactories\SimpleBrushes.cs" />
<Compile Include="Drawing\CopyState.cs" />
<Compile Include="Drawing\DrawOps\AdvConeDrawOps.cs" />
<Compile Include="Drawing\DrawOps\AdvDrawOps.cs" />