Beispiel #1
0
class PlayerPositionPanel(Panel):
    def __init__(self, tool):
        Panel.__init__(self, name='Panel.PlayerPositionPanel')
        self.tool = tool
        self.player_UUID = {"UUID": [], "Name": []}
        self.level = tool.editor.level
        self.playercache = PlayerCache()
        # Add this instance to PlayerCache 'targets'. PlayerCache generated processes will call
        # this instance 'update_player' method when they have finished their execution.
        self.playercache.add_target(self.update_player)
        
        if hasattr(self.level, 'players'):
            players = self.level.players or ["[No players]"]
            if not self.level.oldPlayerFolderFormat:
                for player in players:
                    if player != "Player" and player != "[No players]":
                        if len(player) > 4 and player[4] == "-":
                            os.rename(os.path.join(self.level.worldFolder.getFolderPath("playerdata"), player+".dat"), os.path.join(self.level.worldFolder.getFolderPath("playerdata"), player.replace("-", "", 1)+".dat"))
                            player = player.replace("-", "", 1)
#                         print 5
                        data = self.playercache.getPlayerInfo(player, use_old_data=True)
                        #self.player_UUID[data[0]] = data[1]
                        self.player_UUID["UUID"].append(data[0])
                        self.player_UUID["Name"].append(data[1])
                        #self.player_UUID[player] = data
                if "Player" in players:
                    #self.player_UUID["Player (Single Player)"] = "Player"
                    self.player_UUID["UUID"].append("Player")
                    self.player_UUID["Name"].append("Player (Single Player)")
                if "[No players]" not in players:
                    self.player_names = sorted(self.player_UUID.values(), key=lambda x: False if x == "Player (Single Player)" else x)
                else:
                    self.player_UUID["UUID"].append("[No players]")
                    self.player_UUID["Name"].append("[No players]")

        else:
            players = ["Player (Single Player)"]
        self.players = players
        
        if 'Player' in self.player_UUID['UUID'] and 'Player (Single Player)' in self.player_UUID['Name']:
            self.player_UUID['UUID'].insert(0, self.player_UUID['UUID'].pop(self.player_UUID['UUID'].index('Player')))
            self.player_UUID['Name'].insert(0, self.player_UUID['Name'].pop(self.player_UUID['Name'].index('Player (Single Player)')))

        self.pages = TabPanel()
        tab_height = self.pages.tab_height

        max_height = tab_height + self.tool.editor.mainViewport.height - self.tool.editor.toolbar.height - self.tool.editor.subwidgets[0].height - self.pages.margin * 2
        #-# Uncomment the following line to have a maximum height for this panel.
        # max_height = min(max_height, 500)

        self.editNBTDataButton = Button("Edit NBT", action=self.editNBTData, tooltipText="Open the NBT Explorer to edit player's attributes and inventory")
        addButton = Button("Add", action=self.tool.addPlayer)
        removeButton = Button("Remove", action=self.tool.removePlayer)
        gotoButton = Button("Goto", action=self.tool.gotoPlayer)
        gotoCameraButton = Button("Goto View", action=self.tool.gotoPlayerCamera)
        moveButton = Button("Move", action=self.tool.movePlayer)
        moveToCameraButton = Button("Align to Camera", action=self.tool.movePlayerToCamera)
        reloadSkin = Button("Reload Skins", action=self.tool.reloadSkins, tooltipText="This pulls skins from the online server, so this may take a while")

        btns = [self.editNBTDataButton]
        if not isinstance(self.level, pymclevel.leveldbpocket.PocketLeveldbWorld):
            btns.extend([addButton, removeButton])
        btns.extend([gotoButton, gotoCameraButton, moveButton, moveToCameraButton, reloadSkin])
        btns = Column(btns, margin=0, spacing=2)
        h = max_height - btns.height - self.pages.margin * 2 - 2 - self.font.get_linesize() * 2

        col = Label('')

        def close():
            self.pages.show_page(col)
        self.nbttree = NBTExplorerToolPanel(self.tool.editor, nbtObject={}, height=max_height, \
                                            close_text="Go Back", no_header=True, close_action=close,
                                            load_text=None)
        self.nbttree.shrink_wrap()

        self.nbtpage = Column([self.nbttree])
        self.nbtpage.shrink_wrap()
        self.pages.add_page("NBT Data", self.nbtpage)
        self.pages.set_rect(map(lambda x:x+self.margin, self.nbttree._rect))

        tableview = TableView(nrows=(h - (self.font.get_linesize() * 2.5)) / self.font.get_linesize(),
                              header_height=self.font.get_linesize(),
                              columns=[TableColumn("Player Name(s):", (self.nbttree.width - (self.margin * 3)) / 3),
                                       TableColumn("Player UUID(s):", (self.nbttree.width - (self.margin * 3)))],
                              )
        tableview.index = 0
        tableview.num_rows = lambda: len(self.player_UUID["UUID"])
        tableview.row_data = lambda i: (self.player_UUID["Name"][i],self.player_UUID["UUID"][i])
        tableview.row_is_selected = lambda x: x == tableview.index
        tableview.zebra_color = (0, 0, 0, 48)

        def selectTableRow(i, evt):
            tableview.index = i

        tableview.click_row = selectTableRow

        def mouse_down(e):
            if e.button == 1 and e.num_clicks > 1:
                self.editNBTData()
            TableRowView.mouse_down(tableview.rows, e)

        tableview.rows.mouse_down = mouse_down

        tableview.rows.tooltipText = "Double-click or use the button below to edit the NBT Data."

        self.table = tableview

        col.set_parent(None)
        self.col = col = Column([tableview, btns], spacing=2)

        self.pages.add_page("Players", col, 0)

        self.pages.shrink_wrap()
        self.pages.show_page(col)
        self.add(self.pages)
        self.shrink_wrap()
        self.max_height = max_height

    def editNBTData(self):
        player = self.selectedPlayer
        if player == 'Player (Single Player)':
            alert("Not yet implemented.\nUse the NBT Explorer to edit this player.")
        elif player == '[No players]':
            return
        else:
            player = self.level.getPlayerTag(self.selectedPlayer)
            if player is not None:
                self.pages.remove_page(self.nbtpage)

                def close():
                    self.pages.show_page(self.col)

                self.nbttree = NBTExplorerToolPanel(self.tool.editor, nbtObject=player, fileName=None,
                                              savePolicy=-1, dataKeyName=None,
                                              height=self.max_height, no_header=True, close_text="Go Back",
                                              close_action=close, load_text=None,
                                              copy_data=False)

                self.nbtpage = Column([self.nbttree,])
                self.nbtpage.shrink_wrap()
                self.pages.add_page("NBT Data", self.nbtpage)
                self.pages.show_page(self.nbtpage)
            else:
                alert(_("Unable to load player %s" % self.selectedPlayer()))

    @property
    def selectedPlayer(self):
        if not self.level.oldPlayerFolderFormat:
            player = self.players[self.table.index]
            if player != "Player (Single Player)" and player != "[No players]" and player != "~local_player":
                return self.player_UUID["UUID"][self.table.index]
            else:
                return player
        else:
            return self.players[self.table.index]

    def key_down(self, evt):
        self.dispatch_key('key_down', evt)

    def dispatch_key(self, name, evt):
        if not hasattr(evt, 'key'):
            return
        if name == "key_down":
            keyname = self.root.getKey(evt)
            if self.pages.current_page == self.col:
                if keyname == "Up" and self.table.index > 0:
                    self.table.index -= 1
                    self.table.rows.scroll_to_item(self.table.index)
                elif keyname == "Down" and self.table.index < len(self.players) - 1:
                    self.table.index += 1
                    self.table.rows.scroll_to_item(self.table.index)
                elif keyname == 'Page down':
                    self.table.index = min(len(self.players) - 1, self.table.index + self.table.rows.num_rows())
                elif keyname == 'Page up':
                    self.table.index = max(0, self.table.index - self.table.rows.num_rows())
                elif keyname == 'Return':
                    if self.selectedPlayer:
                        self.editNBTData()
                if self.table.rows.cell_to_item_no(0, 0) + self.table.rows.num_rows() -1 > self.table.index or self.table.rows.cell_to_item_no(0, 0) + self.table.rows.num_rows() -1 < self.table.index:
                    self.table.rows.scroll_to_item(self.table.index)
            elif self.pages.current_page == self.nbtpage:
                self.nbttree.dispatch_key(name, evt)

    def update_player(self, data):
        if isinstance(data, tuple):
            if data[0] in self.player_UUID['UUID']:
                idx = self.player_UUID['UUID'].index(data[0])
                self.player_UUID['UUID'][idx] = data[0]
                self.player_UUID['Name'][idx] = data[1]
