func (c *Client) handleBlock(g *Game, w *game.World, m *proto.MsgBlock) { // Eventually we should simulate block placement/removal entirely // on the server side, but for now, this works fairly well. inv := c.player.Inventory() curBlock := w.Block(m.Pos) if curBlock == mapgen.BLOCK_AIR { // If we are changing AIR to AIR (caused by a race condition) ignore it. if m.Type == mapgen.BLOCK_AIR { return } // Placing a block item := game.ItemFromBlock(m.Type) if inv.RemoveItem(item) { w.ChangeBlock(m.Pos, m.Type) } else { log.Println("Rejecting attempt to place block that is not in inventory!") c.sendBlockChanged(m.Pos, curBlock) } } else { if !curBlock.Mineable() { log.Println("Attempt to mine unmineable block rejected!") c.sendBlockChanged(m.Pos, curBlock) return } // Removing a block item := game.ItemFromBlock(curBlock) w.AddEntity(game.NewWorldItem(item, m.Pos.Center())) w.ChangeBlock(m.Pos, mapgen.BLOCK_AIR) } c.Send(&proto.MsgInventoryState{ Items: c.player.Inventory().ItemsToByteArray(), }) }