using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using BlockLibrary;
using BlockLibrary.Parser;
using PlayerIOClient;
namespace BlockLibrary
{
public static class BL
{
public static bool BuiltNet4 = false;
public static BL.Block[, ,] World = new BL.Block[2, 1, 1];
public static Connection con;
public static bool ValidBLMessage(Message e)
{
switch (e.Type)
{
case "b":
case "bc":
case "br":
case "bs":
case "lb":
case "pt":
case "ts":
case "wp":
return true;
}
return false;
}
public class Block
{
#region Data
public BlockParam BlockParameters;
public Type BlockType;
public int x;
public int y;
public int layer;
public int id;
public int placedby;
#endregion
#region Functions
public void Place()
{
if (this.BlockType.Normal)
con.Send("b", this.layer, this.x, this.y, this.id);
if (this.BlockType.Morphable)
con.Send("b", this.layer, this.x, this.y, this.id, this.BlockParameters.MorphableP.MorphValue);
if (this.BlockType.NumberBlock)
con.Send("b", this.layer, this.x, this.y, this.id, this.BlockParameters.NumberBlockP.NumberValue);
if (this.BlockType.SignBlock)
con.Send("b", this.layer, this.x, this.y, this.id, this.BlockParameters.SignP.SignText, this.BlockParameters.SignP.SignType);
if (this.BlockType.SoundBlock)
con.Send("b", this.layer, this.x, this.y, this.id, this.BlockParameters.SoundP.SoundNumber);
if (this.BlockType.Label)
con.Send("b", this.layer, this.x, this.y, this.id, this.BlockParameters.LabelP.LabelText, this.BlockParameters.LabelP.LabelColor);
if (this.BlockType.WorldPortal)
con.Send("b", this.layer, this.x, this.y, this.id, this.BlockParameters.WorldPortalP.Target);
if (this.BlockType.Portal)
con.Send("b", this.layer, this.x, this.y, this.id, this.BlockParameters.PortalP.PortalRotation, this.BlockParameters.PortalP.PortalID, this.BlockParameters.PortalP.PortalTarget);
}
#endregion
#region Constructors
/// <summary>
/// Create a blank block, with nothing on it.
/// </summary>
public Block()
{
PortalParams a = new PortalParams();
LabelParams b = new LabelParams();
NumberBlockParams c = new NumberBlockParams();
MorphableParams d = new MorphableParams();
SoundBlockParams e = new SoundBlockParams();
SignBlockParams f = new SignBlockParams();
WorldPortalParams g = new WorldPortalParams();
a.PortalID = -1;
a.PortalRotation = -1;
a.PortalTarget = -1;
b.LabelText = "";
b.LabelColor = "";
c.NumberValue = -1;
d.MorphValue = -1;
e.SoundNumber = -1;
f.SignType = -1;
f.SignText = "";
g.Target = "";
BlockParam RetNull = new BlockParam();
RetNull.PortalP = a;
RetNull.LabelP = b;
RetNull.NumberBlockP = c;
RetNull.MorphableP = d;
RetNull.SoundP = e;
RetNull.SignP = f;
RetNull.WorldPortalP = g;
Type bType = new Type();
bType.Label = false;
bType.Morphable = false;
bType.Normal = false;
bType.NumberBlock = false;
bType.Portal = false;
bType.SignBlock = false;
bType.SoundBlock = false;
bType.WorldPortal = false;
this.id = 0;
this.layer = 0;
this.x = 0;
this.y = 0;
this.BlockParameters = RetNull;
this.BlockType = bType;
this.placedby = -1;
}
/// <summary>
/// "Deserializes", or, "Interpets" a block message given by the server into a block.
/// </summary>
/// <param name="m">The PlayerIOClient message</param>
public Block(Message m)
{
if (ValidBLMessage(m))
{
Block br = new Block();
br.id = 0;
br.layer = 0;
br.placedby = 0;
br.x = 0;
br.y = 0;
switch (m.Type)
{
case "b":
br.layer = Convert.ToInt32(m[0]);
br.x = Convert.ToInt32(m[1]);
br.y = Convert.ToInt32(m[2]);
br.id = Convert.ToInt32(m[3]);
br.placedby = Convert.ToInt32(m[4]);
br.BlockType.Normal = true;
break;
case "bc":
br.layer = 0;
br.x = Convert.ToInt32(m[0]);
br.y = Convert.ToInt32(m[1]);
br.id = Convert.ToInt32(m[2]);
br.BlockParameters.NumberBlockP.NumberValue = Convert.ToInt32(m[3]);
br.placedby = Convert.ToInt32(m[4]);
br.BlockType.NumberBlock = true;
break;
case "br":
br.layer = Convert.ToInt32(m[3]);
br.x = Convert.ToInt32(m[0]);
br.y = Convert.ToInt32(m[1]);
br.BlockParameters.MorphableP.MorphValue = Convert.ToInt32(m[2]);
br.placedby = Convert.ToInt32(m[4]);
br.BlockType.Morphable = true;
break;
case "bs":
br.x = Convert.ToInt32(m[0]);
br.y = Convert.ToInt32(m[1]);
br.id = Convert.ToInt32(m[2]);
br.BlockParameters.SoundP.SoundNumber = Convert.ToInt32(m[3]);
br.placedby = Convert.ToInt32(m[4]);
br.BlockType.SoundBlock = true;
break;
case "lb":
br.x = Convert.ToInt32(m[0]);
br.y = Convert.ToInt32(m[1]);
br.id = Convert.ToInt32(m[2]);
br.BlockParameters.LabelP.LabelText = m[3].ToString();
br.BlockParameters.LabelP.LabelColor = m[4].ToString();
br.placedby = Convert.ToInt32(m[5]);
br.BlockType.Label = true;
break;
case "pt":
br.x = Convert.ToInt32(m[0]);
br.y = Convert.ToInt32(m[1]);
br.id = Convert.ToInt32(m[2]);
br.BlockParameters.PortalP.PortalID = Convert.ToInt32(m[4]);
br.BlockParameters.PortalP.PortalRotation = Convert.ToInt32(m[3]);
br.BlockParameters.PortalP.PortalTarget = Convert.ToInt32(m[5]);
br.placedby = Convert.ToInt32(m[6]);
br.BlockType.Portal = true;
break;
case "ts":
br.x = Convert.ToInt32(m[0]);
br.y = Convert.ToInt32(m[1]);
br.id = Convert.ToInt32(m[2]);
br.BlockParameters.SignP.SignText = m[3].ToString();
br.BlockParameters.SignP.SignType = Convert.ToInt32(m[4]);
br.placedby = Convert.ToInt32(m[5]);
br.BlockType.SignBlock = true;
break;
case "wp":
br.x = Convert.ToInt32(m[0]);
br.y = Convert.ToInt32(m[1]);
br.id = Convert.ToInt32(m[2]);
br.BlockParameters.WorldPortalP.Target = m[3].ToString();
br.placedby = Convert.ToInt32(m[4]);
br.BlockType.WorldPortal = true;
break;
}
this.x = br.x;
this.y = br.y;
this.id = br.y;
this.placedby = br.placedby;
this.BlockParameters = br.BlockParameters;
this.BlockType = br.BlockType;
}
}
/// <summary>
/// Make a block how you would send a block, without "b".
/// E.X: Block(0, 1, 1, 9) - Creats a block, layer 0, at 1, 1, with ID 9.
/// </summary>
/// <param name="blockdata">How you would send it without "b"</param>
public Block(params object[] blockdata)
{ object[] p = blockdata;
if (p.Length < 4)
throw new Exception("Not enough parameters to create a block");
Block ret = new Block();
BlockParam blockparam = new BlockParam();
Type blocktype = new Type();
ret.layer = (int)p[0];
ret.x = (int)p[1];
ret.y = (int)p[2];
ret.id = (int)p[3];
ret.placedby = -1;
if (p.Length < 5)
blocktype.Normal = true;
else
{
object[] param = new object[3];
if (p.Length > 5)
if (p.Length > 6)
param = new object[] { p[4], p[5], p[6] };
else
param = new object[] { p[4], p[5] };
else
param = new object[] { p[4] };
if(param[0] is string)
{
if(param.Length == 1)
{
blockparam.WorldPortalP.Target = (string)param[0];
blocktype.WorldPortal = true;
} else if(param.Length == 2)
{
if(param[1] is string)
{
blockparam.LabelP.LabelText = (string)param[0];
blockparam.LabelP.LabelColor = (string)param[1];
}
else
{
blockparam.SignP.SignText = (string)param[0];
blockparam.SignP.SignType = (int)param[1];
blocktype.SignBlock = true;
}
}
}
else if (param[0] is int)
{
if (param.Length == 1)
{
if((int)p[3] == 77 || (int)p[3] == 83)
{
blockparam.SoundP.SoundNumber = (int)param[0];
blocktype.SoundBlock = true;
}
else
{
blockparam.NumberBlockP.NumberValue = (int)param[0];
blocktype.NumberBlock = true;
}
}
else if (param.Length == 3)
{
blockparam.PortalP.PortalID = (int)param[1];
blockparam.PortalP.PortalTarget = (int)param[2];
blockparam.PortalP.PortalRotation = (int)param[3];
blocktype.Portal = true;
}
}
}
ret.BlockParameters = blockparam;
ret.BlockType = blocktype;
this.layer = ret.layer;
this.x = ret.x;
this.y = ret.y;
this.id = ret.id;
this.placedby = ret.placedby;
this.BlockParameters = ret.BlockParameters;
this.BlockType = ret.BlockType;
}
#endregion
}
#region StuffForBlock
public struct Type
{
public bool Portal;
public bool Normal;
public bool Label;
public bool NumberBlock;
public bool Morphable;
public bool SoundBlock;
public bool SignBlock;
public bool WorldPortal;
/// <summary>
/// Create a blank type with nothing on it.
/// </summary>
public Type(bool a = false)
{
this.Label = false;
this.Morphable = false;
this.Normal = false;
this.NumberBlock = false;
this.Portal = false;
this.SignBlock = false;
this.SoundBlock = false;
this.WorldPortal = false;
}
}
public struct PortalParams
{
public int PortalRotation;
public int PortalID;
public int PortalTarget;
}
public struct LabelParams
{
public string LabelText;
public string LabelColor;
}
public struct NumberBlockParams
{
public int NumberValue;
}
public struct MorphableParams
{
public int MorphValue;
}
public struct SoundBlockParams
{
public int SoundNumber;
}
public struct SignBlockParams
{
public string SignText;
public int SignType;
}
public struct WorldPortalParams
{
public string Target;
}
public struct BlockParam
{
public PortalParams PortalP;
public LabelParams LabelP;
public NumberBlockParams NumberBlockP;
public MorphableParams MorphableP;
public SoundBlockParams SoundP;
public SignBlockParams SignP;
public WorldPortalParams WorldPortalP;
/// <summary>
/// Create a blank block param with nothing on it.
/// </summary>
public BlockParam(bool a222 = false)
{
PortalParams a = new PortalParams();
LabelParams b = new LabelParams();
NumberBlockParams c = new NumberBlockParams();
MorphableParams d = new MorphableParams();
SoundBlockParams e = new SoundBlockParams();
SignBlockParams f = new SignBlockParams();
WorldPortalParams g = new WorldPortalParams();
a.PortalID = -1;
a.PortalRotation = -1;
a.PortalTarget = -1;
b.LabelText = "";
b.LabelColor = "";
c.NumberValue = -1;
d.MorphValue = -1;
e.SoundNumber = -1;
f.SignType = -1;
f.SignText = "";
g.Target = "";
this.PortalP = a;
this.LabelP = b;
this.NumberBlockP = c;
this.MorphableP = d;
this.SoundP = e;
this.SignP = f;
this.WorldPortalP = g;
}
}
#endregion
}
}
namespace BlockLibrary.Parser
{
public static class PlayerIOClient
{
private static int worldWidth;
private static int worldHeight;
/// <summary>
/// Just put this in in your message handler and you'll be good to use this.
/// </summary>
/// <param name="e">The message</param>
public static void HandleMessage(Message e)
{
switch (e.Type)
{
case "init":
worldWidth = e.GetInt(18);
worldHeight = e.GetInt(19);
BL.World = new BL.Block[2, worldWidth, worldHeight];
var chunks = InitParse.Parse(e);
foreach (var chunk in chunks)
foreach (var pos in chunk.Locations)
BL.World[chunk.Layer, pos.X, pos.Y] = new BL.Block(chunk.Layer, pos.X, pos.Y, chunk.Type, chunk.Args);
break;
case "reset":
BL.World = new BL.Block[2, worldWidth, worldHeight];
var chunks2 = InitParse.Parse(e);
foreach (var chunk in chunks2)
foreach (var pos in chunk.Locations)
BL.World[chunk.Layer, pos.X, pos.Y] = new BL.Block(chunk.Layer, pos.X, pos.Y, chunk.Type, chunk.Args);
break;
case "clear":
BL.World = new BL.Block[2, worldWidth, worldHeight];
for (int x = 0; x <= worldWidth; x++)
for (int y = 0; y <= worldHeight; y++)
if (y == 0 || y == worldHeight || x == 0 || x == worldWidth)
BL.World[0, x, y] = new BL.Block(0, x, y, Convert.ToInt32(e[2]));
else
BL.World[0, x, y] = new BL.Block(0, x, y, Convert.ToInt32(e[3]));
break;
}
if(BL.ValidBLMessage(e))
{
BL.Block fromMessage = new BL.Block(e);
BL.World[fromMessage.layer, fromMessage.x, fromMessage.y] = fromMessage;
}
}
}
public static class InitParse
{
public static DataChunk[] Parse(Message m)
{
if (m == null) throw new ArgumentNullException("m");
if (m.Type != "init" && m.Type != "reset") throw new ArgumentException("Invalid message type.", "m");
// Get world data
var p = 0u;
var data = new Stack<object>();
while (m[p++] as string != "ws") { }
while (m[p] as string != "we") { data.Push(m[p++]); }
// Parse world data
var chunks = new List<DataChunk>();
while (data.Count > 0)
{
var args = new Stack<object>();
while (!(data.Peek() is byte[]))
args.Push(data.Pop());
var ys = (byte[])data.Pop();
var xs = (byte[])data.Pop();
var layer = (int)data.Pop();
var type = (uint)data.Pop();
chunks.Add(new DataChunk(layer, type, xs, ys, args.ToArray()));
}
return chunks.ToArray();
}
}
public class DataChunk
{
public int Layer { get; set; }
public uint Type { get; set; }
public Point[] Locations { get; set; }
public object[] Args { get; set; }
public DataChunk(int layer, uint type, byte[] xs, byte[] ys, object[] args)
{
this.Layer = layer;
this.Type = type;
this.Args = args;
this.Locations = GetLocations(xs, ys);
}
private static Point[] GetLocations(byte[] xs, byte[] ys)
{
var points = new List<Point>();
for (var i = 0; i < xs.Length; i += 2)
points.Add(new Point(
(xs[i] << 8) | xs[i + 1],
(ys[i] << 8) | ys[i + 1]));
return points.ToArray();
}
}
public struct Point
{
public int X { get; set; }
public int Y { get; set; }
public Point(int x, int y) : this()
{
this.X = x;
this.Y = y;
}
}
}