Beispiel #2
0
class PlayerPositionPanel(Panel):
    def __init__(self, tool):
        Panel.__init__(self, name='Panel.PlayerPositionPanel')
        self.tool = tool
        self.player_UUID = {"UUID": [], "Name": []}
        self.level = tool.editor.level
        self.playercache = PlayerCache()
        # Add this instance to PlayerCache 'targets'. PlayerCache generated processes will call
        # this instance 'update_player' method when they have finished their execution.
        self.playercache.add_target(self.update_player)

        if hasattr(self.level, 'players'):
            players = self.level.players or ["[No players]"]
            if not self.level.oldPlayerFolderFormat:
                for player in players:
                    if player != "Player" and player != "[No players]":
                        if len(player) > 4 and player[4] == "-":
                            os.rename(
                                os.path.join(
                                    self.level.worldFolder.getFolderPath(
                                        "playerdata"), player + ".dat"),
                                os.path.join(
                                    self.level.worldFolder.getFolderPath(
                                        "playerdata"),
                                    player.replace("-", "", 1) + ".dat"))
                            player = player.replace("-", "", 1)


#                         print 5
                        data = self.playercache.getPlayerInfo(
                            player, use_old_data=True)
                        #self.player_UUID[data[0]] = data[1]
                        self.player_UUID["UUID"].append(data[0])
                        self.player_UUID["Name"].append(data[1])
                        #self.player_UUID[player] = data
                if "Player" in players:
                    #self.player_UUID["Player (Single Player)"] = "Player"
                    self.player_UUID["UUID"].append("Player")
                    self.player_UUID["Name"].append("Player (Single Player)")
                if "[No players]" not in players:
                    self.player_names = sorted(
                        self.player_UUID.values(),
                        key=lambda x: False
                        if x == "Player (Single Player)" else x)
                else:
                    self.player_UUID["UUID"].append("[No players]")
                    self.player_UUID["Name"].append("[No players]")

        else:
            players = ["Player (Single Player)"]
        self.players = players

        if 'Player' in self.player_UUID[
                'UUID'] and 'Player (Single Player)' in self.player_UUID[
                    'Name']:
            self.player_UUID['UUID'].insert(
                0, self.player_UUID['UUID'].pop(
                    self.player_UUID['UUID'].index('Player')))
            self.player_UUID['Name'].insert(
                0, self.player_UUID['Name'].pop(
                    self.player_UUID['Name'].index('Player (Single Player)')))

        self.pages = TabPanel()
        tab_height = self.pages.tab_height

        max_height = tab_height + self.tool.editor.mainViewport.height - self.tool.editor.toolbar.height - self.tool.editor.subwidgets[
            0].height - self.pages.margin * 2
        #-# Uncomment the following line to have a maximum height for this panel.
        # max_height = min(max_height, 500)

        self.editNBTDataButton = Button(
            "Edit NBT",
            action=self.editNBTData,
            tooltipText=
            "Open the NBT Explorer to edit player's attributes and inventory")
        addButton = Button("Add", action=self.tool.addPlayer)
        removeButton = Button("Remove", action=self.tool.removePlayer)
        gotoButton = Button("Goto", action=self.tool.gotoPlayer)
        gotoCameraButton = Button("Goto View",
                                  action=self.tool.gotoPlayerCamera)
        moveButton = Button("Move", action=self.tool.movePlayer)
        moveToCameraButton = Button("Align to Camera",
                                    action=self.tool.movePlayerToCamera)
        reloadSkin = Button(
            "Reload Skins",
            action=self.tool.reloadSkins,
            tooltipText=
            "This pulls skins from the online server, so this may take a while"
        )

        btns = [self.editNBTDataButton]
        if not isinstance(self.level,
                          pymclevel.leveldbpocket.PocketLeveldbWorld):
            btns.extend([addButton, removeButton])
        btns.extend([
            gotoButton, gotoCameraButton, moveButton, moveToCameraButton,
            reloadSkin
        ])
        btns = Column(btns, margin=0, spacing=2)
        h = max_height - btns.height - self.pages.margin * 2 - 2 - self.font.get_linesize(
        ) * 2

        col = Label('')

        def close():
            self.pages.show_page(col)
        self.nbttree = NBTExplorerToolPanel(self.tool.editor, nbtObject={}, height=max_height, \
                                            close_text="Go Back", no_header=True, close_action=close,
                                            load_text=None)
        self.nbttree.shrink_wrap()

        self.nbtpage = Column([self.nbttree])
        self.nbtpage.shrink_wrap()
        self.pages.add_page("NBT Data", self.nbtpage)
        self.pages.set_rect(map(lambda x: x + self.margin, self.nbttree._rect))

        tableview = TableView(
            nrows=(h - (self.font.get_linesize() * 2.5)) /
            self.font.get_linesize(),
            header_height=self.font.get_linesize(),
            columns=[
                TableColumn("Player Name(s):",
                            (self.nbttree.width - (self.margin * 3)) / 3),
                TableColumn("Player UUID(s):",
                            (self.nbttree.width - (self.margin * 3)))
            ],
        )
        tableview.index = 0
        tableview.num_rows = lambda: len(self.player_UUID["UUID"])
        tableview.row_data = lambda i: (self.player_UUID["Name"][i], self.
                                        player_UUID["UUID"][i])
        tableview.row_is_selected = lambda x: x == tableview.index
        tableview.zebra_color = (0, 0, 0, 48)

        def selectTableRow(i, evt):
            tableview.index = i

        tableview.click_row = selectTableRow

        def mouse_down(e):
            if e.button == 1 and e.num_clicks > 1:
                self.editNBTData()
            TableRowView.mouse_down(tableview.rows, e)

        tableview.rows.mouse_down = mouse_down

        tableview.rows.tooltipText = "Double-click or use the button below to edit the NBT Data."

        self.table = tableview

        col.set_parent(None)
        self.col = col = Column([tableview, btns], spacing=2)

        self.pages.add_page("Players", col, 0)

        self.pages.shrink_wrap()
        self.pages.show_page(col)
        self.add(self.pages)
        self.shrink_wrap()
        self.max_height = max_height

    def editNBTData(self):
        player = self.selectedPlayer
        if player == 'Player (Single Player)':
            alert(
                "Not yet implemented.\nUse the NBT Explorer to edit this player."
            )
        elif player == '[No players]':
            return
        else:
            player = self.level.getPlayerTag(self.selectedPlayer)
            if player is not None:
                self.pages.remove_page(self.nbtpage)

                def close():
                    self.pages.show_page(self.col)

                self.nbttree = NBTExplorerToolPanel(self.tool.editor,
                                                    nbtObject=player,
                                                    fileName=None,
                                                    savePolicy=-1,
                                                    dataKeyName=None,
                                                    height=self.max_height,
                                                    no_header=True,
                                                    close_text="Go Back",
                                                    close_action=close,
                                                    load_text=None,
                                                    copy_data=False)

                self.nbtpage = Column([
                    self.nbttree,
                ])
                self.nbtpage.shrink_wrap()
                self.pages.add_page("NBT Data", self.nbtpage)
                self.pages.show_page(self.nbtpage)
            else:
                alert(_("Unable to load player %s" % self.selectedPlayer()))

    @property
    def selectedPlayer(self):
        if not self.level.oldPlayerFolderFormat:
            player = self.players[self.table.index]
            if player != "Player (Single Player)" and player != "[No players]" and player != "~local_player":
                return self.player_UUID["UUID"][self.table.index]
            else:
                return player
        else:
            return self.players[self.table.index]

    def key_down(self, evt):
        self.dispatch_key('key_down', evt)

    def dispatch_key(self, name, evt):
        if not hasattr(evt, 'key'):
            return
        if name == "key_down":
            keyname = self.root.getKey(evt)
            if self.pages.current_page == self.col:
                if keyname == "Up" and self.table.index > 0:
                    self.table.index -= 1
                    self.table.rows.scroll_to_item(self.table.index)
                elif keyname == "Down" and self.table.index < len(
                        self.players) - 1:
                    self.table.index += 1
                    self.table.rows.scroll_to_item(self.table.index)
                elif keyname == 'Page down':
                    self.table.index = min(
                        len(self.players) - 1,
                        self.table.index + self.table.rows.num_rows())
                elif keyname == 'Page up':
                    self.table.index = max(
                        0, self.table.index - self.table.rows.num_rows())
                elif keyname == 'Return':
                    if self.selectedPlayer:
                        self.editNBTData()
                if self.table.rows.cell_to_item_no(
                        0, 0
                ) + self.table.rows.num_rows(
                ) - 1 > self.table.index or self.table.rows.cell_to_item_no(
                        0,
                        0) + self.table.rows.num_rows() - 1 < self.table.index:
                    self.table.rows.scroll_to_item(self.table.index)
            elif self.pages.current_page == self.nbtpage:
                self.nbttree.dispatch_key(name, evt)

    def update_player(self, data):
        if isinstance(data, tuple):
            if data[0] in self.player_UUID['UUID']:
                idx = self.player_UUID['UUID'].index(data[0])
                self.player_UUID['UUID'][idx] = data[0]
                self.player_UUID['Name'][idx] = data[1]
