import sys import win32gui import win32api import win32con, winerror import struct, array import commctrl import os from copy import deepcopy from pymclevel import TAG_Compound, TAG_List, TAG_Int_Array, TAG_Byte_Array, TAG_String from pymclevel import TAG_Long, TAG_Int, TAG_Short, TAG_Byte, TAG_Double, TAG_Float from pymclevel import Entity, TileEntity from numpy import zeros import mcplatform displayName = "NBT Editor" inputs = ( ("TileEntities",True), ("Entities",True), ("TileTicks",True), ) tileents = [] ents = [] ticks = [] tileentsids = [] entsids = [] ticksids = [] newtag = [] clipboard = [] idcounter = 0 tilectr = -1 parenttag = None targettag = None def GetID(): global idcounter idcounter+= 1 return idcounter COMPOUND = 0 LIST = 1 BYTE_ARRAY = 2 INT_ARRAY = 3 STRING = 4 LONG = 5 INT = 6 SHORT = 7 BYTE = 8 DOUBLE = 9 FLOAT = 10 iconnames = ( "compound.ico","list.ico","byte_array.ico","int_array.ico","string.ico", "long.ico","integer.ico","short.ico","byte.ico","double.ico","float.ico" ) tagtypes = { TAG_Compound:0, TAG_List:1, TAG_Byte_Array:2,TAG_Int_Array:3, TAG_String:4,TAG_Long:5, TAG_Int:6, TAG_Short:7, TAG_Byte:8, TAG_Double:9, TAG_Float:10 } HITEM = 0 NAME = 1 TYPE = 2 VAL = 3 IDVAL = 4 NEXT = 5 IDC_LISTBOX = 1023 IDC_BUTTON_NEW = 1024 IDC_BUTTON_COPY = 1025 IDC_BUTTON_CUT = 1026 IDC_BUTTON_PASTE = 1027 IDC_BUTTON_DELETE = 1028 IDC_BUTTON_DONE = 1029 IDC_BUTTON_EDIT = 1030 IDC_BUTTON_CANCEL = 1031 CDC_GROUPBOX = 1124 CDC_BUTTON_DONE = 1125 CDC_BUTTON_CANCEL = 1126 CDC_BYTERADIO = 1127 is64bit = "64 bit" in sys.version if win32gui.UNICODE: def _make_text_buffer(text): # XXX - at this stage win32gui.UNICODE is only True in py3k, # and in py3k is makes sense to reject bytes. if not isinstance(text, unicode): raise TypeError('MENUITEMINFO text must be unicode') data = (text+'\0').encode("unicode-internal") return array.array("b", data) else: def _make_text_buffer(text): if isinstance(text, unicode): text = text.encode("mbcs") return array.array("b", text+'\0') # make an 'empty' buffer, ready for filling with cch characters. def _make_empty_text_buffer(cch): return _make_text_buffer("\0" * cch) if sys.version_info < (3,0): def _make_memory(ob): return str(buffer(ob)) def _make_bytes(sval): return sval else: def _make_memory(ob): return bytes(memoryview(ob)) def _make_bytes(sval): return sval.encode('ascii') try: from collections import namedtuple def _MakeResult(names_str, values): names = names_str.split() nt = namedtuple(names[0], names[1:]) return nt(*values) except ImportError: # no namedtuple support - just return the values as a normal tuple. def _MakeResult(names_str, values): return values def _GetMaskAndVal(val, default, mask, flag): if val is None: return mask, default else: if flag is not None: mask |= flag return mask, val _nmhdr_fmt = "PPi" if is64bit: _nmhdr_align_padding = "xxxx" else: _nmhdr_align_padding = "" _tvitem_fmt = "iPiiPiiiiP" def PackTVINSERTSTRUCT(parent, insertAfter, tvitem): tvitem_buf, extra = PackTVITEM(*tvitem) tvitem_buf = tvitem_buf.tostring() format = "PP%ds" % len(tvitem_buf) return struct.pack(format, parent, insertAfter, tvitem_buf), extra def PackTVITEM(hitem, state, stateMask, text, image, selimage, citems, param): extra = [] mask = 0 mask, hitem = _GetMaskAndVal(hitem, 0, mask, commctrl.TVIF_HANDLE) mask, state = _GetMaskAndVal(state, 0, mask, commctrl.TVIF_STATE) if not mask & commctrl.TVIF_STATE: stateMask = 0 mask, text = _GetMaskAndVal(text, None, mask, commctrl.TVIF_TEXT) mask, image = _GetMaskAndVal(image, 0, mask, commctrl.TVIF_IMAGE) mask, selimage = _GetMaskAndVal(selimage, 0, mask, commctrl.TVIF_SELECTEDIMAGE) mask, citems = _GetMaskAndVal(citems, 0, mask, commctrl.TVIF_CHILDREN) mask, param = _GetMaskAndVal(param, 0, mask, commctrl.TVIF_PARAM) if text is None: text_addr = text_len = 0 else: text_buffer = _make_text_buffer(text) text_len = len(text) extra.append(text_buffer) text_addr, _ = text_buffer.buffer_info() buf = struct.pack(_tvitem_fmt, mask, hitem, state, stateMask, text_addr, text_len, # text image, selimage, citems, param) return array.array("b", buf), extra def EmptyTVITEM(hitem, mask = None, text_buf_size=512): extra = [] if mask is None: mask = commctrl.TVIF_HANDLE | commctrl.TVIF_STATE | commctrl.TVIF_TEXT | \ commctrl.TVIF_IMAGE | commctrl.TVIF_SELECTEDIMAGE | \ commctrl.TVIF_CHILDREN | commctrl.TVIF_PARAM if mask & commctrl.TVIF_TEXT: text_buffer = _make_empty_text_buffer(text_buf_size) extra.append(text_buffer) text_addr, _ = text_buffer.buffer_info() else: text_addr = text_buf_size = 0 buf = struct.pack(_tvitem_fmt, mask, hitem, 0, 0, text_addr, text_buf_size, # text 0, 0, 0, 0) return array.array("b", buf), extra def UnpackTVITEM(buffer): item_mask, item_hItem, item_state, item_stateMask, item_textptr, item_cchText, item_image, item_selimage, item_cChildren, item_param = struct.unpack(_tvitem_fmt, buffer) if not (item_mask & commctrl.TVIF_TEXT): item_textptr = item_cchText = None if not (item_mask & commctrl.TVIF_CHILDREN): item_cChildren = None if not (item_mask & commctrl.TVIF_IMAGE): item_image = None if not (item_mask & commctrl.TVIF_PARAM): item_param = None if not (item_mask & commctrl.TVIF_SELECTEDIMAGE): item_selimage = None if not (item_mask & commctrl.TVIF_STATE): item_state = item_stateMask = None text = None #TexelElf: #The following lines spam ValueError exceptions when used in unpacking WM_NOTIFY messages. According to #MSDN at http://msdn.microsoft.com/en-us/library/windows/desktop/bb773544%28v=vs.85%29.aspx # "Only the mask, hItem, state, and lParam members of these (TVITEM) structures are valid." #As I have no need to extract the item text, I'm not fixing it by creating a separate UnpackTVITEM for WM_NOTIFY # if item_textptr: # text = win32gui.PyGetString(item_textptr) # else: # text = None return _MakeResult("TVITEM item_hItem item_state item_stateMask " "text item_image item_selimage item_cChildren item_param", (item_hItem, item_state, item_stateMask, text, item_image, item_selimage, item_cChildren, item_param)) # Unpack the lparm from a "TVNOTIFY" message def UnpackTVNOTIFY(lparam): item_size = struct.calcsize(_tvitem_fmt) format = _nmhdr_fmt + _nmhdr_align_padding if is64bit: format = format + "ixxxx" else: format = format + "i" format = format + "%ds%ds" % (item_size, item_size) buf = win32gui.PyGetMemory(lparam, struct.calcsize(format)) hwndFrom, id, code, action, buf_old, buf_new = struct.unpack(format, buf) item_old = UnpackTVITEM(buf_old) item_new = UnpackTVITEM(buf_new) return _MakeResult("TVNOTIFY hwndFrom id code action item_old item_new", (hwndFrom, id, code, action, item_old, item_new)) def UnpackTVDISPINFO(lparam): item_size = struct.calcsize(_tvitem_fmt) format = "PPi%ds" % (item_size,) buf = win32gui.PyGetMemory(lparam, struct.calcsize(format)) hwndFrom, id, code, buf_item = struct.unpack(format, buf) item = UnpackTVITEM(buf_item) return _MakeResult("TVDISPINFO hwndFrom id code item", (hwndFrom, id, code, item)) class DialogBase(object): def __init__(self): win32gui.InitCommonControls() self.hinst = win32gui.dllhandle self.current_hitem = None self.current_lparam = None self.title = "NBT Editor" self.modified = False def _RegisterWndClass(self): className = "NBTEditorWindowClass" message_map = {} wc = win32gui.WNDCLASS() wc.SetDialogProc() wc.hInstance = self.hinst wc.lpszClassName = className wc.style = win32con.CS_VREDRAW | win32con.CS_HREDRAW wc.hCursor = win32gui.LoadCursor( 0, win32con.IDC_ARROW ) wc.hbrBackground = win32con.COLOR_WINDOW + 1 wc.lpfnWndProc = message_map # C code: wc.cbWndExtra = DLGWINDOWEXTRA + sizeof(HBRUSH) + (sizeof(COLORREF)); wc.cbWndExtra = win32con.DLGWINDOWEXTRA + struct.calcsize("Pi") icon_flags = win32con.LR_DEFAULTSIZE wc.hIcon=0 try: classAtom = win32gui.RegisterClass(wc) except win32gui.error, err_info: if err_info.winerror!=winerror.ERROR_CLASS_ALREADY_EXISTS: raise return className def _GetDialogTemplate(self, dlgClassName): style = win32con.WS_BORDER | win32con.WS_VISIBLE | win32con.WS_CAPTION | win32con.WS_SYSMENU cs = win32con.WS_CHILD | win32con.WS_VISIBLE dlg = [ [self.title, (0, 0, 300, 322), style, None, (8, "MS Sans Serif"), None, dlgClassName], ] dlg.append([128, "&New", IDC_BUTTON_NEW, (0, 308, 30, 14), cs | win32con.BS_PUSHBUTTON]) dlg.append([128, "&Edit", IDC_BUTTON_EDIT, (30, 308, 30, 14), cs | win32con.BS_PUSHBUTTON]) dlg.append([128, "&Delete", IDC_BUTTON_DELETE, (60, 308, 30, 14), cs | win32con.BS_PUSHBUTTON]) dlg.append([128, "&Copy", IDC_BUTTON_COPY, (90, 308, 30, 14), cs | win32con.BS_PUSHBUTTON]) dlg.append([128, "C&ut", IDC_BUTTON_CUT, (120, 308, 30, 14), cs | win32con.BS_PUSHBUTTON]) dlg.append([128, "&Paste", IDC_BUTTON_PASTE, (150, 308, 30, 14), cs | win32con.BS_PUSHBUTTON]) dlg.append([128, "D&one", IDC_BUTTON_DONE, (200, 308, 50, 14), cs | win32con.BS_DEFPUSHBUTTON]) dlg.append([128, "C&ancel", win32con.IDCANCEL, (250, 308, 50, 14), cs | win32con.BS_PUSHBUTTON]) return dlg def _DoCreate(self, fn, hwnd): message_map = { win32con.WM_COMMAND: self.OnCommand, win32con.WM_NOTIFY: self.OnNotify, win32con.WM_INITDIALOG: self.OnInitDialog, win32con.WM_CLOSE: self.OnClose, win32con.WM_DESTROY: self.OnDestroy, } dlgClassName = self._RegisterWndClass() template = self._GetDialogTemplate(dlgClassName) return fn(self.hinst, template, hwnd, message_map) def _SetupList(self): global tilectr,tileents,ents,ticks child_style = win32con.WS_CHILD | win32con.WS_VISIBLE | win32con.WS_BORDER | win32con.WS_HSCROLL | win32con.WS_VSCROLL child_style |= commctrl.TVS_HASLINES | commctrl.TVS_HASBUTTONS | commctrl.TVS_LINESATROOT | commctrl.TVS_SHOWSELALWAYS self.hwndTree = win32gui.CreateWindow("SysTreeView32", None, child_style, 0, 0, 450, 500, self.hwnd, IDC_LISTBOX, self.hinst, None) if tileents: blarg,asdff = PackTVINSERTSTRUCT(0,commctrl.TVI_ROOT,(None,None,None,"TileEntities",LIST,LIST,None,1)) self.htreeTileEnts = win32gui.SendMessage(self.hwndTree, commctrl.TVM_INSERTITEM, 0, blarg) if ents: blarg,asdff = PackTVINSERTSTRUCT(0,commctrl.TVI_ROOT,(None,None,None,"Entities",LIST,LIST,None,2)) self.htreeEnts = win32gui.SendMessage(self.hwndTree, commctrl.TVM_INSERTITEM, 0, blarg) if ticks: blarg,asdff = PackTVINSERTSTRUCT(0,commctrl.TVI_ROOT,(None,None,None,"TileTicks",LIST,LIST,None,3)) self.htreeTicks = win32gui.SendMessage(self.hwndTree, commctrl.TVM_INSERTITEM, 0, blarg) pathdir = os.path.join(mcplatform.filtersDir,"NBT_icons") if os.path.isdir(pathdir): il = win32gui.ImageList_Create(12,16,commctrl.ILC_COLOR32 | commctrl.ILC_MASK,11,0) for i in iconnames: large, small = win32gui.ExtractIconEx(os.path.join(pathdir,i), 0, 1) win32gui.ImageList_ReplaceIcon(il, -1, large[0]) win32gui.DestroyIcon(small[0]) win32gui.DestroyIcon(large[0]) win32gui.SendMessage(self.hwndTree, commctrl.TVM_SETIMAGELIST, commctrl.TVSIL_NORMAL, il) if tileents: self.FillTree(tileents,self.htreeTileEnts,tilectr,tileentsids,True,True) if ents: self.FillTree(ents,self.htreeEnts,tilectr,entsids,True,True) if ticks: self.FillTree(ticks,self.htreeTicks,tilectr,ticksids,True,True) win32gui.UpdateWindow(self.hwnd) def OnInitDialog(self, hwnd, msg, wparam, lparam): self.hwnd = hwnd self._SetupList() def OnNotify(self, hwnd, msg, wparam, lparam): info = UnpackTVNOTIFY(lparam) if info.code == commctrl.NM_DBLCLK: self.EditTag() # elif info.code == commctrl.NM_RCLICK: # win32gui.SendMessage(self.hwnd, win32con.WM_COMMAND, IDC_BUTTON_NEW, 0) elif info.code == commctrl.TVN_KEYDOWN: if (win32api.GetKeyState(win32con.VK_CONTROL)>>15)&1 and (win32api.GetKeyState(67)>>15)&1: win32gui.SendMessage(self.hwnd, win32con.WM_COMMAND, IDC_BUTTON_COPY, 0) elif (win32api.GetKeyState(win32con.VK_CONTROL)>>15)&1 and (win32api.GetKeyState(88)>>15)&1: win32gui.SendMessage(self.hwnd, win32con.WM_COMMAND, IDC_BUTTON_CUT, 0) elif (win32api.GetKeyState(win32con.VK_CONTROL)>>15)&1 and (win32api.GetKeyState(86)>>15)&1: win32gui.SendMessage(self.hwnd, win32con.WM_COMMAND, IDC_BUTTON_PASTE, 0) elif (win32api.GetKeyState(win32con.VK_CONTROL)>>15)&1 and (win32api.GetKeyState(78)>>15)&1: win32gui.SendMessage(self.hwnd, win32con.WM_COMMAND, IDC_BUTTON_NEW, 0) elif (win32api.GetKeyState(win32con.VK_CONTROL)>>15)&1 and (win32api.GetKeyState(69)>>15)&1: win32gui.SendMessage(self.hwnd, win32con.WM_COMMAND, IDC_BUTTON_EDIT, 0) elif (win32api.GetKeyState(win32con.VK_DELETE)>>15)&1: win32gui.SendMessage(self.hwnd, win32con.WM_COMMAND, IDC_BUTTON_DELETE, 0) elif info.code == commctrl.TVN_SELCHANGED: if info.item_new.item_param > 0: self.current_hitem = info.item_new.item_hItem self.current_lparam = info.item_new.item_param return 1 def NewIDs(self,obj): obj[IDVAL] = GetID() if obj[NEXT]: for tag in obj[NEXT]: self.NewIDs(tag) else: return def OnCommand(self, hwnd, msg, wparam, lparam): global targettag, parenttag, clipboard, tilectr, newtag id = win32api.LOWORD(wparam) if id == IDC_BUTTON_DELETE: if self.current_lparam != 0 and self.current_lparam != None: win32gui.SetFocus(self.hwndTree) if self.DeleteItem(self.current_hitem, self.current_lparam): win32gui.PostMessage(self.hwndTree, commctrl.TVM_DELETEITEM, 0, self.current_hitem) self.modified = True elif id == IDC_BUTTON_NEW: if self.current_lparam != 0 and self.current_lparam != None: win32gui.SetFocus(self.hwndTree) if (self.current_lparam>>16) == 0: find = self.current_lparam&0xffff addtag = [0,0,COMPOUND,0,0,[]] if find == 1: self.FillTree(addtag,self.htreeTileEnts,0,tileentsids,False,True) tileents.append(addtag) elif find == 2: self.FillTree(addtag,self.htreeEnts,0,entsids,False,True) ents.append(addtag) elif find == 3: self.FillTree(addtag,self.htreeTicks,0,ticksids,False,True) ticks.append(addtag) self.modified = True return elif (self.current_lparam>>16): self.FindMe(self.current_lparam) w=NewDialog() if w.Create(self.hwnd): if newtag: insertop = newtag[3] tg = [0,0 if newtag[0] == "" else newtag[0],newtag[2],newtag[1],0,[]] if insertop: if targettag[TYPE] in (LIST, BYTE_ARRAY, INT_ARRAY): tg[NAME] = 0 if tg[TYPE] == COMPOUND: tg[VAL] = 0 self.NewIDs(tg) self.FillTree(tg,targettag[HITEM],self.current_lparam>>16,None,False) targettag[NEXT].append(tg) else: if parenttag[TYPE] in (LIST, BYTE_ARRAY, INT_ARRAY): tg[NAME] = 0 if tg[TYPE] == COMPOUND: tg[VAL] = 0 self.NewIDs(tg) self.FillTree(tg,parenttag[HITEM],self.current_lparam>>16,None,False) parenttag[NEXT].append(tg) self.modified = True elif id == IDC_BUTTON_COPY: if self.current_lparam != 0 and self.current_lparam != None: win32gui.SetFocus(self.hwndTree) del clipboard clipboard = [] if (self.current_lparam>>16) and (self.current_lparam&0xffff): self.FindMe(self.current_lparam) clipboard = deepcopy(targettag) else: find = self.current_lparam >> 16 if find in tileentsids: clipboard = deepcopy(tileents[tileentsids.index(find)]) elif find in entsids: clipboard = deepcopy(ents[entsids.index(find)]) elif find in ticksids: clipboard = deepcopy(ticks[ticksids.index(find)]) elif id == IDC_BUTTON_CUT: if self.current_lparam != 0 and self.current_lparam != None: win32gui.SetFocus(self.hwndTree) del clipboard clipboard = [] if (self.current_lparam>>16) and (self.current_lparam&0xffff): self.FindMe(self.current_lparam) clipboard = deepcopy(targettag) else: find = self.current_lparam >> 16 if find in tileentsids: clipboard = deepcopy(tileents[tileentsids.index(find)]) elif find in entsids: clipboard = deepcopy(ents[entsids.index(find)]) elif find in ticksids: clipboard = deepcopy(ticks[ticksids.index(find)]) if self.DeleteItem(self.current_hitem, self.current_lparam): win32gui.PostMessage(self.hwndTree, commctrl.TVM_DELETEITEM, 0, self.current_hitem) self.modified = True elif id == IDC_BUTTON_PASTE: if not clipboard: return if self.current_lparam != 0 and self.current_lparam != None: win32gui.SetFocus(self.hwndTree) if (self.current_lparam>>16): insertop = 0 self.FindMe(self.current_lparam) if targettag[TYPE] not in (COMPOUND, LIST, BYTE_ARRAY,INT_ARRAY): if targettag[TYPE] == clipboard[TYPE]: insertop = 0 else: if parenttag[TYPE] == COMPOUND: insertop = 0 elif parenttag[TYPE] in (LIST, BYTE_ARRAY, INT_ARRAY): win32gui.MessageBox(self.hwnd, "The copied tag's type does not match the List or Array's tag type. Lists and Arrays can only hold one tag type.", "Error", win32con.MB_OK | win32con.MB_ICONEXCLAMATION) return else: win32gui.MessageBox(self.hwnd, "Data corruption detected! Please press \"Cancel\" to avoid data loss.", "Error", win32con.MB_OK | win32con.MB_ICONEXCLAMATION) return else: if not targettag[NEXT] or targettag[TYPE] == COMPOUND: insertop = 1 elif targettag[NEXT]: if targettag[NEXT][0][TYPE] != clipboard[TYPE]: win32gui.MessageBox(self.hwnd, "The copied tag's type does not match the List or Array child tag type. Lists and Arrays can only hold one tag type.", "Error", win32con.MB_OK | win32con.MB_ICONEXCLAMATION) return else: insertop = 1 newtag = False if insertop: if targettag[TYPE] == COMPOUND: if clipboard[NAME] == "" or isinstance(clipboard[NAME], (int,long)): win32gui.MessageBox(self.hwnd, "Please specify a new tag name!","Error", win32con.MB_OK | win32con.MB_ICONEXCLAMATION) newtag = ["blah",insertop+1] else: for tag in targettag[NEXT]: if tag[NAME] == clipboard[NAME]: win32gui.MessageBox(self.hwnd, "There is already a \""+clipboard[NAME]+"\" tag! All tag names must be unique within a Compound tag!","Error", win32con.MB_OK | win32con.MB_ICONEXCLAMATION) newtag = ["blah",insertop+1] break elif targettag[TYPE] in (LIST, BYTE_ARRAY, INT_ARRAY): clipboard[NAME] = 0 if clipboard[TYPE] == COMPOUND: clipboard[VAL] = 0 if newtag: w = PesterDialog() if not w.Create(self.hwnd): return clipboard[NAME] = newtag[0] self.NewIDs(clipboard) self.FillTree(clipboard,targettag[HITEM],self.current_lparam>>16,None,False) targettag[NEXT].append(clipboard) self.modified = True else: if parenttag[TYPE] == COMPOUND: if clipboard[NAME] == "" or isinstance(clipboard[NAME], (int,long)): win32gui.MessageBox(self.hwnd, "Please specify a new tag name!","Error", win32con.MB_OK | win32con.MB_ICONEXCLAMATION) newtag = ["blah",insertop+1] else: for tag in parenttag[NEXT]: if tag[NAME] == clipboard[NAME]: win32gui.MessageBox(self.hwnd, "There is already a \""+clipboard[NAME]+"\" tag! All tag names must be unique within a Compound tag!","Error", win32con.MB_OK | win32con.MB_ICONEXCLAMATION) newtag = ["blah",insertop+1] break elif parenttag[TYPE] in (LIST, BYTE_ARRAY, INT_ARRAY): clipboard[NAME] = 0 if clipboard[TYPE] == COMPOUND: clipboard[VAL] = 0 if newtag: w = PesterDialog() if not w.Create(self.hwnd): return clipboard[NAME] = newtag[0] self.NewIDs(clipboard) self.FillTree(clipboard,parenttag[HITEM],self.current_lparam>>16,None,False) parenttag[NEXT].append(clipboard) self.modified = True elif ((self.current_lparam>>16) == 0) and (self.current_lparam&0xffff): if clipboard[TYPE] != COMPOUND: win32gui.MessageBox(self.hwnd, "Only TAG_Compounds can be pasted into base tags.", "Error", win32con.MB_OK | win32con.MB_ICONEXCLAMATION) return find = self.current_lparam&0xffff if find == 1: clipboard[NAME] = 0 self.NewIDs(clipboard) self.FillTree(clipboard,self.htreeTileEnts,tilectr,tileentsids,False,True) tileents.append(clipboard) elif find == 2: clipboard[NAME] = 0 self.NewIDs(clipboard) self.FillTree(clipboard,self.htreeEnts,tilectr,entsids,False,True) ents.append(clipboard) elif find == 3: clipboard[NAME] = 0 self.NewIDs(clipboard) self.FillTree(clipboard,self.htreeTicks,tilectr,ticksids,False,True) ticks.append(clipboard) self.modified = True elif id == IDC_BUTTON_DONE: win32gui.EndDialog(self.hwnd, 1) elif id == win32con.IDCANCEL: if self.modified: docancel = win32gui.MessageBox(self.hwnd, "Changes have been made. Discard these changes?", "Warning", win32con.MB_YESNO | win32con.MB_ICONWARNING) if docancel == win32con.IDNO: return win32gui.EndDialog(self.hwnd, 0) elif id == IDC_BUTTON_EDIT: win32gui.SetFocus(self.hwndTree) self.EditTag() return 1 def OnClose(self, hwnd, msg, wparam, lparam): raise NotImplementedError def OnDestroy(self, hwnd, msg, wparam, lparam): pass def FillTree(self, obj, parent, parentid, idlist, prevtype=True,autoincr=False): global tilectr if not obj: return if prevtype: for tag in obj: if autoincr: tilectr += 1 idlist.append(tilectr) parentid = tilectr if tag[TYPE] in (COMPOUND, LIST, BYTE_ARRAY, INT_ARRAY): if isinstance(tag[NAME], (int,long)): blarg,asdff = PackTVINSERTSTRUCT(parent,commctrl.TVI_LAST,(None,None,None,None,tag[TYPE],tag[TYPE],None,((parentid<<16)|tag[IDVAL]))) else: blarg,asdff = PackTVINSERTSTRUCT(parent,commctrl.TVI_SORT,(None,None,None,unicode(unicode(tag[NAME])),tag[TYPE],tag[TYPE],None,((parentid<<16)|tag[IDVAL]))) else: if isinstance(tag[NAME], (int,long)): blarg,asdff = PackTVINSERTSTRUCT(parent,commctrl.TVI_LAST,(None,None,None,unicode(unicode(tag[VAL])),tag[TYPE],tag[TYPE],None,((parentid<<16)|tag[IDVAL]))) else: blarg,asdff = PackTVINSERTSTRUCT(parent,commctrl.TVI_SORT,(None,None,None,unicode(unicode(tag[NAME])+": "+unicode(tag[VAL])),tag[TYPE],tag[TYPE],None,((parentid<<16)|tag[IDVAL]))) tag[HITEM] = win32gui.SendMessage(self.hwndTree, commctrl.TVM_INSERTITEM, 0, blarg) if tag[TYPE] in (COMPOUND, LIST, BYTE_ARRAY, INT_ARRAY): self.FillTree(tag[NEXT],tag[HITEM],parentid,idlist,True) else: if autoincr: tilectr += 1 idlist.append(tilectr) parentid = tilectr if obj[TYPE] in (COMPOUND, LIST, BYTE_ARRAY, INT_ARRAY): if isinstance(obj[NAME], (int,long)): blarg,asdff = PackTVINSERTSTRUCT(parent,commctrl.TVI_LAST,(None,None,None,None,obj[TYPE],obj[TYPE],None,((parentid<<16)|obj[IDVAL]))) else: blarg,asdff = PackTVINSERTSTRUCT(parent,commctrl.TVI_SORT,(None,None,None,unicode(unicode(obj[NAME])),obj[TYPE],obj[TYPE],None,((parentid<<16)|obj[IDVAL]))) else: if isinstance(obj[NAME], (int,long)): blarg,asdff = PackTVINSERTSTRUCT(parent,commctrl.TVI_LAST,(None,None,None,unicode(unicode(obj[VAL])),obj[TYPE],obj[TYPE],None,((parentid<<16)|obj[IDVAL]))) else: blarg,asdff = PackTVINSERTSTRUCT(parent,commctrl.TVI_SORT,(None,None,None,unicode(unicode(obj[NAME])+unicode(": ")+unicode(obj[VAL])),obj[TYPE],obj[TYPE],None,((parentid<<16)|obj[IDVAL]))) obj[HITEM] = win32gui.SendMessage(self.hwndTree, commctrl.TVM_INSERTITEM, 0, blarg) if obj[TYPE] in (COMPOUND, LIST, BYTE_ARRAY, INT_ARRAY): self.FillTree(obj[NEXT],obj[HITEM],parentid,idlist,True) def DeleteItem(self, hitem, lparam): parentid = lparam>>16 listitem = lparam&0xFFFF if parentid != 0 and listitem == 0: if parentid in tileentsids: del tileents[tileentsids.index(parentid)] del tileentsids[tileentsids.index(parentid)] return True elif parentid in entsids: del ents[entsids.index(parentid)] del entsids[entsids.index(parentid)] return True elif parentid in ticksids: del ticks[ticksids.index(parentid)] del ticksids[ticksids.index(parentid)] return True return False if parentid in tileentsids: if self.DelTag(tileents[tileentsids.index(parentid)][NEXT],listitem): return True if parentid in entsids: if self.DelTag(ents[entsids.index(parentid)][NEXT],listitem): return True if parentid in ticksids: if self.DelTag(ticks[ticksids.index(parentid)][NEXT],listitem): return True return False def DelTag(self,obj,val): for tag in obj: if tag[IDVAL] == val: obj.remove(tag) return True if tag[NEXT]: if self.DelTag(tag[NEXT],val): return True else: return False def FindMe(self,lparam): global targettag, parenttag, ents, entsids, tileents, tileentsids, ticks, ticksids targettag = None parenttag = None parentid = lparam>>16 listitem = lparam&0xFFFF if parentid in tileentsids: parenttag = tileents[tileentsids.index(parentid)] if listitem == 0: targettag = tileents[tileentsids.index(parentid)] else: self.FindTag(tileents[tileentsids.index(parentid)][NEXT],listitem) return if parentid in entsids: parenttag = ents[entsids.index(parentid)] if listitem == 0: targettag = ents[entsids.index(parentid)] else: self.FindTag(ents[entsids.index(parentid)][NEXT],listitem) return if parentid in ticksids: parenttag = ticks[ticksids.index(parentid)] if listitem == 0: targettag = ticks[ticksids.index(parentid)] else: self.FindTag(ticks[ticksids.index(parentid)][NEXT],listitem) return def FindTag(self,obj,val,old=None): global targettag, parenttag for tag in obj: if tag[IDVAL] == val: targettag = tag if old != None: parenttag = old return if tag[NEXT]: self.FindTag(tag[NEXT],val, tag) else: return def EditTag(self): global parenttag, targettag, newtag if (self.current_lparam>>16) and (self.current_lparam&0xffff): self.FindMe(self.current_lparam) else: win32gui.MessageBox(self.hwnd, "Base tags cannot be Edited.", "Error", win32con.MB_OK | win32con.MB_ICONEXCLAMATION) return if parenttag[TYPE] == LIST and targettag[TYPE] == COMPOUND: win32gui.MessageBox(self.hwnd, "This tag cannot be Edited in this location.", "Error", win32con.MB_OK | win32con.MB_ICONEXCLAMATION) return else: w=EditDialog() if w.Create(self.hwnd): if newtag: self.modified = True if newtag[0] != "": targettag[NAME] = newtag[0] if newtag[2] in (COMPOUND, LIST, BYTE_ARRAY, INT_ARRAY): targettag[VAL] = 0 else: targettag[VAL] = newtag[1] targettag[TYPE] = newtag[2] if targettag[TYPE] in (COMPOUND, LIST, BYTE_ARRAY, INT_ARRAY): if isinstance(targettag[NAME], (int,long)): blarg,asdff = PackTVITEM(targettag[HITEM],None,None,None,targettag[TYPE],targettag[TYPE],None,None) else: blarg,asdff = PackTVITEM(targettag[HITEM],None,None,unicode(unicode(targettag[NAME])),targettag[TYPE],targettag[TYPE],None,None) else: if isinstance(targettag[VAL], (str,unicode)): targettag[VAL] = targettag[VAL].decode("unicode-escape") if isinstance(targettag[NAME], (int,long)): blarg,asdff = PackTVITEM(targettag[HITEM],None,None,unicode(unicode(targettag[VAL])),targettag[TYPE],targettag[TYPE],None,None) else: blarg,asdff = PackTVITEM(targettag[HITEM],None,None,unicode(unicode(targettag[NAME])+": "+unicode(targettag[VAL])),targettag[TYPE],targettag[TYPE],None,None) win32gui.SendMessage(self.hwndTree, commctrl.TVM_SETITEM, 0, blarg) class Dialog(DialogBase): def Create(self,hwnd): return self._DoCreate(win32gui.DialogBoxIndirect,hwnd) def OnClose(self, hwnd, msg, wparam, lparam): if self.modified: docancel = win32gui.MessageBox(self.hwnd, "Changes have been made. Discard these changes?", "Warning", win32con.MB_YESNO | win32con.MB_ICONWARNING) if docancel == win32con.IDNO: return win32gui.EndDialog(hwnd, 0) def CreateDialog(hwnd): w=Dialog() return w.Create(hwnd) class EditDialog(DialogBase): def __init__(self): super(EditDialog,self).__init__() self.title = "Edit Tag" def RangeCheck(self,val,nttype): retval = success = -1 if nttype == LONG: try: retval = long(val) except ValueError: win32gui.MessageBox(self.hwnd, "Could not convert value \""+val+"\" to TAG_Long", "Error", win32con.MB_OK | win32con.MB_ICONEXCLAMATION) return (retval, success) elif nttype == INT: try: retval = int(val) except ValueError: win32gui.MessageBox(self.hwnd, "Could not convert value \""+val+"\" to TAG_Int", "Error", win32con.MB_OK | win32con.MB_ICONEXCLAMATION) return (retval, success) if retval > 2147483647: retval = 2147483647 elif retval < -2147483648: retval = -2147483648 elif nttype == SHORT: try: retval = int(val) except ValueError: win32gui.MessageBox(self.hwnd, "Could not convert value \""+val+"\" to TAG_Short", "Error", win32con.MB_OK | win32con.MB_ICONEXCLAMATION) return (retval, success) if retval > 32767: retval = 32767 elif retval < -32768: retval = -32768 elif nttype == BYTE: try: retval = int(val) except ValueError: win32gui.MessageBox(self.hwnd, "Could not convert value \""+val+"\" to TAG_Byte", "Error", win32con.MB_OK | win32con.MB_ICONEXCLAMATION) return (retval, success) if retval > 127: retval = 127 elif retval < -128: retval = -128 elif nttype == DOUBLE: try: retval = float(val) except ValueError: win32gui.MessageBox(self.hwnd, "Could not convert value \""+val+"\" to TAG_Double", "Error", win32con.MB_OK | win32con.MB_ICONEXCLAMATION) return (retval, success) elif nttype == FLOAT: try: retval = float(val) except ValueError: win32gui.MessageBox(self.hwnd, "Could not convert value \""+val+"\" to TAG_Float", "Error", win32con.MB_OK | win32con.MB_ICONEXCLAMATION) return (retval, success) return (retval, 1) def OnCommand(self, hwnd, msg, wparam, lparam): global parenttag, targettag, newtag id = win32api.LOWORD(wparam) if id == CDC_BUTTON_DONE: nameval = win32gui.GetWindowText(self.nameedit) if parenttag[TYPE] == COMPOUND: if targettag[NAME] != nameval: for tag in parenttag[NEXT]: if tag[NAME] == nameval: win32gui.MessageBox(self.hwnd, "There is already a \""+nameval+"\" tag! All tag names must be unique within a Compound tag!","Error", win32con.MB_OK | win32con.MB_ICONEXCLAMATION) return valval = win32gui.GetWindowText(self.valueedit) for button, label in self.buttons: if win32gui.SendMessage(button, win32con.BM_GETCHECK, 0, 0): nttype = self.buttons.index((button,label)) break if nttype in (COMPOUND, LIST, BYTE_ARRAY, INT_ARRAY): newval = 0 elif nttype == STRING: newval = valval else: newval, result = self.RangeCheck(valval, nttype) if result == -1: return 1 newtag = [nameval,newval,nttype] win32gui.EndDialog(self.hwnd, 1) elif id == win32con.IDCANCEL: win32gui.EndDialog(self.hwnd, 0) elif id == CDC_BYTERADIO: for button, label in self.buttons: if button == lparam: if self.buttons.index((button,label)) in (COMPOUND,LIST,BYTE_ARRAY,INT_ARRAY): win32gui.EnableWindow(self.valuelabel,False) win32gui.EnableWindow(self.valueedit,False) else: win32gui.EnableWindow(self.valuelabel,True) win32gui.EnableWindow(self.valueedit,True) break return 1 def DisableStuff(self): global parenttag, targettag if parenttag[TYPE] not in (LIST, BYTE_ARRAY, INT_ARRAY): win32gui.SetWindowText(self.nameedit,unicode(targettag[NAME])) if targettag[TYPE] not in (COMPOUND, LIST, BYTE_ARRAY, INT_ARRAY): win32gui.SetWindowText(self.valueedit,unicode(targettag[VAL])) win32gui.SendMessage(self.buttons[targettag[TYPE]][0],win32con.BM_SETCHECK,True,None) if targettag[TYPE] in (COMPOUND, LIST, BYTE_ARRAY, INT_ARRAY): win32gui.EnableWindow(self.valuelabel,False) win32gui.EnableWindow(self.valueedit,False) for button, label in self.buttons: if self.buttons.index((button,label)) == targettag[TYPE]: continue win32gui.EnableWindow(label,False) win32gui.EnableWindow(button,False) if parenttag[TYPE] in (LIST, BYTE_ARRAY, INT_ARRAY): win32gui.EnableWindow(self.namelabel,False) win32gui.EnableWindow(self.nameedit,False) for button, label in self.buttons: if self.buttons.index((button,label)) == targettag[TYPE]: continue win32gui.EnableWindow(label,False) win32gui.EnableWindow(button,False) if targettag[TYPE] not in (COMPOUND, LIST, BYTE_ARRAY, INT_ARRAY, STRING): win32gui.SendMessage(self.valueedit,win32con.EM_SETSEL,0,-1) win32gui.SetFocus(self.valueedit) def _SetupList(self): global parenttag, targettag self.groupBox = self.hwnd pathdir = os.path.join(mcplatform.filtersDir,"NBT_icons") if os.path.isdir(pathdir): icons = [] for i in iconnames: icons.append(win32gui.LoadImage(0,os.path.join(pathdir,i),1,0,0,0x00000010)) self.hfont = win32gui.SendMessage(self.hwnd, win32con.WM_GETFONT, 0, 0) self.buttons = [] child_style = win32con.WS_CHILD | win32con.WS_VISIBLE | win32con.BS_AUTORADIOBUTTON | win32con.BS_ICON | win32con.BS_RIGHTBUTTON br = win32gui.CreateWindow("BUTTON", None, child_style, 1, 1, 31, 16, self.groupBox, CDC_BYTERADIO, self.hinst, None) bl = win32gui.CreateWindow("static", "TAG_Compound", win32con.WS_CHILD | win32con.WS_VISIBLE, 33, 1, 80, 16, self.groupBox, 0, self.hinst, None) self.buttons.append((br,bl)) child_style = win32con.WS_CHILD | win32con.WS_VISIBLE | win32con.BS_AUTORADIOBUTTON | win32con.BS_ICON | win32con.BS_RIGHTBUTTON br = win32gui.CreateWindow("BUTTON", None, child_style, 1, 19, 31, 16, self.groupBox, CDC_BYTERADIO, self.hinst, None) bl = win32gui.CreateWindow("static", "TAG_List", win32con.WS_CHILD | win32con.WS_VISIBLE, 33, 19, 80, 16, self.groupBox, 0, self.hinst, None) self.buttons.append((br,bl)) child_style = win32con.WS_CHILD | win32con.WS_VISIBLE | win32con.BS_AUTORADIOBUTTON | win32con.BS_ICON | win32con.BS_RIGHTBUTTON br = win32gui.CreateWindow("BUTTON", None, child_style, 1, 35, 31, 16, self.groupBox, CDC_BYTERADIO, self.hinst, None) bl = win32gui.CreateWindow("static", "TAG_Byte_Array", win32con.WS_CHILD | win32con.WS_VISIBLE, 33, 35, 80, 16, self.groupBox, 0, self.hinst, None) self.buttons.append((br,bl)) child_style = win32con.WS_CHILD | win32con.WS_VISIBLE | win32con.BS_AUTORADIOBUTTON | win32con.BS_ICON | win32con.BS_RIGHTBUTTON br = win32gui.CreateWindow("BUTTON", None, child_style, 120, 1, 31, 16, self.groupBox, CDC_BYTERADIO, self.hinst, None) bl = win32gui.CreateWindow("static", "TAG_Int_Array", win32con.WS_CHILD | win32con.WS_VISIBLE, 152, 1, 80, 16, self.groupBox, 0, self.hinst, None) self.buttons.append((br,bl)) child_style = win32con.WS_CHILD | win32con.WS_VISIBLE | win32con.BS_AUTORADIOBUTTON | win32con.BS_ICON | win32con.BS_RIGHTBUTTON br = win32gui.CreateWindow("BUTTON", None, child_style, 120, 19, 31, 16, self.groupBox, CDC_BYTERADIO, self.hinst, None) bl = win32gui.CreateWindow("static", "TAG_String", win32con.WS_CHILD | win32con.WS_VISIBLE, 152, 19, 80, 16, self.groupBox, 0, self.hinst, None) self.buttons.append((br,bl)) child_style = win32con.WS_CHILD | win32con.WS_VISIBLE | win32con.BS_AUTORADIOBUTTON | win32con.BS_ICON | win32con.BS_RIGHTBUTTON br = win32gui.CreateWindow("BUTTON", None, child_style, 120, 35, 31, 16, self.groupBox, CDC_BYTERADIO, self.hinst, None) bl = win32gui.CreateWindow("static", "TAG_Long", win32con.WS_CHILD | win32con.WS_VISIBLE, 152, 35, 80, 16, self.groupBox, 0, self.hinst, None) self.buttons.append((br,bl)) child_style = win32con.WS_CHILD | win32con.WS_VISIBLE | win32con.BS_AUTORADIOBUTTON | win32con.BS_ICON | win32con.BS_RIGHTBUTTON br = win32gui.CreateWindow("BUTTON", None, child_style, 239, 1, 31, 16, self.groupBox, CDC_BYTERADIO, self.hinst, None) bl = win32gui.CreateWindow("static", "TAG_Int", win32con.WS_CHILD | win32con.WS_VISIBLE, 271, 1, 80, 16, self.groupBox, 0, self.hinst, None) self.buttons.append((br,bl)) child_style = win32con.WS_CHILD | win32con.WS_VISIBLE | win32con.BS_AUTORADIOBUTTON | win32con.BS_ICON | win32con.BS_RIGHTBUTTON br = win32gui.CreateWindow("BUTTON", None, child_style, 239, 19, 31, 16, self.groupBox, CDC_BYTERADIO, self.hinst, None) bl = win32gui.CreateWindow("static", "TAG_Short", win32con.WS_CHILD | win32con.WS_VISIBLE, 271, 19, 80, 16, self.groupBox, 0, self.hinst, None) self.buttons.append((br,bl)) child_style = win32con.WS_CHILD | win32con.WS_VISIBLE | win32con.BS_AUTORADIOBUTTON | win32con.BS_ICON | win32con.BS_RIGHTBUTTON br = win32gui.CreateWindow("BUTTON", None, child_style, 239, 35, 31, 16, self.groupBox, CDC_BYTERADIO, self.hinst, None) bl = win32gui.CreateWindow("static", "TAG_Byte", win32con.WS_CHILD | win32con.WS_VISIBLE, 271, 35, 80, 16, self.groupBox, 0, self.hinst, None) self.buttons.append((br,bl)) child_style = win32con.WS_CHILD | win32con.WS_VISIBLE | win32con.BS_AUTORADIOBUTTON | win32con.BS_ICON | win32con.BS_RIGHTBUTTON br = win32gui.CreateWindow("BUTTON", None, child_style, 338, 1, 31, 16, self.groupBox, CDC_BYTERADIO, self.hinst, None) bl = win32gui.CreateWindow("static", "TAG_Double", win32con.WS_CHILD | win32con.WS_VISIBLE, 370, 1, 65, 16, self.groupBox, 0, self.hinst, None) self.buttons.append((br,bl)) child_style = win32con.WS_CHILD | win32con.WS_VISIBLE | win32con.BS_AUTORADIOBUTTON | win32con.BS_ICON | win32con.BS_RIGHTBUTTON br = win32gui.CreateWindow("BUTTON", None, child_style, 338, 19, 31, 16, self.groupBox, CDC_BYTERADIO, self.hinst, None) bl = win32gui.CreateWindow("static", "TAG_Float", win32con.WS_CHILD | win32con.WS_VISIBLE, 370, 19, 60, 16, self.groupBox, 0, self.hinst, None) self.buttons.append((br,bl)) self.namelabel = win32gui.CreateWindow("static", "Tag Name:", win32con.WS_CHILD | win32con.WS_VISIBLE, 1, 60, 60, 16, self.hwnd, 0, self.hinst, None) self.nameedit = win32gui.CreateWindow("edit", None, win32con.WS_CHILD | win32con.WS_VISIBLE | win32con.WS_BORDER | win32con.ES_NOHIDESEL, 60, 57, 200, 20, self.hwnd, 0, self.hinst, None) win32gui.SendMessage(self.namelabel, win32con.WM_SETFONT, self.hfont, 0) win32gui.SendMessage(self.nameedit, win32con.WM_SETFONT, self.hfont, 0) self.valuelabel = win32gui.CreateWindow("static", "Tag Value:", win32con.WS_CHILD | win32con.WS_VISIBLE, 1, 82, 58, 16, self.hwnd, 0, self.hinst, None) self.valueedit = win32gui.CreateWindow("edit", None, win32con.WS_CHILD | win32con.WS_VISIBLE | win32con.WS_BORDER | win32con.ES_AUTOHSCROLL | win32con.ES_NOHIDESEL, 60, 79, 370, 20, self.hwnd, 0, self.hinst, None) win32gui.SendMessage(self.valuelabel, win32con.WM_SETFONT, self.hfont, 0) win32gui.SendMessage(self.valueedit, win32con.WM_SETFONT, self.hfont, 0) for button, label in self.buttons: win32gui.SendMessage(label, win32con.WM_SETFONT, self.hfont, 0) for i in xrange(len(self.buttons)): win32gui.SendMessage(self.buttons[i][0], win32con.BM_SETIMAGE, win32con.IMAGE_ICON, icons[i]) self.DisableStuff() def _RegisterWndClass(self): className = "EditTagClass" message_map = {} wc = win32gui.WNDCLASS() wc.SetDialogProc() wc.hInstance = self.hinst wc.lpszClassName = className wc.style = win32con.CS_VREDRAW | win32con.CS_HREDRAW wc.hCursor = win32gui.LoadCursor( 0, win32con.IDC_ARROW ) wc.hbrBackground = win32con.COLOR_WINDOW + 1 wc.lpfnWndProc = message_map wc.cbWndExtra = win32con.DLGWINDOWEXTRA + struct.calcsize("Pi") icon_flags = win32con.LR_DEFAULTSIZE wc.hIcon=0 try: classAtom = win32gui.RegisterClass(wc) except win32gui.error, err_info: if err_info.winerror!=winerror.ERROR_CLASS_ALREADY_EXISTS: raise return className def _GetDialogTemplate(self, dlgClassName): style = win32con.WS_BORDER | win32con.WS_VISIBLE | win32con.WS_CAPTION | win32con.WS_SYSMENU cs = win32con.WS_CHILD | win32con.WS_VISIBLE dlg = [ [self.title, (0, 0, 290, 62), style, None, (8, "MS Sans Serif"), None, dlgClassName], ] s = cs | win32con.WS_TABSTOP dlg.append([128, "&Done", CDC_BUTTON_DONE, (180, 33, 50, 14), s | win32con.BS_DEFPUSHBUTTON]) s = win32con.BS_PUSHBUTTON | s dlg.append([128, "&Cancel", win32con.IDCANCEL, (230, 33, 50, 14), s]) return dlg def _DoCreate(self, fn, hwnd): message_map = { win32con.WM_COMMAND: self.OnCommand, win32con.WM_NOTIFY: self.OnNotify, win32con.WM_INITDIALOG: self.OnInitDialog, win32con.WM_CLOSE: self.OnClose, win32con.WM_DESTROY: self.OnDestroy, } dlgClassName = self._RegisterWndClass() template = self._GetDialogTemplate(dlgClassName) return fn(self.hinst, template, hwnd, message_map) def Create(self, hwnd): return self._DoCreate(win32gui.DialogBoxIndirect, hwnd) def OnClose(self, hwnd, msg, wparam, lparam): win32gui.EndDialog(hwnd, 0) class NewDialog(EditDialog): def __init__(self): super(NewDialog,self).__init__() self.title = "New Tag" def DisableStuff(self): global parenttag, targettag if targettag[TYPE] not in (COMPOUND, LIST, BYTE_ARRAY,INT_ARRAY): #not scalar, so can't insert below if parenttag[TYPE] == COMPOUND: #compounds can contain aggregate data types self.insertop = 0 newtagtype = -1 newtagname = True elif parenttag[TYPE] in (LIST, BYTE_ARRAY, INT_ARRAY): #lists/arrays can't disableall = True newtagname = False newtagtype = targettag[TYPE] self.insertop = 0 else: #inserting into child container if not targettag[NEXT] or targettag[TYPE] == COMPOUND: #no children or is a compound, takes any tag type self.insertop = 1 newtagtype = -1 newtagname = True elif targettag[NEXT]: if targettag[TYPE] in (LIST, BYTE_ARRAY, INT_ARRAY): self.insertop = 1 newtagtype = targettag[NEXT][0][TYPE] newtagname = False disableall = True if not newtagname: win32gui.EnableWindow(self.namelabel,False) win32gui.EnableWindow(self.nameedit,False) if newtagtype != -1: if newtagtype in (COMPOUND, LIST, BYTE_ARRAY, INT_ARRAY): win32gui.EnableWindow(self.valuelabel,False) win32gui.EnableWindow(self.valueedit,False) if disableall: for button, label in self.buttons: if self.buttons.index((button,label)) == newtagtype: continue win32gui.EnableWindow(label,False) win32gui.EnableWindow(button,False) win32gui.SendMessage(self.buttons[newtagtype][0],win32con.BM_SETCHECK,True,None) def OnCommand(self, hwnd, msg, wparam, lparam): global parenttag, targettag, newtag, newtagtype id = win32api.LOWORD(wparam) if id == CDC_BUTTON_DONE: nameval = win32gui.GetWindowText(self.nameedit) if self.insertop: if targettag[TYPE] == COMPOUND: if nameval == "": win32gui.MessageBox(self.hwnd, "No name specified!","Error", win32con.MB_OK | win32con.MB_ICONEXCLAMATION) return for tag in targettag[NEXT]: if tag[NAME] == nameval: win32gui.MessageBox(self.hwnd, "There is already a \""+nameval+"\" tag! All tag names must be unique within a Compound tag!","Error", win32con.MB_OK | win32con.MB_ICONEXCLAMATION) return else: if parenttag[TYPE] == COMPOUND: if nameval == "": win32gui.MessageBox(self.hwnd, "No name specified!","Error", win32con.MB_OK | win32con.MB_ICONEXCLAMATION) return for tag in parenttag[NEXT]: if tag[NAME] == nameval: win32gui.MessageBox(self.hwnd, "There is already a \""+nameval+"\" tag! All tag names must be unique within a Compound tag!","Error", win32con.MB_OK | win32con.MB_ICONEXCLAMATION) return valval = win32gui.GetWindowText(self.valueedit) valval = valval.decode("unicode-escape") for button, label in self.buttons: if win32gui.SendMessage(button, win32con.BM_GETCHECK, 0, 0): nttype = self.buttons.index((button,label)) break else: win32gui.MessageBox(self.hwnd, "No tag type specified!","Error", win32con.MB_OK | win32con.MB_ICONEXCLAMATION) return if nttype in (COMPOUND, LIST, BYTE_ARRAY, INT_ARRAY): newval = 0 elif nttype == STRING: newval = valval else: newval, result = self.RangeCheck(valval, nttype) if result == -1: return 1 newtag = [nameval,newval,nttype,self.insertop] win32gui.EndDialog(self.hwnd, 1) else: super(NewDialog,self).OnCommand(hwnd, msg, wparam, lparam) return 1 class PesterDialog(EditDialog): def __init__(self): super(PesterDialog,self).__init__() self.title = "Input New Tag Name" def DisableStuff(self): win32gui.EnableWindow(self.namelabel,True) win32gui.EnableWindow(self.nameedit,True) win32gui.EnableWindow(self.valuelabel,False) win32gui.EnableWindow(self.valueedit,False) for button, label in self.buttons: win32gui.EnableWindow(label,False) win32gui.EnableWindow(button,False) def OnCommand(self, hwnd, msg, wparam, lparam): global newtag id = win32api.LOWORD(wparam) if id == CDC_BUTTON_DONE: insertop = newtag[1]-1 nameval = win32gui.GetWindowText(self.nameedit) if insertop: if targettag[TYPE] == COMPOUND: if nameval == "": win32gui.MessageBox(self.hwnd, "No name specified!","Error", win32con.MB_OK | win32con.MB_ICONEXCLAMATION) return for tag in targettag[NEXT]: if tag[NAME] == nameval: win32gui.MessageBox(self.hwnd, "There is already a \""+nameval+"\" tag! All tag names must be unique within a Compound tag!","Error", win32con.MB_OK | win32con.MB_ICONEXCLAMATION) return else: if parenttag[TYPE] == COMPOUND: if nameval == "": win32gui.MessageBox(self.hwnd, "No name specified!","Error", win32con.MB_OK | win32con.MB_ICONEXCLAMATION) return for tag in parenttag[NEXT]: if tag[NAME] == nameval: win32gui.MessageBox(self.hwnd, "There is already a \""+nameval+"\" tag! All tag names must be unique within a Compound tag!","Error", win32con.MB_OK | win32con.MB_ICONEXCLAMATION) return newtag = [nameval,insertop] win32gui.EndDialog(self.hwnd, 1) else: super(PesterDialog,self).OnCommand(hwnd, msg, wparam, lparam) return 1 def Deserialize(obj, tag_list, tgtype): if tgtype == COMPOUND: for tag in sorted(obj.keys(),cmp=lambda x,y: cmp(x.lower(), y.lower())): if (type(obj[tag]) is TAG_Compound) or (type(obj[tag]) is TAG_List): tag_list.append([0,tag,tagtypes[type(obj[tag])],0,GetID(),[]]) Deserialize(obj[tag],tag_list[-1][NEXT],tagtypes[type(obj[tag])]) elif type(obj[tag]) is TAG_Int_Array or type(obj[tag]) is TAG_Byte_Array: tag_list.append([0,tag,tagtypes[type(obj[tag])],0,GetID(),[]]) for i in obj[tag].value: if type(obj[tag]) is TAG_Int_Array: tag_list[-1][NEXT].append([0,0,INT,i,GetID(),[]]) else: tag_list[-1][NEXT].append([0,0,BYTE,i,GetID(),[]]) else: tag_list.append([0,tag,tagtypes[type(obj[tag])],obj[tag].value,GetID(),[]]) elif tgtype == LIST: for index in range(0,len(obj)): if type(obj[index]) is TAG_Compound or type(obj[index]) is TAG_List: tag_list.append([0,index,tagtypes[type(obj[index])],0,GetID(),[]]) Deserialize(obj[index],tag_list[-1][NEXT],tagtypes[type(obj[index])]) elif type(obj[index]) is TAG_Int_Array or type(obj[index]) is TAG_Byte_Array: tag_list.append([0,index,tagtypes[type(obj[index])],0,GetID(),[]]) for i in obj[index].value: if type(obj[index]) is TAG_Int_Array: tag_list[-1][NEXT].append([0,index,INT,i,GetID(),[]]) else: tag_list[-1][NEXT].append([0,index,BYTE,i,GetID(),[]]) else: tag_list.append([0,index,tagtypes[type(obj[index])],obj[index].value,GetID(),[]]) return tag_list def GetEnt(obj): entlist = [0,0,COMPOUND,0,0,[]] entlist[NEXT] = Deserialize(obj,[],COMPOUND) return entlist def NBT_Tag(type, value): if type == COMPOUND: return TAG_Compound() elif type == LIST: return TAG_List() elif type == BYTE_ARRAY: return TAG_Byte_Array(value) elif type == INT_ARRAY: return TAG_Int_Array(value) elif type == STRING: return TAG_String(value) elif type == LONG: return TAG_Long(value) elif type == INT: return TAG_Int(value) elif type == SHORT: return TAG_Short(value) elif type == BYTE: return TAG_Byte(value) elif type == DOUBLE: return TAG_Double(value) elif type == FLOAT: return TAG_Float(value) def GetNBT(obj): entlist = TAG_List() cmpnd = TAG_Compound() for o in obj: retval = Serialize(o,cmpnd) newervar = deepcopy(retval) entlist.append(newervar) del newervar return entlist def Serialize(obj,nbt,scalar=False): if obj[TYPE] in (COMPOUND, LIST, BYTE_ARRAY, INT_ARRAY): if isinstance(obj[NAME], (int,long)): nbt = NBT_Tag(obj[TYPE],0) nextnbt = nbt else: nbt[obj[NAME]] = NBT_Tag(obj[TYPE],0) nextnbt = nbt[obj[NAME]] if obj[NEXT]: if obj[TYPE] == COMPOUND: for o in obj[NEXT]: nextnbt = Serialize(o,nextnbt) elif obj[TYPE] == LIST: for o in obj[NEXT]: nbt[obj[NAME]].append(Serialize(o,0,True)) elif obj[TYPE] in (BYTE_ARRAY, INT_ARRAY): num = len(obj[NEXT]) if obj[TYPE] == INT_ARRAY: buff = zeros(num,">u4") else: buff = zeros(num,"uint8") nmpyctr = 0 for o in obj[NEXT]: buff[nmpyctr] = o[VAL] nmpyctr += 1 nbt[obj[NAME]] = NBT_Tag(obj[TYPE],buff) else: if scalar: return NBT_Tag(obj[TYPE],obj[VAL]) nbt[obj[NAME]] = NBT_Tag(obj[TYPE],obj[VAL]) return nbt def perform(level, box, options): global tileents, ents, canceled, tileentsids, entsids, idcounter, tilectr, clipboard dotileentities = options["TileEntities"] doentities = options["Entities"] doticks = options["TileTicks"] if not dotileentities and not doentities and not doticks: print "Nothing to do!" return idcounter = 0 tilectr = 1 canceled = True tileents[:] = [] ents[:] = [] tileentsids[:] = [] entsids[:] = [] ticks[:] = [] ticksids[:] = [] clipboard[:] = [] tileentstodelete = [] entstodelete = [] tickstodelete = [] for (chunk, slices, point) in level.getChunkSlices(box): if dotileentities: for e in chunk.TileEntities: x = e["x"].value y = e["y"].value z = e["z"].value if (x,y,z) in box: tileentstodelete.append((chunk,e)) tileents.append(GetEnt(e)) if doentities: for e in chunk.Entities: x = e["Pos"][0].value y = e["Pos"][1].value z = e["Pos"][2].value if (x,y,z) in box: entstodelete.append((chunk,e)) ents.append(GetEnt(e)) if doticks: if "TileTicks" in chunk.root_tag["Level"]: for e in chunk.root_tag["Level"]["TileTicks"]: x = e["x"].value y = e["y"].value z = e["z"].value if (x,y,z) in box: tickstodelete.append((chunk,e)) ticks.append(GetEnt(e)) if tileents or ents or ticks: if not CreateDialog(win32gui.GetForegroundWindow()): print "Edit operation was canceled; no changes were made." return tileentities = GetNBT(tileents) entities = GetNBT(ents) tick = GetNBT(ticks) for (chunk, entity) in tileentstodelete: chunk.TileEntities.remove(entity) chunk.dirty = True for (chunk, entity) in entstodelete: chunk.Entities.remove(entity) chunk.dirty = True for (chunk, entity) in tickstodelete: chunk.root_tag["Level"]["TileTicks"].remove(entity) chunk.dirty = True for te in tileentities: if "x" in te and "y" in te and "z" in te: x = te["x"].value z = te["z"].value chunk = level.getChunk(x>>4, z>>4) chunk.TileEntities.append(te) chunk.dirty = True for e in entities: if "Pos" in e: if len(e["Pos"]) >= 3: x = e["Pos"][0].value z = e["Pos"][2].value x = int(x)>>4 z = int(z)>>4 chunk = level.getChunk(x, z) chunk.Entities.append(e) chunk.dirty = True for t in tick: if "x" in t and "y" in t and "z" in t: x = t["x"].value z = t["z"].value chunk = level.getChunk(x>>4, z>>4) if "TileTicks" not in chunk.root_tag["Level"]: chunk.root_tag["Level"]["TileTicks"] = TAG_List() chunk.root_tag["Level"]["TileTicks"].append(t) chunk.dirty = True