public ByteOperation(string Param) { const string PREFIXES = "+-&|^"; Mode = ByteMode.Overwrite; Bytes = null; LastError = null; if (!string.IsNullOrWhiteSpace(Param)) { if (PREFIXES.Contains(Param[0])) { switch (Param[0]) { case '+': Mode = ByteMode.Add; break; case '-': Mode = ByteMode.Subtract; break; case '&': Mode = ByteMode.AND; break; case '|': Mode = ByteMode.OR; break; case '^': Mode = ByteMode.XOR; break; default: LastError = new ArgumentException("Invalid Prefix"); break; } Bytes = GetBytes(Param.Substring(1)); } else { Bytes = GetBytes(Param); } } }
public static string GetPrefix() { return(PREFIXES.RandomElement()); }
private static void OnMessage(object ws, Message m) { //handle PlayerExit before data.Parse; we want to get the player object before it gets removed switch (m.Type) { case MessageType.PlayerExit: { con.ChatRespond(data.Players[m.GetInt(0)].Username, "goodbye!"); break; } } data.Parse(m);//parse messages //we can now do whatever switch (m.Type) { case MessageType.Init: con.Chat("connected!"); pingTimer.Change(0, 5000); //start measuring ping break; case MessageType.PlayerJoin: { string username = m.GetString(1); con.ChatRespond(username, "hello!"); foreach (var item in globalEffects) { //give player effects, if any con.GiveEffect(username, item.Key, item.Value); } break; } case MessageType.Chat: { const string PREFIXES = ".,!"; //chat prefixes, we can access the string like an array later var id = m.GetInt(0); var player = data.Players[id]; var username = player.Username; string message = m.GetString(1); string[] args = message.Split(' '); //message split into array of words char prefix; //this will keep the prefix used if (PREFIXES.Contains(args[0][0])) //if first character of first word of message is a prefix { prefix = args[0][0]; //note prefix used args[0] = args[0].Substring(1); //remove first character } else { break; //not a command so break } switch (args[0]) { //handle commands case "help": con.ChatRespond(username, $"available commands: gibedit, count <id/blockname>, edges [id/blockname]. prefixes are {PREFIXES}"); break; case "gibedit": con.GiveEdit(username); break; case "count": { //count blocks in world if (args.Length < 2) { break; //break if argument is not specified } if (!TryGetBlockIdFromString(args[1], out int result)) { con.ChatRespond(username, "invalid block id!"); break; } int count = 0; foreach (var block in data.Blocks) //for every block in blocks, { if (block.Id == result) { count++; //if id is what we are looking for, increment count } } con.ChatRespond(username, $"There are {count} blocks of id {result}."); //also note if you count empty blocks it will count double as it counts both foreground and background layer } break; case "fill": { //fill entire level with a block if (args.Length < 2) { break; } if (!TryGetBlockIdFromString(args[1], out int result)) { con.ChatRespond(username, "invalid block id!"); break; } var layer = ((BlockId)result).IsBackground() ? 0 : 1; //place bgs on bg layer, fgs on fg layer FillWorld(result, layer); break; } case "edges": { //fill world borders with id int result; if (args.Length < 2) { //if argument not specified, use air result = 0; } else { //try to parse id from string if (!TryGetBlockIdFromString(args[1], out result)) { con.ChatRespond(username, "invalid block id!"); break; } } //fill edges with id var layer = ((BlockId)result).IsBackground() ? 0 : 1; var width = data.Width; var height = data.Height; for (int i = 0; i < width; i++) { //top and bottom if (data.Blocks[layer, i, 0].Id != result) { con.PlaceBlock(layer, i, 0, result); } if (data.Blocks[layer, i, height - 1].Id != result) { con.PlaceBlock(layer, i, height - 1, result); } } for (int i = 1; i < height - 1; i++) { //left and right if (data.Blocks[layer, 0, i].Id != result) { con.PlaceBlock(layer, 0, i, result); } if (data.Blocks[layer, width - 1, i].Id != result) { con.PlaceBlock(layer, width - 1, i, result); } } break; } default: con.ChatRespond(username, "unknown command. type .help for help."); break; } break; } case MessageType.PlaceBlock: { //snakebot int l = m.GetInt(1), x = m.GetInt(2), y = m.GetInt(3), id = m.GetInt(4); int msdelay = 0; //we can change the delay depending on the block used //animate blocks int tid = -1; const int metaldelay = 600; switch ((BlockId)id) { //metal snake case BlockId.MetalGold: tid = (int)BlockId.MetalBronze; msdelay = metaldelay; break; case BlockId.MetalBronze: tid = (int)BlockId.MetalCopper; msdelay = metaldelay; break; case BlockId.MetalCopper: tid = (int)BlockId.Empty; msdelay = metaldelay; break; } const int tilesdelay = 50; if (tid == -1) { //tiles snake if (id >= (int)BlockId.TilesWhite && id <= (int)BlockId.TilesBlue) { msdelay = tilesdelay; tid = id + 1; } //check for range to avoid too much code repeat else if (id == (int)BlockId.TilesPurple) { msdelay = tilesdelay; tid = 0; } } if (tid == -1) { break; //the block is not what we're looking for; break } msdelay -= ping; //subtract our ping if (msdelay < 0) { msdelay = 0; //if time ends up being in negatives then set to 0 } Task.Delay(msdelay).ContinueWith((_) => //delay a bit and continue asynchronously to not block the thread { //compare id with latest id at that location, if they are different then break, it will be queued by the new block //that way if you place a block again at that location the snake won't break unless it happens to be after it tries to place it if (id != data.Blocks[l, x, y].Id) { return; //gotta use return inside lambda now } con.PlaceBlock(l, x, y, tid); //place new block after time has passed }); break; } case MessageType.Effect: { //global effects var pid = m.GetInt(0); var eid = m.GetInt(1); var ecfg = m.GetInt(2) + 1; //eeu is buggy if (eid == (int)EffectType.MultiJump && ecfg == 0) { ecfg = 999 + 1; //you can't give infinite jumps from a command so this is the closest we can get } //since we receive the message again after we give effect we need to search for it to not enter a loop when someone spams effects if (pid == data.BotId) { break; //break if id is our bot } if (globalEffectsIgnore.TryGetValue(pid, out var list)) { bool breakoff = false; //need this to break from nested scope foreach (var tup in list) { if (eid == tup.eid && ecfg == tup.ecfg) { list.Remove(tup); //remove the effect from list breakoff = true; //set flag to break later break; //break from foreach } } if (breakoff) { break; //break from switch } } if (eid == 0) { globalEffects.Clear(); //if clearing effects, clear the dictionary } else { globalEffects[eid] = ecfg; //else store effect in dict } Console.WriteLine($"{pid} {eid} {ecfg}"); foreach (var player in data.Players.Values) { //give everyone else the effect if (player.Id == pid) { continue; //skip player that originally got the effect } if (!globalEffectsIgnore.ContainsKey(pid)) { globalEffectsIgnore.Add(pid, new List <(int eid, int ecfg)>()); //init list if it's not there } globalEffectsIgnore[pid].Add((eid, ecfg)); //add effect to be ignored later if (eid == 0) { con.ClearEffects(player.Username); //effect id 0 means clear all } else { con.GiveEffect(player.Username, eid, ecfg); //give effect } } break; } case MessageType.PlayerMove: { //stalkbot var id = m.GetInt(0); if (id == data.BotId) { break; //break if id is bot } if (data.Players[id].Username != data.OwnerUsername) { break; //break if not world owner, in other worlds, only stalk world owner (you) } //skip playerid and take 30 elements that form playermove, turn to array var msg = m.Data.Skip(1).Take(30).ToArray(); con.SendL(MessageType.PlayerMove, msg); //send it //this is not taking god mode into account which can lead to interesting effects (flying without visible godmode and falling upon hitting a block) break; } } //switch } //onmessage