Beispiel #3
0
class PlayerAddOperation(Operation):
    playerTag = None

    def __init__(self, tool):
        super(PlayerAddOperation, self).__init__(tool.editor, tool.editor.level)
        self.tool = tool
        self.level = self.tool.editor.level
        self.canUndo = False
        self.playercache = PlayerCache()

    def perform(self, recordUndo=True):
        initial = ""
        allowed_chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_"
        while True:
            self.player = input_text_buttons("Enter a Player Name: ", 160, initial=initial, allowed_chars=allowed_chars)
            if self.player is None:
                return
            elif len(self.player) > 16:
                alert("Name too long. Maximum name length is 16.")
                initial = self.player
            elif len(self.player) < 1:
                alert("Name too short. Minimum name length is 1.")
                initial = self.player
            else:
                break
            
#         print 1
        data = self.playercache.getPlayerInfo(self.player)
        if "<Unknown UUID>" not in data and "Server not ready" not in data:
            self.uuid = data[0]
            self.player = data[1]
        else:
            action = ask("Could not get {}'s UUID. Please make sure that you are connected to the internet and that the player \"{}\" exists.".format(self.player, self.player), ["Enter UUID manually", "Cancel"])
            if action != "Enter UUID manually":
                return
            self.uuid = input_text_buttons("Enter a Player UUID: ", 160)
            if not self.uuid:
                return
