private void HandleMessage(int start, int len) { if (statusTotal > 0) { statusCount++; if (statusCount == statusTotal) statusTotal = 0; else Dispatcher.Invoke(DispatcherPriority.Normal, new Action(delegate() { serverText.Text = ((int)((float)statusCount * 100.0 / (float)statusTotal)) + "% - " + status; })); } int messageid = messages[start++]; len--; int payload = start; switch (messageid) { case 0x01: // connect request - c2s only break; case 0x02: //error { string error = Encoding.ASCII.GetString(messages, payload, len); Dispatcher.Invoke(DispatcherPriority.Normal, new Action(delegate() { MessageBox.Show(error); })); socket.Close(); busy = false; } break; case 0x03: //connection approved { if (loginLevel == 1) loginLevel = 2; playerSlot = messages[payload]; SendMessage(4); SendMessage(0x10); SendMessage(0x2a); //send buffs //send inventory //send dyes SendMessage(6); if (loginLevel == 2) loginLevel = 3; } break; case 0x04: //player appearance //ignore other players break; case 0x05: //inventory items //ignore player inventory break; case 0x06: //request world info - c2s only break; case 0x07: //world info { gameTime = BitConverter.ToInt32(messages, payload); payload += 4; dayNight = messages[payload++] == 1; moonPhase = messages[payload++]; bloodMoon = messages[payload++] == 1; payload++; //eclipse tilesWide = BitConverter.ToInt32(messages, payload); payload += 4; tilesHigh = BitConverter.ToInt32(messages, payload); payload += 4; spawnX = BitConverter.ToInt32(messages, payload); payload += 4; spawnY = BitConverter.ToInt32(messages, payload); payload += 4; groundLevel = BitConverter.ToInt32(messages, payload); payload += 4; rockLevel = BitConverter.ToInt32(messages, payload); payload += 4; worldID = BitConverter.ToInt32(messages, payload); payload += 4; payload++; //moon type for (int i = 0; i < 3; i++) { treeX[i] = BitConverter.ToInt32(messages, payload); payload += 4; } for (int i = 0; i < 4; i++) treeStyle[i] = messages[payload++]; for (int i = 0; i < 3; i++) { caveBackX[i] = BitConverter.ToInt32(messages, payload); payload += 4; } for (int i = 0; i < 4; i++) caveBackStyle[i] = messages[payload++]; for (int i = 0; i < 8; i++) styles[i] = messages[payload++]; iceBackStyle = messages[payload++]; jungleBackStyle = messages[payload++]; hellBackStyle = messages[payload++]; payload += 4; //wind speed payload++; //number of clouds byte flags = messages[payload++]; byte flags2 = messages[payload++]; payload += 4; //max rain string title = Encoding.ASCII.GetString(messages, payload, start + len - payload); Dispatcher.Invoke(DispatcherPriority.Normal, new Action(delegate() { Title = title; })); smashedOrb = (flags & 1) == 1; killedBoss1 = (flags & 2) == 2; killedBoss2 = (flags & 4) == 4; killedBoss3 = (flags & 8) == 8; hardMode = (flags & 16) == 16; killedClown = (flags & 32) == 32; killedPlantBoss = (flags & 128) == 128; killedMechBoss1 = (flags2 & 1) == 1; killedMechBoss2 = (flags2 & 2) == 2; killedMechBoss3 = (flags2 & 4) == 4; killedMechBossAny = (flags2 & 8) == 8; crimson = (flags2 & 32) == 32; meteorSpawned = false; killedFrost = false; killedGoblins = false; killedPirates = false; killedQueenBee = false; savedMechanic = false; savedTinkerer = false; savedWizard = false; goblinsDelay = 0; altarsSmashed = 0; ResizeMap(); if (loginLevel == 3) { sectionsWide = (tilesWide / 200); sectionsHigh = (tilesHigh / 150); sentSections = new bool[sectionsWide, sectionsHigh]; loginLevel = 4; for (int y = 0; y < tilesHigh; y++) //set all tiles to blank for (int x = 0; x < tilesWide; x++) { tiles[x, y].isActive = false; tiles[x, y].wall = 0; tiles[x, y].liquid = 0; tiles[x, y].hasRedWire = false; tiles[x, y].hasGreenWire = false; tiles[x, y].hasBlueWire = false; tiles[x, y].half = false; tiles[x, y].actuator = false; tiles[x, y].inactive = false; tiles[x, y].color = 0; tiles[x, y].wallColor = 0; } SendMessage(8); //request initial tile data } chests.Clear(); signs.Clear(); npcs.Clear(); loadPlayerMap(); } break; case 0x08: //request initial tile data - c2s only break; case 0x09: //status text { statusTotal = BitConverter.ToInt32(messages, payload); payload += 4; statusCount = 0; status = Encoding.ASCII.GetString(messages, payload, start + len - payload); Dispatcher.Invoke(DispatcherPriority.Normal, new Action(delegate() { serverText.Text = status; })); } break; case 0x0a: //tile row data { int width = BitConverter.ToInt16(messages, payload); payload += 2; int startx = BitConverter.ToInt32(messages, payload); payload += 4; int y = BitConverter.ToInt32(messages, payload); payload += 4; for (int x = startx; x < startx + width; x++) { Tile tile = tiles[x, y]; byte flags = messages[payload++]; byte flags2 = messages[payload++]; tile.isActive = (flags & 1) == 1; tile.hasRedWire = (flags & 16) == 16; tile.half = (flags & 32) == 32; tile.actuator = (flags & 64) == 64; tile.inactive = (flags & 128) == 128; tile.hasGreenWire = (flags2 & 1) == 1; tile.hasBlueWire = (flags2 & 2) == 2; tile.slope = (byte)((flags2 & 0x30) >> 4); if ((flags2 & 4) == 4) tile.color = messages[payload++]; else tile.color = 0; if ((flags2 & 8) == 8) tile.wallColor = messages[payload++]; else tile.wallColor = 0; if (tile.isActive) { tile.type = messages[payload++]; if (tileInfos[tile.type].hasExtra) { tile.u = BitConverter.ToInt16(messages, payload); payload += 2; tile.v = BitConverter.ToInt16(messages, payload); payload += 2; } else { tile.u = -1; tile.v = -1; } } if ((flags & 4) == 4) { tile.wall = messages[payload++]; tile.wallu = -1; tile.wallv = -1; } else tile.wall = 0; if ((flags & 8) == 8) { tile.liquid = messages[payload++]; tile.isLava = messages[payload] == 1; tile.isHoney = messages[payload] == 2; payload++; } else tile.liquid = 0; int rle = BitConverter.ToInt16(messages, payload); payload += 2; for (int r = x + 1; r < x + 1 + rle; r++) { tiles[r, y].isActive = tiles[x, y].isActive; tiles[r, y].type = tiles[x, y].type; tiles[r, y].u = tiles[x, y].u; tiles[r, y].v = tiles[x, y].v; tiles[r, y].wall = tiles[x, y].wall; tiles[r, y].wallu = -1; tiles[r, y].wallv = -1; tiles[r, y].liquid = tiles[x, y].liquid; tiles[r, y].isLava = tiles[x, y].isLava; tiles[r, y].isHoney = tiles[x, y].isHoney; tiles[r, y].hasRedWire = tiles[x, y].hasRedWire; tiles[r, y].hasGreenWire = tiles[x, y].hasGreenWire; tiles[r, y].hasBlueWire = tiles[x, y].hasBlueWire; tiles[r, y].half = tiles[x, y].half; tiles[r, y].actuator = tiles[x, y].actuator; tiles[r, y].inactive = tiles[x, y].inactive; tiles[r, y].slope = tiles[x, y].slope; tiles[r, y].color = tiles[x, y].color; tiles[r, y].wallColor = tiles[x, y].wallColor; } x += rle; } } break; case 0x0b: //recalculate u/v { int startx = BitConverter.ToInt16(messages, payload); payload += 4; int starty = BitConverter.ToInt16(messages, payload); payload += 4; int endx = BitConverter.ToInt16(messages, payload); payload += 2; int endy = BitConverter.ToInt16(messages, payload); for (int y = starty; y <= endy; y++) for (int x = startx; x <= endx; x++) sentSections[x, y] = true; startx *= 200; starty *= 150; endx = (endx + 1) * 200; endy = (endy + 1) * 150; for (int y = starty; y < endy; y++) for (int x = startx; x < endx; x++) { Tile tile = tiles[x, y]; if (tile.isActive && !tileInfos[tile.type].hasExtra) { tile.u = -1; tile.v = -1; } if (tile.wall > 0) { tile.wallu = -1; tile.wallv = -1; } } if (loginLevel == 5) fetchNextSection(); } break; case 0x0c: //player spawned break; case 0x0d: //player control break; case 0x0e: //set active players break; case 0x10: //player life break; case 0x11: //modify tile break; case 0x12: //set time break; case 0x13: //open/close door break; case 0x14: //update tile block break; case 0x15: //update item break; case 0x16: //set item owner break; case 0x17: //update NPC { int slot = BitConverter.ToInt16(messages, payload); payload += 2; float posx = BitConverter.ToSingle(messages, payload); payload += 4; float posy = BitConverter.ToSingle(messages, payload); payload += 4; payload += 9; //skip velocity and target byte flags = messages[payload++]; payload += 4; //skip life //skip any applicable AI if ((flags & 32) == 32) payload += 4; if ((flags & 16) == 16) payload += 4; if ((flags & 8) == 8) payload += 4; if ((flags & 4) == 4) payload += 4; int id = BitConverter.ToInt16(messages, payload); bool found = false; for (int i = 0; i < npcs.Count; i++) { if (npcs[i].slot == slot) { npcs[i].x = posx; npcs[i].y = posy; npcs[i].sprite = id; found = true; addNPCToMenu(npcs[i]); } } if (!found) { for (int i = 0; i < friendlyNPCs.Length; i++) if (friendlyNPCs[i].id == id) //we found a friendly npc { NPC npc = new NPC(); npc.isHomeless = true; //homeless for now npc.title = friendlyNPCs[i].title; npc.name = ""; npc.num = friendlyNPCs[i].num; npc.sprite = id; npc.x = posx; npc.y = posy; npc.slot = slot; npcs.Add(npc); addNPCToMenu(npc); } } } break; case 0x18: //strike npc break; case 0x19: //chat break; case 0x1a: //damage player break; case 0x1b: //update projectile break; case 0x1c: //damage npc break; case 0x1d: //destroy projectile break; case 0x1e: //pvp toggled break; case 0x1f: //request open chest - c2s only break; case 0x20: //set chest item break; case 0x21: //open chest break; case 0x22: //destroy chest break; case 0x23: //heal player break; case 0x24: //set zones break; case 0x25: //request password. { Dispatcher.Invoke(DispatcherPriority.Normal, new Action(delegate() { ServerPassword s = new ServerPassword(); if (s.ShowDialog() == true) SendMessage(0x26, s.Password); else { socket.Close(); serverText.Text = "Login cancelled."; busy = false; } })); } break; case 0x26: //login - c2s only break; case 0x27: //unassign item break; case 0x28: //talk to npc break; case 0x29: //animate flail break; case 0x2a: //set mana break; case 0x2b: //replenish mana break; case 0x2c: //kill player break; case 0x2d: //change party break; case 0x2e: //read sign - c2s only break; case 0x2f: //edit sign break; case 0x30: //adjust liquids break; case 0x31: //okay to spawn if (loginLevel == 4) { loginLevel = 5; Dispatcher.Invoke(DispatcherPriority.Normal, new Action(delegate() { serverText.Text = ""; render.SetWorld(tilesWide, tilesHigh, groundLevel, rockLevel, styles, treeX, treeStyle, caveBackX, caveBackStyle, jungleBackStyle, hellBackStyle, npcs); loaded = true; curX = spawnX; curY = spawnY; if (render.Textures != null && render.Textures.Valid) { UseTextures.IsChecked = true; curScale = 16.0; } RenderMap(); })); SendMessage(0x0c); //spawn if (tilesWide == 8400) //large world { //give the user a choice to map a remote large world Dispatcher.Invoke(DispatcherPriority.Normal, new Action(delegate() { if (MessageBox.Show(this, "Mapping remote large worlds is not recommend.\nContinue to map the rest of the world?", "Map Whole World", MessageBoxButton.YesNo, MessageBoxImage.Question) == MessageBoxResult.Yes) { fetchNextSection(); //start fetching the world } else { socket.Close(); busy = false; } })); } else fetchNextSection(); //start fetching the world } break; case 0x32: //set buffs break; case 0x33: //old man answer break; case 0x34: //unlock chest break; case 0x35: //add npc buff break; case 0x36: //set npc buffs break; case 0x37: //add player buff break; case 0x38: //set npc names { int id = BitConverter.ToInt16(messages, payload); payload += 2; string name = Encoding.ASCII.GetString(messages, payload, start + len - payload); for (int i = 0; i < npcs.Count; i++) { if (npcs[i].sprite == id) { npcs[i].name = name; addNPCToMenu(npcs[i]); } } } break; case 0x39: //set balance stats break; case 0x3a: //play harp break; case 0x3b: //flip switch break; case 0x3c: //move npc home { int slot = BitConverter.ToInt16(messages, payload); payload += 2; int x = BitConverter.ToInt16(messages, payload); payload += 2; int y = BitConverter.ToInt16(messages, payload); payload += 2; byte homeless = messages[payload]; for (int i = 0; i < npcs.Count; i++) { if (npcs[i].slot == slot) { npcs[i].isHomeless = homeless == 1; npcs[i].homeX = x; npcs[i].homeY = y; addNPCToMenu(npcs[i]); break; } } } break; case 0x3d: //summon boss break; case 0x3e: //ninja dodge break; case 0x3f: //paint tile break; case 0x40: //paint wall break; case 0x41: //teleport npc break; case 0x42: //heal player break; case 0x44: //unknown break; default: // ignore unknown messages break; } }
private void HandleMessage(int start, int len) { if (statusTotal > 0) { statusCount++; if (statusCount == statusTotal) statusTotal = 0; else Dispatcher.Invoke(DispatcherPriority.Normal, new Action(delegate() { serverText.Text = ((int)((float)statusCount * 100.0 / (float)statusTotal)) + "% - " + status; })); } int messageid = messages[start++]; len--; int payload = start; switch (messageid) { case 0x01: // connect request - c2s only break; case 0x02: //error { string error = Encoding.ASCII.GetString(messages, payload, len); Dispatcher.Invoke(DispatcherPriority.Normal, new Action(delegate() { MessageBox.Show(error); })); socket.Close(); busy = false; } break; case 0x03: //connection approved { if (loginLevel == 1) loginLevel = 2; playerSlot = messages[payload]; SendMessage(4); SendMessage(0x10); SendMessage(0x2a); //send buffs //send inventory SendMessage(6); if (loginLevel == 2) loginLevel = 3; } break; case 0x04: //player appearance //ignore other players break; case 0x05: //inventory items //ignore player inventory break; case 0x06: //request world info - c2s only break; case 0x07: //world info { gameTime = BitConverter.ToInt32(messages, payload); payload += 4; dayNight = messages[payload++] == 1; moonPhase = messages[payload++]; bloodMoon = messages[payload++] == 1; tilesWide = BitConverter.ToInt32(messages, payload); payload += 4; tilesHigh = BitConverter.ToInt32(messages, payload); payload += 4; spawnX = BitConverter.ToInt32(messages, payload); payload += 4; spawnY = BitConverter.ToInt32(messages, payload); payload += 4; groundLevel = BitConverter.ToInt32(messages, payload); payload += 4; rockLevel = BitConverter.ToInt32(messages, payload); payload += 4; payload += 4; //skip world id byte flags = messages[payload++]; string title = Encoding.ASCII.GetString(messages, payload, start + len - payload); Dispatcher.Invoke(DispatcherPriority.Normal, new Action(delegate() { Title = title; })); smashedOrb = (flags & 1) == 1; killedBoss1 = (flags & 2) == 2; killedBoss2 = (flags & 4) == 4; killedBoss3 = (flags & 8) == 8; hardMode = (flags & 16) == 16; killedClown = (flags & 32) == 32; meteorSpawned = false; killedFrost = false; killedGoblins = false; savedMechanic = false; savedTinkerer = false; savedWizard = false; goblinsDelay = 0; altarsSmashed = 0; ResizeMap(); if (loginLevel == 3) { sectionsWide = (tilesWide / 200); sectionsHigh = (tilesHigh / 150); sentSections = new bool[sectionsWide, sectionsHigh]; loginLevel = 4; for (int y = 0; y < tilesHigh; y++) //set all tiles to blank for (int x = 0; x < tilesWide; x++) { tiles[x, y].isActive = false; tiles[x, y].wall = 0; tiles[x, y].liquid = 0; tiles[x, y].hasWire = false; } SendMessage(8); //request initial tile data } } break; case 0x08: //request initial tile data - c2s only break; case 0x09: //status text { statusTotal = BitConverter.ToInt32(messages, payload); payload += 4; statusCount = 0; status = Encoding.ASCII.GetString(messages, payload, start + len - payload); Dispatcher.Invoke(DispatcherPriority.Normal, new Action(delegate() { serverText.Text = status; })); } break; case 0x0a: //tile row data { int width = BitConverter.ToInt16(messages, payload); payload += 2; int startx = BitConverter.ToInt32(messages, payload); payload += 4; int y = BitConverter.ToInt32(messages, payload); payload += 4; for (int x = startx; x < startx + width; x++) { Tile tile = tiles[x, y]; byte flags = messages[payload++]; tile.isActive = (flags & 1) == 1; tile.hasWire = (flags & 16) == 16; if (tile.isActive) { tile.type = messages[payload++]; if (tileInfos[tile.type].hasExtra) { tile.u = BitConverter.ToInt16(messages, payload); payload += 2; tile.v = BitConverter.ToInt16(messages, payload); payload += 2; } else { tile.u = -1; tile.v = -1; } } if ((flags & 4) == 4) { tile.wall = messages[payload++]; tile.wallu = -1; tile.wallv = -1; } else tile.wall = 0; if ((flags & 8) == 8) { tile.liquid = messages[payload++]; tile.isLava = messages[payload++] == 1; } else tile.liquid = 0; int rle = BitConverter.ToInt16(messages, payload); payload += 2; for (int r = x + 1; r < x + 1 + rle; r++) { tiles[r, y].isActive = tiles[x, y].isActive; tiles[r, y].type = tiles[x, y].type; tiles[r, y].u = tiles[x, y].u; tiles[r, y].v = tiles[x, y].v; tiles[r, y].wall = tiles[x, y].wall; tiles[r, y].wallu = -1; tiles[r, y].wallv = -1; tiles[r, y].liquid = tiles[x, y].liquid; tiles[r, y].isLava = tiles[x, y].isLava; tiles[r, y].hasWire = tiles[x, y].hasWire; } x += rle; } } break; case 0x0b: //recalculate u/v { int startx = BitConverter.ToInt32(messages, payload); payload += 4; int starty = BitConverter.ToInt32(messages, payload); payload += 4; int endx = BitConverter.ToInt32(messages, payload); payload += 4; int endy = BitConverter.ToInt32(messages, payload); for (int y = starty; y<= endy; y++) for (int x = startx; x <= endx; x++) sentSections[x, y] = true; startx *= 200; starty *= 150; endx = (endx + 1) * 200; endy = (endy + 1) * 150; for (int y=starty;y<endy;y++) for (int x = startx; x < endx; x++) { Tile tile = tiles[x, y]; if (tile.isActive && !tileInfos[tile.type].hasExtra) { tile.u = -1; tile.v = -1; } if (tile.wall > 0) { tile.wallu = -1; tile.wallv = -1; } } if (loginLevel == 5) fetchNextSection(); } break; case 0x0c: //player spawned break; case 0x0d: //player control break; case 0x0e: //set active players break; case 0x10: //player life break; case 0x11: //modify tile break; case 0x12: //set time break; case 0x13: //open/close door break; case 0x14: //update tile block break; case 0x15: //update item break; case 0x16: //set item owner break; case 0x17: //update NPC { int slot = BitConverter.ToInt16(messages, payload); payload += 2; float posx = BitConverter.ToSingle(messages, payload); payload += 4; float posy = BitConverter.ToSingle(messages, payload); payload += 4; payload += 32; //don't care about velocity, target, ai, or direction int id = BitConverter.ToInt16(messages, payload); bool found = false; for (int i = 0; i < npcs.Count; i++) { if (npcs[i].slot == slot) { npcs[i].x = posx; npcs[i].y = posy; npcs[i].sprite = id; found = true; addNPCToMenu(npcs[i]); } } if (!found) { for (int i = 0; i < friendlyNPCs.Length; i++) if (friendlyNPCs[i].id == id) //we found a friendly npc { NPC npc = new NPC(); npc.isHomeless = true; //homeless for now npc.title = friendlyNPCs[i].title; npc.name = ""; npc.num = friendlyNPCs[i].num; npc.sprite = id; npc.x = posx; npc.y = posy; npc.slot = slot; npcs.Add(npc); addNPCToMenu(npc); } } } break; case 0x18: //strike npc break; case 0x19: //chat break; case 0x1a: //damage player break; case 0x1b: //update projectile break; case 0x1c: //damage npc break; case 0x1d: //destroy projectile break; case 0x1e: //pvp toggled break; case 0x1f: //request open chest - c2s only break; case 0x20: //set chest item break; case 0x21: //open chest break; case 0x22: //destroy chest break; case 0x23: //heal player break; case 0x24: //set zones break; case 0x25: //request password. { Dispatcher.Invoke(DispatcherPriority.Normal, new Action(delegate() { ServerPassword s = new ServerPassword(); if (s.ShowDialog() == true) SendMessage(0x26, s.Password); else { socket.Close(); serverText.Text = "Login cancelled."; busy = false; } })); } break; case 0x26: //login - c2s only break; case 0x27: //unassign item break; case 0x28: //talk to npc break; case 0x29: //animate flail break; case 0x2a: //set mana break; case 0x2b: //replenish mana break; case 0x2c: //kill player break; case 0x2d: //change party break; case 0x2e: //read sign - c2s only break; case 0x2f: //edit sign break; case 0x30: //adjust liquids break; case 0x31: //okay to spawn if (loginLevel == 4) { loginLevel = 5; Dispatcher.Invoke(DispatcherPriority.Normal, new Action(delegate() { serverText.Text = ""; render.SetWorld(tilesWide, tilesHigh, groundLevel, rockLevel, npcs); loaded = true; curX = spawnX; curY = spawnY; if (render.Textures!=null && render.Textures.Valid) { UseTextures.IsChecked = true; curScale = 16.0; } RenderMap(); })); SendMessage(0x0c); //spawn if (tilesWide == 8400) //large world { socket.Close(); busy = false; Dispatcher.Invoke(DispatcherPriority.Normal, new Action(delegate() { MessageBox.Show("Will not map remote large worlds\nother than the spawn point"); })); } else fetchNextSection(); //start fetching the world } break; case 0x32: //set buffs break; case 0x33: //old man answer break; case 0x34: //unlock chest break; case 0x35: //add npc buff break; case 0x36: //set npc buffs break; case 0x37: //add player buff break; case 0x38: //set npc names { int id = BitConverter.ToInt16(messages, payload); payload += 2; string name = Encoding.ASCII.GetString(messages, payload, start + len - payload); for (int i = 0; i < npcs.Count; i++) { if (npcs[i].sprite == id) { npcs[i].name = name; addNPCToMenu(npcs[i]); } } } break; case 0x39: //set balance stats break; case 0x3a: //play harp break; case 0x3b: //flip switch break; case 0x3c: //move npc home { int slot=BitConverter.ToInt16(messages,payload); payload+=2; int x=BitConverter.ToInt16(messages,payload); payload+=2; int y=BitConverter.ToInt16(messages,payload); payload+=2; byte homeless=messages[payload]; for (int i = 0; i < npcs.Count; i++) { if (npcs[i].slot == slot) { npcs[i].isHomeless = homeless == 1; npcs[i].homeX = x; npcs[i].homeY = y; addNPCToMenu(npcs[i]); break; } } } break; default: // ignore unknown messages break; } }