1 | from typing import List, Dict, Any, Tuple, Callable
|
---|
2 | from .comm import CommWrapper
|
---|
3 | from .creature import Creature
|
---|
4 | from gui.framsutils.framsProperty import Property
|
---|
5 | from framsfiles import reader
|
---|
6 | import threading
|
---|
7 | import asyncio
|
---|
8 | from functools import partial
|
---|
9 | import time
|
---|
10 | import glm
|
---|
11 | from .utils import parseNeuronDToOrient
|
---|
12 |
|
---|
13 | class FramsSocket:
|
---|
14 | def __init__(self):
|
---|
15 | self.comm = CommWrapper()
|
---|
16 | self.refreshControlButtonsCallback = None
|
---|
17 | self.refreshTreeviewCallback = None
|
---|
18 | self.loop = asyncio.get_event_loop()
|
---|
19 | self.loop_thread = threading.Thread(target=self.loop.run_forever)
|
---|
20 | self.loop_thread.start()
|
---|
21 |
|
---|
22 | def initConnection(self, address: str = '127.0.0.1', port: int = 9009) -> None:
|
---|
23 | self.comm = CommWrapper()
|
---|
24 | i = 0
|
---|
25 | time_delta = 0.1
|
---|
26 | total_time = 10
|
---|
27 | self.comm.start(address, port)
|
---|
28 | while self.comm.client.connecting == True and i < total_time / time_delta:
|
---|
29 | time.sleep(time_delta)
|
---|
30 | i += 1
|
---|
31 | response = self.comm.client.connected
|
---|
32 | if response:
|
---|
33 | self.comm.client.consumer.runningChangeEventCallback = self._runningChangeEventCallback
|
---|
34 | self.comm.client.consumer.populationsGroupChangeEventCallback = self._populationsGroupChangeEventCallback
|
---|
35 | self.comm.client.consumer.genepoolsGroupChangeEventCallback = self._genepoolsGroupChangeEventCallback
|
---|
36 | self.sendRequest("reg /simulator/populations/groups_changed")
|
---|
37 | self.sendRequest("reg /simulator/genepools/groups_changed")
|
---|
38 | self.sendRequest("reg /simulator/running_changed")
|
---|
39 | self.sendRequest("reg /cli/messages")
|
---|
40 | else:
|
---|
41 | self.comm.close()
|
---|
42 | raise ConnectionError()
|
---|
43 |
|
---|
44 | def closeConnection(self) -> None:
|
---|
45 | if self.comm:
|
---|
46 | self.comm.stop()
|
---|
47 | self.loop.call_soon_threadsafe(self.loop.stop)
|
---|
48 | self.loop_thread.join()
|
---|
49 |
|
---|
50 | def sendRequest(self, request: str, timeout = 1.0, return_index = False, index=-1) -> List[str]:
|
---|
51 | response = []
|
---|
52 |
|
---|
53 | if self.comm.connected:
|
---|
54 | if self.comm:
|
---|
55 | idx = self.comm.write(request, index=index)
|
---|
56 | future = asyncio.run_coroutine_threadsafe(self.comm.read(idx, timeout), self.loop)
|
---|
57 | try:
|
---|
58 | response = future.result(timeout)
|
---|
59 | response = [e+'\n' for e in response.split('\n')]
|
---|
60 | except asyncio.TimeoutError:
|
---|
61 | future.cancel()
|
---|
62 | except Exception as ex:
|
---|
63 | print("dropped request id {}, exception: {}".format(idx, ex))
|
---|
64 |
|
---|
65 | append = False
|
---|
66 | change = False
|
---|
67 | for i in range(len(response) - 2, -1, -1):
|
---|
68 | if response[i].find('~\n') >= 0 and response[i].find('\~\n') < 0:
|
---|
69 | response[i].replace('~\n', '')
|
---|
70 | change = True
|
---|
71 |
|
---|
72 | if append and not change:
|
---|
73 | response[i] = response[i] + response.pop(i + 1) #merge middle line
|
---|
74 | elif append and change:
|
---|
75 | response[i] = response[i] + response.pop(i + 1) #merge last line
|
---|
76 |
|
---|
77 | if change:
|
---|
78 | append = not append
|
---|
79 | change = False
|
---|
80 | if return_index:
|
---|
81 | return response, idx
|
---|
82 | return response
|
---|
83 |
|
---|
84 | def writeCreatureFromString(self, groupNo: int, creature: str) -> None:
|
---|
85 | creatureString = "call /simulator/populations/groups/{} createFromString {}".format(groupNo, creature)
|
---|
86 | self.sendRequest(creatureString)
|
---|
87 |
|
---|
88 | def step(self):
|
---|
89 | self.sendRequest("call /simulator step")
|
---|
90 |
|
---|
91 | def start(self):
|
---|
92 | self.sendRequest("call /simulator start")
|
---|
93 |
|
---|
94 | def stop(self):
|
---|
95 | self.sendRequest("call /simulator stop")
|
---|
96 |
|
---|
97 | def info(self, path: str = "/") -> List[Property]:
|
---|
98 | response = self.sendRequest("info {}".format(path))
|
---|
99 | properties = self._infoParser(response)
|
---|
100 | return properties
|
---|
101 |
|
---|
102 | def infoList(self, path: str) -> List[Property]:
|
---|
103 | response = self.sendRequest("get {}".format(path))
|
---|
104 | properties = self._infoParser(response)
|
---|
105 | return properties
|
---|
106 |
|
---|
107 | def _infoParser(self, response: List[str], packToProperty = True) -> List[Property]:
|
---|
108 | properties: List[Property] = []
|
---|
109 |
|
---|
110 | tmp = reader.loads(''.join(response))
|
---|
111 | if packToProperty:
|
---|
112 | properties = [Property(p=x) for x in tmp]
|
---|
113 | return properties
|
---|
114 | return tmp
|
---|
115 |
|
---|
116 | def _VstyleParserColor(self, style: str):
|
---|
117 | f = "color=0x"
|
---|
118 | idx = style.find(f)
|
---|
119 | if idx > -1:
|
---|
120 | hx = style[idx+len(f):idx+len(f)+6]
|
---|
121 | r = int(hx[0:2], 16) / 255.0
|
---|
122 | g = int(hx[2:4], 16) / 255.0
|
---|
123 | b = int(hx[4:6], 16) / 255.0
|
---|
124 | return r, g, b
|
---|
125 | return None, None, None
|
---|
126 |
|
---|
127 | def readCreatures(self, groupNo: int, creatureNo: int, color):
|
---|
128 | creatures: List[Creature] = []
|
---|
129 | if color:
|
---|
130 | creatureString = "get /simulator/populations/groups/{}/creatures/{}(/mechparts{{x,y,z,orient}},/joints{{p1,p2,vr,vg,vb,Vstyle}},/parts{{vr,vg,vb,Vstyle}},/neurodefs{{p,j,d}},{{model_Vstyle}})".format(groupNo, creatureNo)
|
---|
131 | else:
|
---|
132 | creatureString = "get /simulator/populations/groups/{}/creatures/{}(/mechparts{{x,y,z,orient}},/joints{{p1,p2}},/neurodefs{{p,j,d}})".format(groupNo, creatureNo)
|
---|
133 | response = self.sendRequest(creatureString)
|
---|
134 |
|
---|
135 | mechParts = []
|
---|
136 | joints = []
|
---|
137 | partColors = []
|
---|
138 | neurons = []
|
---|
139 | neuronStyles = []
|
---|
140 | creature: Creature = None
|
---|
141 |
|
---|
142 | mechPart: List[float] = [0,0,0]
|
---|
143 | joint: List[int] = [0,0]
|
---|
144 | partColor: glm.vec3 = glm.vec3(0,0,0)
|
---|
145 | neuron: Tuple(int, int) = (-1,-1)
|
---|
146 |
|
---|
147 | files = [i for i, x in enumerate(response) if x.startswith("file")]
|
---|
148 | files.append(-1)
|
---|
149 |
|
---|
150 | for i in range(len(files)-1):
|
---|
151 | file = response[files[i]]
|
---|
152 |
|
---|
153 | groupsStr = "groups/"
|
---|
154 | groupBegin = file.find(groupsStr) + len(groupsStr)
|
---|
155 | groupEnd = file.find("/", groupBegin)
|
---|
156 | group = int(file[groupBegin:groupEnd])
|
---|
157 |
|
---|
158 | creaturesStr = "creatures/"
|
---|
159 | creatureIndexBegin = file.find(creaturesStr) + len(creaturesStr)
|
---|
160 | creatureIndexEnd = file.find("/", creatureIndexBegin)
|
---|
161 | creatureIndex = int(file[creatureIndexBegin:creatureIndexEnd])
|
---|
162 |
|
---|
163 | creature = next((x for x in creatures if x.group == group and x.index == creatureIndex), None)
|
---|
164 | if not creature:
|
---|
165 | creature = Creature(group, creatureIndex)
|
---|
166 | creatures.append(creature)
|
---|
167 |
|
---|
168 | mechParts = []
|
---|
169 | joints = []
|
---|
170 | partColors = []
|
---|
171 | jointColors = []
|
---|
172 | neurons = []
|
---|
173 | neuronStyles = []
|
---|
174 | partOrient = []
|
---|
175 | neuroRelativeOrient = []
|
---|
176 |
|
---|
177 | resp = self._infoParser(response[files[i]:files[i+1]], False)
|
---|
178 |
|
---|
179 | for p in resp:
|
---|
180 | if p["_classname"] == "MechPart":
|
---|
181 | mechPart = [p['x'], p['y'], p['z']]
|
---|
182 | orient = p["orient"]
|
---|
183 | orient = orient[orient.find('[')+1:orient.find(']')]
|
---|
184 | orient = glm.mat4(glm.mat3(*[float(x) for x in orient.split(',')]))
|
---|
185 | mechParts.append(mechPart)
|
---|
186 | partOrient.append(orient)
|
---|
187 | elif p["_classname"] == "Joint":
|
---|
188 | joint = [p["p1"], p["p2"]]
|
---|
189 | joints.append(joint)
|
---|
190 |
|
---|
191 | if color:
|
---|
192 | jointColor = glm.vec3(p["vr"], p["vg"], p["vb"])
|
---|
193 | colors = self._VstyleParserColor(p["Vstyle"])
|
---|
194 | if colors and colors[0] != None:
|
---|
195 | jointColor = glm.vec3(colors)
|
---|
196 |
|
---|
197 | jointColors.append(jointColor)
|
---|
198 | elif p["_classname"] == "Part":
|
---|
199 | partColor = glm.vec3(p["vr"], p["vg"], p["vb"])
|
---|
200 |
|
---|
201 | colors = self._VstyleParserColor(p["Vstyle"])
|
---|
202 | if colors and colors[0] != None:
|
---|
203 | partColor = glm.vec3(colors)
|
---|
204 |
|
---|
205 | partColors.append(partColor)
|
---|
206 | elif p["_classname"] == "NeuroDef":
|
---|
207 | neuron = (p['p'], p['j'])
|
---|
208 | neurons.append(neuron)
|
---|
209 | neuronStyles.append(p['d'].split(':')[0])
|
---|
210 |
|
---|
211 | '''ix = p['d'].find(':')
|
---|
212 | rorient = glm.mat4(1)
|
---|
213 | if ix != -1:
|
---|
214 | ds = p['d'][ix+1:].split(',')
|
---|
215 | ds = [x.split('=') for x in ds]
|
---|
216 | rots = [x for x in ds if x[0].startswith('r')]
|
---|
217 |
|
---|
218 | if not any("ry" in x[0] for x in rots):
|
---|
219 | rots.append(["ry", '0'])
|
---|
220 | if not any("rz" in x[0] for x in rots):
|
---|
221 | rots.append(["rz", '0'])
|
---|
222 |
|
---|
223 | angle = next(float(x[1]) for x in rots if x[0] == "rz")
|
---|
224 | rorient = glm.rotate(rorient, angle, glm.vec3(0,0,1))
|
---|
225 | angle = -next(float(x[1]) for x in rots if x[0] == "ry")
|
---|
226 | rorient = glm.rotate(rorient, angle, glm.vec3(0,1,0))'''
|
---|
227 |
|
---|
228 | rorient = parseNeuronDToOrient(p['d'])
|
---|
229 | neuroRelativeOrient.append(rorient)
|
---|
230 | elif p["_classname"] == "Creature":
|
---|
231 | colors = self._VstyleParserColor(p["model_Vstyle"])
|
---|
232 | if colors and colors[0] != None:
|
---|
233 | creature.colorsPart = [glm.vec3(colors) for i in creature.colorsPart]
|
---|
234 |
|
---|
235 | creature.mechParts.extend(mechParts.copy())
|
---|
236 | creature.joints.extend(joints.copy())
|
---|
237 | creature.colorsPart.extend(partColors.copy())
|
---|
238 | creature.colorsJoint.extend(jointColors.copy())
|
---|
239 | creature.neurons.extend(neurons.copy())
|
---|
240 | creature.styleNeuron.extend(neuronStyles.copy())
|
---|
241 | creature.partOrient.extend(partOrient.copy())
|
---|
242 | creature.neuronRelativeOrient.extend(neuroRelativeOrient.copy())
|
---|
243 |
|
---|
244 | invalidCreatures = []
|
---|
245 | for creature in creatures:
|
---|
246 | if len(creature.mechParts) == 0:
|
---|
247 | invalidCreatures.append(creature)
|
---|
248 | for creature in invalidCreatures:
|
---|
249 | creatures.remove(creature)
|
---|
250 |
|
---|
251 | return creatures
|
---|
252 |
|
---|
253 | def readGenePoolsGroups(self) -> Dict[str, int]:
|
---|
254 | genotypes: Dict[str, int] = {}
|
---|
255 | tmp = []
|
---|
256 | for i in range(3):
|
---|
257 | response = self.sendRequest("get /simulator/genepools/groups/+ index,name")
|
---|
258 | tmp = self._infoParser(response)
|
---|
259 | if len(tmp) > 0:
|
---|
260 | break
|
---|
261 |
|
---|
262 | for i in tmp:
|
---|
263 | genotypes[i.p["name"]] = i.p["index"]
|
---|
264 |
|
---|
265 | return genotypes
|
---|
266 |
|
---|
267 | def readGenePools(self, props: List[str]) -> Dict[str, List[Dict[str, Any]]]:
|
---|
268 | genotypes: Dict[str, List[Dict[str, Any]]] = {}
|
---|
269 |
|
---|
270 | for i in range(3):
|
---|
271 | response = self.sendRequest("get /simulator/genepools/groups/+ index,name")
|
---|
272 | tmp = self._infoParser(response)
|
---|
273 | if len(tmp) > 0:
|
---|
274 | break
|
---|
275 | else:
|
---|
276 | return genotypes
|
---|
277 |
|
---|
278 | tu = {}
|
---|
279 | for i in tmp:
|
---|
280 | tu[i.p["index"]] = i.p["name"]
|
---|
281 | genotypes[i.p["index"]] = []
|
---|
282 |
|
---|
283 | p = ",".join(props)
|
---|
284 | response = self.sendRequest("get /simulator/genepools/groups/+/genotypes/+ {}".format(p))
|
---|
285 |
|
---|
286 | files = [i for i, x in enumerate(response) if x.startswith("file")]
|
---|
287 | files.append(-1)
|
---|
288 |
|
---|
289 | for i in range(len(files)-1):
|
---|
290 | file = response[files[i]]
|
---|
291 |
|
---|
292 | groupsStr = "groups/"
|
---|
293 | groupBegin = file.find(groupsStr) + len(groupsStr)
|
---|
294 | groupEnd = file.find("/", groupBegin)
|
---|
295 | group = int(file[groupBegin:groupEnd])
|
---|
296 |
|
---|
297 | genotypesStr = "genotypes/"
|
---|
298 | genotypeIndexBegin = file.find(genotypesStr) + len(genotypesStr)
|
---|
299 | genotypeIndexEnd = file.find("/", genotypeIndexBegin-1) +2
|
---|
300 | genotypeIndex = int(file[genotypeIndexBegin:genotypeIndexEnd])
|
---|
301 |
|
---|
302 | resp = self._infoParser(response[files[i]:files[i+1]], False)
|
---|
303 |
|
---|
304 | genotypes[group].append(resp[0])
|
---|
305 | genotypes[group][-1].update({"group": group, "index": genotypeIndex})
|
---|
306 |
|
---|
307 | g = {}
|
---|
308 | for (i, gen) in genotypes.items():
|
---|
309 | g[tu[i]] = gen
|
---|
310 |
|
---|
311 | return g
|
---|
312 |
|
---|
313 | def readPopulationsGroups(self) -> Dict[str, int]:
|
---|
314 | creatures: Dict[str, int] = {}
|
---|
315 | tmp = []
|
---|
316 | for i in range(3):
|
---|
317 | response = self.sendRequest("get /simulator/populations/groups/+ index,name")
|
---|
318 | tmp = self._infoParser(response)
|
---|
319 | if len(tmp) > 0:
|
---|
320 | break
|
---|
321 |
|
---|
322 | for i in tmp:
|
---|
323 | creatures[i.p["name"]] = i.p["index"]
|
---|
324 |
|
---|
325 | return creatures
|
---|
326 |
|
---|
327 | def readPopulations(self, props: List[str]) -> Dict[str, List[Dict[str, Any]]]:
|
---|
328 | creatures: Dict[str, List[Dict[str, Any]]] = {}
|
---|
329 | for i in range(3):
|
---|
330 | response = self.sendRequest("get /simulator/populations/groups/+ index,name")
|
---|
331 | tmp = self._infoParser(response)
|
---|
332 | if len(tmp) > 0:
|
---|
333 | break
|
---|
334 | else:
|
---|
335 | return creatures
|
---|
336 |
|
---|
337 | tu = {}
|
---|
338 | for i in tmp:
|
---|
339 | tu[i.p["index"]] = i.p["name"]
|
---|
340 | creatures[i.p["index"]] = []
|
---|
341 |
|
---|
342 | p = ",".join(props)
|
---|
343 | response = self.sendRequest("get /simulator/populations/groups/+/creatures/+ {}".format(p))
|
---|
344 |
|
---|
345 | files = [i for i, x in enumerate(response) if x.startswith("file")]
|
---|
346 | files.append(-1)
|
---|
347 |
|
---|
348 | for i in range(len(files)-1):
|
---|
349 | file = response[files[i]]
|
---|
350 |
|
---|
351 | groupsStr = "groups/"
|
---|
352 | groupBegin = file.find(groupsStr) + len(groupsStr)
|
---|
353 | groupEnd = file.find("/", groupBegin)
|
---|
354 | group = int(file[groupBegin:groupEnd])
|
---|
355 |
|
---|
356 | creaturesStr = "creatures/"
|
---|
357 | creatureIndexBegin = file.find(creaturesStr) + len(creaturesStr)
|
---|
358 | creatureIndexEnd = file.find("/", creatureIndexBegin-1) +2
|
---|
359 | creatureIndex = int(file[creatureIndexBegin:creatureIndexEnd])
|
---|
360 |
|
---|
361 | resp = self._infoParser(response[files[i]:files[i+1]], False)
|
---|
362 |
|
---|
363 | creatures[group].append(resp[0])
|
---|
364 | creatures[group][-1].update({"group": group, "index": creatureIndex})
|
---|
365 |
|
---|
366 | c = {}
|
---|
367 | for (i, cre) in creatures.items():
|
---|
368 | c[tu[i]] = cre
|
---|
369 |
|
---|
370 | return c
|
---|
371 |
|
---|
372 | def readCreatureInfo(self, groupNo: int, creatureNo: int) -> List[Property]:
|
---|
373 | response = self.sendRequest("info /simulator/populations/groups/{}/creatures/{}".format(groupNo, creatureNo))
|
---|
374 | response2 = self.sendRequest("get /simulator/populations/groups/{}/creatures/{}".format(groupNo, creatureNo))
|
---|
375 |
|
---|
376 | tmpProperties = self._infoParser(response)
|
---|
377 | tmpValues = self._infoParser(response2)
|
---|
378 | properties: List[Property] = []
|
---|
379 | for prop in tmpProperties:
|
---|
380 | if "type" in prop.p and "id" in prop.p and len(prop.p["type"]) > 0:
|
---|
381 | if prop.p["type"][0] not in "xole": #xol is a list of unwanted types
|
---|
382 | if prop.p["type"][0] == 'p':
|
---|
383 | prop.p["value"] = partial(self.call, "/simulator/populations/groups/{}/creatures/{} {}".format(groupNo, creatureNo, prop.p["id"]))
|
---|
384 | else:
|
---|
385 | prop.p["value"] = next(v for k, v in tmpValues[0].p.items() if k == prop.p["id"])
|
---|
386 | properties.append(prop)
|
---|
387 |
|
---|
388 | return properties
|
---|
389 |
|
---|
390 | def readGenotypeInfo(self, groupNo: int, genotypeNo: int) -> List[Property]:
|
---|
391 | response = self.sendRequest("info /simulator/genepools/groups/{}/genotypes/{}".format(groupNo, genotypeNo))
|
---|
392 | response2 = self.sendRequest("get /simulator/genepools/groups/{}/genotypes/{}".format(groupNo, genotypeNo))
|
---|
393 |
|
---|
394 | tmpProperties = self._infoParser(response)
|
---|
395 | tmpValues = self._infoParser(response2)
|
---|
396 | properties: List[Property] = []
|
---|
397 | for prop in tmpProperties:
|
---|
398 | if "type" in prop.p and "id" in prop.p and len(prop.p["type"]) > 0:
|
---|
399 | if prop.p["type"][0] not in "xole": #xol is a list of unwanted types
|
---|
400 | if prop.p["type"][0] == 'p':
|
---|
401 | prop.p["value"] = partial(self.call, "/simulator/genepools/groups/{}/genotypes/{} {}".format(groupNo, genotypeNo, prop.p["id"]))
|
---|
402 | else:
|
---|
403 | prop.p["value"] = next(v for k, v in tmpValues[0].p.items() if k == prop.p["id"])
|
---|
404 | properties.append(prop)
|
---|
405 |
|
---|
406 | return properties
|
---|
407 |
|
---|
408 | def readPropertyInfo(self, path) -> List[Property]:
|
---|
409 | response = self.sendRequest("info {}".format(path))
|
---|
410 | response2 = self.sendRequest("get {}".format(path))
|
---|
411 |
|
---|
412 | tmpProperties = self._infoParser(response)
|
---|
413 | tmpValues = self._infoParser(response2)
|
---|
414 | properties: List[Property] = []
|
---|
415 | for prop in tmpProperties:
|
---|
416 | if "type" in prop.p and "id" in prop.p and len(prop.p["type"]) > 0:
|
---|
417 | if prop.p["type"][0] and prop.p["type"][0] not in "xole": #xole is a list of unwanted types
|
---|
418 | if prop.p["type"][0] == 'p':
|
---|
419 | prop.p["value"] = partial(self.call, "{} {}".format(path, prop.p["id"]))
|
---|
420 | else:
|
---|
421 | prop.p["value"] = next((v for k, v in tmpValues[0].p.items() if k == prop.p["id"]), "")
|
---|
422 | properties.append(prop)
|
---|
423 |
|
---|
424 | return properties
|
---|
425 |
|
---|
426 | def writeCreatureInfo(self, uid: str, prop: str, value: str) -> bool:
|
---|
427 | response = self.sendRequest("get /simulator/populations size")
|
---|
428 | size = next(int(x[x.find(":")+1:-1]) for x in response if x.startswith("size"))
|
---|
429 | if response:
|
---|
430 | for i in range(size):
|
---|
431 | res = self.sendRequest("set /simulator/populations/groups/{}/creatures/{} {} \"{}\"".format(i, uid, prop, value))
|
---|
432 | return True
|
---|
433 | return False
|
---|
434 |
|
---|
435 | def writeGenotypeInfo(self, uid: str, prop: str, value: str) -> bool:
|
---|
436 | response = self.sendRequest("get /simulator/genepools size")
|
---|
437 | size = next(int(x[x.find(":")+1:-1]) for x in response if x.startswith("size"))
|
---|
438 | if response:
|
---|
439 | for i in range(size):
|
---|
440 | res = self.sendRequest("set /simulator/genepools/groups/{}/genotypes/{} {} \"{}\"".format(i, uid, prop, value))
|
---|
441 | return True
|
---|
442 | return False
|
---|
443 |
|
---|
444 | def writePropertyInfo(self, path: str, prop: str, value: str):
|
---|
445 | response = self.sendRequest("set {} {} \"{}\"".format(path, prop, value))
|
---|
446 | if response:
|
---|
447 | return True
|
---|
448 | return False
|
---|
449 |
|
---|
450 | def call(self, path: str):
|
---|
451 | self.sendRequest("call {}".format(path))
|
---|
452 |
|
---|
453 | def _runningChangeEventCallback(self, block: str, header: str):
|
---|
454 | prop = self._infoParser([block])[0]
|
---|
455 | if self.refreshControlButtonsCallback:
|
---|
456 | self.refreshControlButtonsCallback(prop.p["value"])
|
---|
457 |
|
---|
458 | def _populationsGroupChangeEventCallback(self, block: str, header: str):
|
---|
459 | if self.refreshTreeviewCallback:
|
---|
460 | self.refreshTreeviewCallback()
|
---|
461 |
|
---|
462 | def _genepoolsGroupChangeEventCallback(self, block: str, header: str):
|
---|
463 | if self.refreshTreeviewCallback:
|
---|
464 | self.refreshTreeviewCallback()
|
---|
465 |
|
---|
466 | def registerMessageEventCallback(self, callback: Callable[[str, str], None]):
|
---|
467 | self.comm.client.consumer.messagesEventCallback = callback
|
---|
468 |
|
---|
469 | def loadFile(self, path: str) -> None:
|
---|
470 | response, idx = self.sendRequest("call /simulator netload", return_index=True)
|
---|
471 | if response:
|
---|
472 | if response[0].startswith("needfile"):
|
---|
473 | with open(path) as file:
|
---|
474 | data = "file \n" + file.read() + "eof"
|
---|
475 | self.sendRequest(data, index=idx)
|
---|
476 |
|
---|
477 | def importFile(self, path: str, options: int) -> None:
|
---|
478 | response, idx = self.sendRequest("call /simulator netimport {}".format(options), return_index=True)
|
---|
479 | if response:
|
---|
480 | if response[0].startswith("needfile"):
|
---|
481 | with open(path) as file:
|
---|
482 | data = "file \n" + file.read() + "eof"
|
---|
483 | self.sendRequest(data, index=idx)
|
---|
484 |
|
---|
485 | def saveFile(self, path: str, options: int) -> None:
|
---|
486 | response = self.sendRequest("call /simulator netexport {} -1 -1".format(options))
|
---|
487 | if response:
|
---|
488 | start = 0
|
---|
489 | end = len(response) - 1
|
---|
490 | if response[0].startswith("file"):
|
---|
491 | start = 1
|
---|
492 |
|
---|
493 | while response[end].strip() == '':
|
---|
494 | end -= 1
|
---|
495 |
|
---|
496 | if response[end].startswith("ok"):
|
---|
497 | end -= 1
|
---|
498 | if response[end].startswith("eof"):
|
---|
499 | end -= 1
|
---|
500 |
|
---|
501 | while response[end].strip() == '':
|
---|
502 | end -= 1
|
---|
503 | end += 1
|
---|
504 |
|
---|
505 | with open(path, 'w') as file:
|
---|
506 | file.write(''.join(response[start:end]))
|
---|
507 | file.write("\n")
|
---|
508 |
|
---|
509 | def getWorldType(self) -> int:
|
---|
510 | info = []
|
---|
511 | while not info:
|
---|
512 | response = self.sendRequest("get /simulator/world wrldtyp")
|
---|
513 | info = self._infoParser(response)
|
---|
514 | return info[0].p["wrldtyp"]
|
---|
515 |
|
---|
516 | def getWorldSize(self) -> float:
|
---|
517 | info = []
|
---|
518 | while not info:
|
---|
519 | response = self.sendRequest("get /simulator/world wrldsiz")
|
---|
520 | info = self._infoParser(response)
|
---|
521 | return info[0].p["wrldsiz"]
|
---|
522 |
|
---|
523 | def getWorldWaterLevel(self) -> float:
|
---|
524 | info = []
|
---|
525 | while not info:
|
---|
526 | response = self.sendRequest("get /simulator/world wrldwat")
|
---|
527 | info = self._infoParser(response)
|
---|
528 | return info[0].p["wrldwat"]
|
---|
529 |
|
---|
530 | def getWorldBoundaries(self) -> int:
|
---|
531 | info = []
|
---|
532 | while not info:
|
---|
533 | response = self.sendRequest("get /simulator/world wrldbnd")
|
---|
534 | info = self._infoParser(response)
|
---|
535 | return info[0].p["wrldbnd"]
|
---|
536 |
|
---|
537 | def getWorldMap(self) -> str:
|
---|
538 | info = []
|
---|
539 | while not info:
|
---|
540 | response = self.sendRequest("get /simulator/world geometry")
|
---|
541 | info = self._infoParser(response)
|
---|
542 | return info[0].p["geometry"]
|
---|
543 |
|
---|
544 | def getSimtype(self) -> int:
|
---|
545 | info = []
|
---|
546 | while not info:
|
---|
547 | response = self.sendRequest("get /simulator/world simtype")
|
---|
548 | info = self._infoParser(response)
|
---|
549 | return info[0].p["simtype"] |
---|