#             print 2
            self.player = self.playercache.getPlayerInfo(self.uuid)
            if self.player == self.uuid.replace("-", ""):
                if ask("UUID was not found. Continue anyways?") == "Cancel":
                    return
#         print "PlayerAddOperation.perform::self.uuid", self.uuid
        if self.uuid in self.level.players:
            alert("Player already exists in this World.")
            return

        self.playerTag = self.newPlayer()

        #if self.tool.panel:
        #    self.tool.panel.players.append(self.player)

        if self.level.oldPlayerFolderFormat:
            self.level.playerTagCache[self.level.getPlayerPath(self.player)] = self.playerTag
            
            self.level.players.append(self.player)
            #if self.tool.panel:
                #self.tool.panel.player_UUID[self.player] = self.player

        else:
            self.level.playerTagCache[self.level.getPlayerPath(self.uuid)] = self.playerTag
            
            self.level.players.append(self.uuid)
            if self.tool.panel:
                self.tool.panel.player_UUID["UUID"].append(self.uuid)
                self.tool.panel.player_UUID["Name"].append(self.player)

        self.tool.playerPos[self.editor.level.dimNo][(0,0,0)] = self.uuid
        self.tool.revPlayerPos[self.editor.level.dimNo][self.uuid] = (0,0,0)
