[1198] | 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"] |
---|