forked from 529324416/MapEditor
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathEditorData.py
More file actions
308 lines (243 loc) · 8.98 KB
/
EditorData.py
File metadata and controls
308 lines (243 loc) · 8.98 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
# 地图编辑器数据模块
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
import os
import utils
import qtutils
import numpy as np
from EditorRoomBuffer import *
# WARN> 关于瓦片
class Tile:
'''单块瓦片数据'''
def __init__(self, tileId:int, tileName:str, pixmap:QPixmap, filepath:str, refcount=1):
'''初始化单块瓦片数据'''
self.tileId = tileId
self.tileName = tileName
self.filepath = filepath
self.pixmap = pixmap
self.refcount = refcount
# 编辑器认为瓦片可以直接作为笔刷来绘画
self.brushdata = np.array([[tileId]])
@property
def json(self):
'''将该瓦片的数据转换为JSON结构'''
return {
"id":self.tileId,
"name":self.tileName,
"filepath":self.filepath,
"refcount":self.refcount
}
class TileLib:
'''描述一个瓦片库/一个瓦片库可以具有多个瓦片但每个瓦片只会有一个'''
def __init__(self, libid, name):
'''创建一个瓦片库'''
self.name = name
self.libid = libid
self.tiles = list()
self.tileIds = set()
def add(self, tile:Tile) -> bool:
'''增加瓦片数据'''
if tile.tileId in self.tileIds:
return False
self.tileIds.add(tile.tileId)
self.tiles.append(tile)
return True
def remove(self, index:int) -> Tile:
'''根据给定的索引来删除瓦片数据,并返回该瓦片'''
if index >= 0 and index < len(self.tiles):
tile = self.tiles[index]
tile.refcount -= 1
self.tiles.remove(tile)
self.tileIds.remove(tile.tileId)
return tile
return None
def clear_tiles(self):
'''所有的瓦片引用数减一,如果瓦片引用数为0,则准备删除该瓦片'''
output = list()
self.tileIds.clear()
for tile in self.tiles:
tile.refcount -= 1
if tile.refcount == 0:
output.append(tile)
return output
@property
def render_infos(self):
'''获取需要渲染的数据'''
return [(_.tileName, _.pixmap) for _ in self.tiles]
class TileManager:
'''瓦片管理器'''
def __init__(self, tilesize=(12, 12)):
'''管理所有的瓦片'''
TileManager.instance = self
self.counter = utils.Counter(entry=1)
self.tilesize = QSize(*tilesize)
# DOC> 瓦片名 > 瓦片实体
self.tiles = dict()
self.libs = list()
self.libCounter = utils.Counter(entry=1)
self.currentlib = None
self.hasSaved = True
def findLib(self, name) -> tuple:
'''根据名称找到目标库'''
for i, lib in enumerate(self.libs):
if lib.name == name:
return i, lib
return -1, None
def indexLib(self, index:int) -> TileLib:
'''根据索引找到一个库'''
if index >= 0 and index < len(self.libs):
return self.libs[index]
return None
def set_current_lib(self, name:str) -> TileLib:
'''设置当前的瓦片库'''
index, lib = self.findLib(name)
if lib != None:
self.currentlib = lib
return self.currentlib
return None
def createLib(self):
'''新建一个瓦片的库/该库会成为当前被选中的库'''
libid = self.libCounter.next_id
name = f"新建库{libid}"
self.currentlib = TileLib(libid, name)
self.libs.append(self.currentlib)
return self.currentlib
def removeLib(self, index):
'''删除目标瓦片库'''
lib = self.libs[index]
tiles = lib.clear_tiles()
self.libCounter.recycle(lib.libid)
self.libs.remove(lib)
for tile in tiles:
self.tiles.pop(tile.tileName)
self.counter.recycle(tile.tileId)
def removeTile(self, tile: Tile):
'''删除单块瓦片\n
检查是否有地图数据引用了这块瓦片,如果有则不予删除'''
# TODO> 检查是否有地图或者笔刷数据引用了这块瓦片
self.counter.recycle(tile.tileId)
self.tiles.pop(tile.tileName)
# self.tilesById.pop(tile.tileId)
def create(self, file:str):
'''根据给定的文件创建一个新的瓦片数据'''
if file is None or not os.path.exists(file):
return False
try:
name = utils.parseNameFromPath(file)
if name in self.tiles:
tile = self.tiles[name]
tile.refcount += 1
self.currentlib.add(tile)
return True
pixmap = QPixmap(file)
# DOC> 不限制瓦片的大小
# if pixmap.size() != self.tilesize:
# return False
tile = Tile(self.counter.next_id, name, pixmap, file)
self.tiles.setdefault(tile.tileName, tile)
# self.tilesById.setdefault(tile.tileId, tile)
self.currentlib.add(tile)
return True
except:
return False
def _import_tiles(self) -> list:
'''导入一组瓦片'''
self.hasSaved = False
failed_list = []
filenames = qtutils.openfiles(caption="选择瓦片")
if filenames is None:
return False, None
for filename in filenames:
if not self.create(filename):
failed_list.append(filename)
return True, failed_list
@property
def json(self):
'''将所有的瓦片转换为一个JSON数据,它将以查找表的形式存在,通过瓦片Id查找瓦片名称,并且该数据还会记录自身的回收列表情况'''
tiles = {
"counter":self.counter.json,
"tiles":[v.json for v in self.tiles.values()]
}
_libs = dict()
for lib in self.libs:
_libs.setdefault(lib.name, {"tiles":[_.tileId for _ in lib.tiles],"libId":lib.libid})
return {
"tiles":tiles,
"libs":{
"counter":self.libCounter.json,
"libs":_libs
}
}
def load_json(self, obj: dict) -> int:
'''从json数据中恢复当前的tileManager'''
jsonTile = obj["tiles"]
missingCount = 0
self.counter.load_json(jsonTile["counter"])
namelut = dict()
for tileinfo in jsonTile["tiles"]:
try:
pixmap = QPixmap(tileinfo["filepath"])
tmp = Tile(tileinfo["id"], tileinfo["name"], pixmap, tileinfo["filepath"], tileinfo["refcount"])
self.tiles.setdefault(tmp.tileName, tmp)
namelut.setdefault(tmp.tileId, tmp.tileName)
except:
missingCount += 1
jsonLib = obj["libs"]
self.libCounter.load_json(jsonLib["counter"])
for name, lib in jsonLib["libs"].items():
tmp = TileLib(lib["libId"], name)
for tileId in lib["tiles"]:
tile = self.tiles.get(namelut[tileId])
if tile != None:
tmp.add(tile)
self.libs.append(tmp)
self.currentlib = tmp
return missingCount
class ProjectData(QObject):
'''工程文件
1.管理编辑器所有的数据信息'''
@staticmethod
def load_fromjson(data:dict):
'''从json文件中恢复所有的数据'''
tilesize = tuple(data["tilesize"])
project = ProjectData(tilesize)
missingCount = project.tileManager.load_json(data["tileManager"])
return project, missingCount
tileChoosed = pyqtSignal(Tile)
tileRemoved = pyqtSignal(Tile)
def __init__(self, tilesize=(12, 12)):
'''创建所有的数据单位'''
super().__init__(None)
self.tilesize = tilesize
self.tilew,self.tileh = tilesize
self.tileManager = TileManager(tilesize)
# self.dungeon = None
self.__current_tile = None
def choosetile(self, index:int):
'''当用户在瓦片窗口选中了某个瓦片时执行该函数'''
lib = self.tileManager.currentlib
self.__current_tile = lib.tiles[index]
self.tileChoosed.emit(self.__current_tile)
def removetile(self, index:int) -> list:
'''当某个瓦片被删除时执行该函数,返回被删除瓦片所在库的渲染信息'''
lib = self.tileManager.currentlib
tile = lib.remove(index)
if tile.refcount == 0:
if tile is self.__current_tile:
self.__current_tile = None
self.tileManager.removeTile(tile)
self.tileRemoved.emit(tile)
return lib.render_infos
@property
def json(self):
return {
"tileManager":self.tileManager.json,
"tilesize":[self.tilew, self.tileh]
}
@property
def currentTile(self):
return self.__current_tile
@property
def hasSaved(self):
return False