#         print 3
        r = self.playercache.getPlayerSkin(self.uuid, force_download=False)
        if not isinstance(r, (str, unicode)):
#             print 'r 1', r
            r = r.join()
#             print 'r 2', r
        self.tool.playerTexture[self.uuid] = loadPNGTexture(r)
        self.tool.markerList.invalidate()
        self.tool.recordMove = False
        self.tool.movingPlayer = self.uuid
        if self.tool.panel:
            self.tool.hidePanel()
            self.tool.showPanel()
        self.canUndo = True
        self.playerTag.save(self.level.getPlayerPath(self.uuid))
        self.tool.nonSavedPlayers.append(self.level.getPlayerPath(self.uuid))
        self.tool.inOtherDimension[self.editor.level.dimNo].append(self.uuid)

    def newPlayer(self):
        playerTag = nbt.TAG_Compound()

        playerTag['Air'] = nbt.TAG_Short(300)
        playerTag['AttackTime'] = nbt.TAG_Short(0)
        playerTag['DeathTime'] = nbt.TAG_Short(0)
        playerTag['Fire'] = nbt.TAG_Short(-20)
        playerTag['Health'] = nbt.TAG_Short(20)
        playerTag['HurtTime'] = nbt.TAG_Short(0)
        playerTag['Score'] = nbt.TAG_Int(0)
        playerTag['FallDistance'] = nbt.TAG_Float(0)
        playerTag['OnGround'] = nbt.TAG_Byte(0)
        playerTag['Dimension'] = nbt.TAG_Int(self.editor.level.dimNo)

        playerTag["Inventory"] = nbt.TAG_List()

        playerTag['Motion'] = nbt.TAG_List([nbt.TAG_Double(0) for i in xrange(3)])
        spawn = self.level.playerSpawnPosition()
        spawnX = spawn[0]
        spawnZ = spawn[2]
        blocks = [self.level.blockAt(spawnX, i, spawnZ) for i in xrange(self.level.Height)]
        i = self.level.Height
        done = False
        for index, b in enumerate(reversed(blocks)):
            if b != 0 and not done:
                i = index
                done = True
        spawnY = self.level.Height - i
        playerTag['Pos'] = nbt.TAG_List([nbt.TAG_Double([spawnX, spawnY, spawnZ][i]) for i in xrange(3)])
        playerTag['Rotation'] = nbt.TAG_List([nbt.TAG_Float(0), nbt.TAG_Float(0)])

        return playerTag

    def undo(self):
        self.level.players.remove(self.uuid)
        self.tool.movingPlayer = None
        if self.tool.panel:
            #self.tool.panel.players.remove(self.player)
            self.tool.panel.player_UUID["UUID"].remove(self.uuid)
            self.tool.panel.player_UUID["Name"].remove(self.player)
            self.tool.hidePanel()
            self.tool.showPanel()
        if self.tool.movingPlayer is None:
            del self.tool.playerPos[self.tool.revPlayerPos[self.uuid]]
        else:
            del self.tool.playerPos[(0,0,0)]
        del self.tool.revPlayerPos[self.uuid]
        del self.tool.playerTexture[self.uuid]
        os.remove(self.level.getPlayerPath(self.uuid))
        if self.level.getPlayerPath(self.uuid) in self.tool.nonSavedPlayers:
            self.tool.nonSavedPlayers.remove(self.level.getPlayerPath(self.uuid))

        self.tool.markerList.invalidate()

    def redo(self):
        if not (self.playerTag is None):
            self.level.playerTagCache[self.level.getPlayerPath(self.uuid)] = self.playerTag

            self.level.players.append(self.uuid)
            if self.tool.panel:
                #self.tool.panel.players.append(self.uuid)
                #self.tool.panel.player_UUID[self.player] = self.uuid
                self.tool.panel.player_UUID["UUID"].append(self.uuid)
                self.tool.panel.player_UUID["Name"].append(self.player)
#             print 4
            r = self.playercache.getPlayerSkin(self.uuid)
            if isinstance(r, (str, unicode)):
                r = r.join()
            self.tool.playerTexture[self.uuid] = loadPNGTexture(r)
            self.tool.playerPos[(0,0,0)] = self.uuid
            self.tool.revPlayerPos[self.uuid] = (0,0,0)
            self.playerTag.save(self.level.getPlayerPath(self.uuid))
            self.tool.nonSavedPlayers.append(self.level.getPlayerPath(self.uuid))

        self.tool.markerList.invalidate()
Beispiel #4
0
class PlayerAddOperation(Operation):
    playerTag = None

    def __init__(self, tool):
        super(PlayerAddOperation, self).__init__(tool.editor,
                                                 tool.editor.level)
        self.tool = tool
        self.level = self.tool.editor.level
        self.canUndo = False
        self.playercache = PlayerCache()

    def perform(self, recordUndo=True):
        initial = ""
        allowed_chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_"
        while True:
            self.player = input_text_buttons("Enter a Player Name: ",
                                             160,
                                             initial=initial,
                                             allowed_chars=allowed_chars)
            if self.player is None:
                return
            elif len(self.player) > 16:
                alert("Name too long. Maximum name length is 16.")
                initial = self.player
            elif len(self.player) < 1:
                alert("Name too short. Minimum name length is 1.")
                initial = self.player
            else:
                break

#         print 1
        data = self.playercache.getPlayerInfo(self.player)
        if "<Unknown UUID>" not in data and "Server not ready" not in data:
            self.uuid = data[0]
            self.player = data[1]
        else:
            action = ask(
                "Could not get {}'s UUID. Please make sure that you are connected to the internet and that the player \"{}\" exists."
                .format(self.player,
                        self.player), ["Enter UUID manually", "Cancel"])
            if action != "Enter UUID manually":
                return
            self.uuid = input_text_buttons("Enter a Player UUID: ", 160)
            if not self.uuid:
                return
#             print 2
            self.player = self.playercache.getPlayerInfo(self.uuid)
            if self.player == self.uuid.replace("-", ""):
                if ask("UUID was not found. Continue anyways?") == "Cancel":
                    return
#         print "PlayerAddOperation.perform::self.uuid", self.uuid
        if self.uuid in self.level.players:
            alert("Player already exists in this World.")
            return

        self.playerTag = self.newPlayer()

        #if self.tool.panel:
        #    self.tool.panel.players.append(self.player)

        if self.level.oldPlayerFolderFormat:
            self.level.playerTagCache[self.level.getPlayerPath(
                self.player)] = self.playerTag

            self.level.players.append(self.player)
            #if self.tool.panel:
            #self.tool.panel.player_UUID[self.player] = self.player

        else:
            self.level.playerTagCache[self.level.getPlayerPath(
                self.uuid)] = self.playerTag

            self.level.players.append(self.uuid)
            if self.tool.panel:
                self.tool.panel.player_UUID["UUID"].append(self.uuid)
                self.tool.panel.player_UUID["Name"].append(self.player)

        self.tool.playerPos[self.editor.level.dimNo][(0, 0, 0)] = self.uuid
        self.tool.revPlayerPos[self.editor.level.dimNo][self.uuid] = (0, 0, 0)
        #         print 3
        r = self.playercache.getPlayerSkin(self.uuid, force_download=False)
        if not isinstance(r, (str, unicode)):
            #             print 'r 1', r
            r = r.join()
#             print 'r 2', r
        self.tool.playerTexture[self.uuid] = loadPNGTexture(r)
        self.tool.markerList.invalidate()
        self.tool.recordMove = False
        self.tool.movingPlayer = self.uuid
        if self.tool.panel:
            self.tool.hidePanel()
            self.tool.showPanel()
        self.canUndo = True
        self.playerTag.save(self.level.getPlayerPath(self.uuid))
        self.tool.nonSavedPlayers.append(self.level.getPlayerPath(self.uuid))
        self.tool.inOtherDimension[self.editor.level.dimNo].append(self.uuid)

    def newPlayer(self):
        playerTag = nbt.TAG_Compound()

        playerTag['Air'] = nbt.TAG_Short(300)
        playerTag['AttackTime'] = nbt.TAG_Short(0)
        playerTag['DeathTime'] = nbt.TAG_Short(0)
        playerTag['Fire'] = nbt.TAG_Short(-20)
        playerTag['Health'] = nbt.TAG_Short(20)
        playerTag['HurtTime'] = nbt.TAG_Short(0)
        playerTag['Score'] = nbt.TAG_Int(0)
        playerTag['FallDistance'] = nbt.TAG_Float(0)
        playerTag['OnGround'] = nbt.TAG_Byte(0)
        playerTag['Dimension'] = nbt.TAG_Int(self.editor.level.dimNo)

        playerTag["Inventory"] = nbt.TAG_List()

        playerTag['Motion'] = nbt.TAG_List(
            [nbt.TAG_Double(0) for i in xrange(3)])
        spawn = self.level.playerSpawnPosition()
        spawnX = spawn[0]
        spawnZ = spawn[2]
        blocks = [
            self.level.blockAt(spawnX, i, spawnZ)
            for i in xrange(self.level.Height)
        ]
        i = self.level.Height
        done = False
        for index, b in enumerate(reversed(blocks)):
            if b != 0 and not done:
                i = index
                done = True
        spawnY = self.level.Height - i
        playerTag['Pos'] = nbt.TAG_List(
            [nbt.TAG_Double([spawnX, spawnY, spawnZ][i]) for i in xrange(3)])
        playerTag['Rotation'] = nbt.TAG_List(
            [nbt.TAG_Float(0), nbt.TAG_Float(0)])

        return playerTag

    def undo(self):
        self.level.players.remove(self.uuid)
        self.tool.movingPlayer = None
        if self.tool.panel:
            #self.tool.panel.players.remove(self.player)
            self.tool.panel.player_UUID["UUID"].remove(self.uuid)
            self.tool.panel.player_UUID["Name"].remove(self.player)
            self.tool.hidePanel()
            self.tool.showPanel()
        if self.tool.movingPlayer is None:
            del self.tool.playerPos[self.tool.revPlayerPos[self.uuid]]
        else:
            del self.tool.playerPos[(0, 0, 0)]
        del self.tool.revPlayerPos[self.uuid]
        del self.tool.playerTexture[self.uuid]
        os.remove(self.level.getPlayerPath(self.uuid))
        if self.level.getPlayerPath(self.uuid) in self.tool.nonSavedPlayers:
            self.tool.nonSavedPlayers.remove(
                self.level.getPlayerPath(self.uuid))

        self.tool.markerList.invalidate()

    def redo(self):
        if not (self.playerTag is None):
            self.level.playerTagCache[self.level.getPlayerPath(
                self.uuid)] = self.playerTag

            self.level.players.append(self.uuid)
            if self.tool.panel:
                #self.tool.panel.players.append(self.uuid)
                #self.tool.panel.player_UUID[self.player] = self.uuid
                self.tool.panel.player_UUID["UUID"].append(self.uuid)
                self.tool.panel.player_UUID["Name"].append(self.player)


#             print 4
            r = self.playercache.getPlayerSkin(self.uuid)
            if isinstance(r, (str, unicode)):
                r = r.join()
            self.tool.playerTexture[self.uuid] = loadPNGTexture(r)
            self.tool.playerPos[(0, 0, 0)] = self.uuid
            self.tool.revPlayerPos[self.uuid] = (0, 0, 0)
            self.playerTag.save(self.level.getPlayerPath(self.uuid))
            self.tool.nonSavedPlayers.append(
                self.level.getPlayerPath(self.uuid))

        self.tool.markerList.invalidate()