Пример #1
0
class Store:
    def __init__(self, reducer: Dict, init_value: Dict):
        self._reducer = reducer
        #Default Setter
        if "SET_VALUE" in self._reducer:
            raise KeyError("Reducer name 'SET_VALUE' is reserved")
        self._reducer["SET_VALUE"] = set_value_reducer

        self._state = BehaviorSubject({})
        self._state.on_next(init_value)

    def dispatch(self, name: str, payload: Dict = None):
        if name in self._reducer:
            self._state.on_next(self._reducer[name](self.state, payload))

    def get_reducers(self):
        return {name: partial(self.dispatch, name) for name in self._reducer}

    def select_compiled(self, comp, built_in=None, logger=None):
        def wrapper(state):
            built_in.update(state)
            try:
                return eval_compiled(comp, variables=built_in)
            except:
                # Could not evaluate, probably wrong binding
                if logger:
                    logger.warn(f"Error could not evaluate binding")
                    logger.warn(format_exc(limit=2))
                return None

        return self.select([wrapper])

    def select(self, selectors: List):
        if len(selectors) == 1 and callable(selectors[0]):
            return self._state.pipe(rxop.map(selectors[0]),
                                    rxop.distinct_until_changed())
        else:
            return self._state.pipe(
                rxop.map(lambda data: safe_get(data, selectors)),
                rxop.distinct_until_changed())

    def select_by_path(self, path):
        return self.select(path.split("."))

    def subscribe(self, subscriber):
        return self._state.subscribe(subscriber)

    @property
    def state(self) -> Dict:
        return self._state.value
Пример #2
0
    def _add_obs(self, name, default=None):
        subject = BehaviorSubject(default)
        uniq_subject = subject.pipe(ops.distinct_until_changed())

        def getobs(self):
            return getattr(self, f"_obs_{name}").value

        def setobs(self, v):
            getattr(self, f"_obs_{name}").on_next(v)

        setattr(self, f"_obs_{name}", subject)
        setattr(self, f"obs_{name}", uniq_subject)
        setattr(self.__class__, name, property(getobs, setobs))
        self._data_fields.append(name)
Пример #3
0
class BlenderContext(Context):
    window_size: RV[Dimension] = rv.new_view()

    batch: RV[GPUBatch] = window_size.map(lambda c, s: c.create_batch(s))

    buffer: RV[GPUBatch] = window_size.map(lambda c, s: c.create_batch(s))

    def __init__(self,
                 toolkit: BlenderToolkit,
                 look_and_feel: Optional[LookAndFeel] = None,
                 font_options: Optional[FontOptions] = None,
                 window_manager: Optional[WindowManager] = None,
                 error_handler: Optional[ErrorHandler] = None) -> None:
        super().__init__(toolkit, look_and_feel, font_options, window_manager,
                         error_handler)

        resolution = Dimension(bge.render.getWindowWidth(),
                               bge.render.getWindowHeight())

        self._resolution = BehaviorSubject(resolution)

        # noinspection PyTypeChecker
        self.window_size = self._resolution.pipe(ops.distinct_until_changed())

        self._shader = cast(GPUShader, gpu.shader.from_builtin("2D_IMAGE"))

        if use_viewport_render:
            # noinspection PyArgumentList
            self._draw_handler = SpaceView3D.draw_handler_add(
                self.process, (), "WINDOW", "POST_PIXEL")
        else:
            self._draw_handler = None

            bge.logic.getCurrentScene().post_draw.append(self.process)

        # noinspection PyTypeChecker
        self._texture = Buffer(bgl.GL_INT, 1)

        bgl.glGenTextures(1, self.texture)

    @property
    def shader(self) -> GPUShader:
        return self._shader

    @property
    def texture(self) -> Buffer:
        return self._texture

    def create_batch(self, size: Dimension) -> GPUBatch:
        if size is None:
            raise ValueError("Argument 'size' is required.")

        points = Bounds(0, 0, size.width, size.height).points

        vertices = tuple(map(lambda p: p.tuple, map(self.translate, points)))
        coords = ((0, 0), (1, 0), (1, 1), (0, 1))

        indices = {"pos": vertices, "texCoord": coords}

        return batch_for_shader(self.shader, "TRI_FAN", indices)

    def translate(self, point: Point) -> Point:
        if point is None:
            raise ValueError("Argument 'point' is required.")

        return point.copy(y=self.window_size.height - point.y)

    # noinspection PyTypeChecker
    def process_draw(self) -> None:
        width = bge.render.getWindowWidth()
        height = bge.render.getWindowHeight()

        self._resolution.on_next(Dimension(width, height))

        super().process_draw()

        data = self.surface.get_data()

        source = bgl.Buffer(bgl.GL_BYTE, width * height * 4, data)

        bgl.glEnable(bgl.GL_BLEND)
        bgl.glActiveTexture(bgl.GL_TEXTURE0)

        # noinspection PyUnresolvedReferences
        bgl.glBindTexture(bgl.GL_TEXTURE_2D, self.texture[0])

        bgl.glTexImage2D(bgl.GL_TEXTURE_2D, 0, bgl.GL_SRGB_ALPHA, width,
                         height, 0, bgl.GL_BGRA, bgl.GL_UNSIGNED_BYTE, source)

        bgl.glTexParameteri(bgl.GL_TEXTURE_2D, bgl.GL_TEXTURE_MIN_FILTER,
                            bgl.GL_NEAREST)
        bgl.glTexParameteri(bgl.GL_TEXTURE_2D, bgl.GL_TEXTURE_MAG_FILTER,
                            bgl.GL_NEAREST)

        self.shader.bind()
        self.shader.uniform_int("image", 0)

        self.batch.draw(self.shader)

        bgl.glDeleteBuffers(1, source)

    def dispose(self) -> None:
        if self._draw_handler:
            # noinspection PyArgumentList
            SpaceView3D.draw_handler_remove(self._draw_handler, "WINDOW")
        else:
            bge.logic.getCurrentScene().post_draw.remove(self.process)

        bgl.glDeleteTextures(1, self.texture)

        # noinspection PyTypeChecker
        bgl.glDeleteBuffers(1, self.texture)

        super().dispose()
Пример #4
0
class LobbyConnection:
    """
    GUARANTEES:
    - After calling connect, connection will leave disconnected state.
    """
    def __init__(self, host, port):
        self.socket = QtNetwork.QTcpSocket()
        self.socket.stateChanged.connect(self._on_socket_state_change)
        self.socket.readyRead.connect(self.read)
        self.socket.error.connect(self._on_error)
        self.socket.setSocketOption(QtNetwork.QTcpSocket.KeepAliveOption, 1)

        self._host = host
        self._port = port
        self.block_size = 0

        self._obs_state = BehaviorSubject(ConnectionState.DISCONNECTED)
        self.obs_state = self._obs_state.pipe(ops.distinct_until_changed())
        self.message_stream = Subject()

    def _socket_state(self, s):
        qas = QtNetwork.QAbstractSocket
        if s in [qas.ConnectedState, qas.ClosingState]:
            return ConnectionState.CONNECTED
        elif s in [qas.BoundState, qas.HostLookupState, qas.ConnectingState]:
            return ConnectionState.CONNECTING
        else:
            return ConnectionState.DISCONNECTED

    @property
    def state(self):
        return self._obs_state.value

    def _on_socket_state_change(self, state):
        s = self._socket_state(state)
        if s is ConnectionState.DISCONNECTED:
            self.block_size = 0
        self._obs_state.on_next(s)

    # Conflict with PySide2 signals!
    # Idempotent
    def connect_(self):
        if self.state is not ConnectionState.DISCONNECTED:
            return
        self.socket.connectToHost(self._host, self._port)

    def disconnect_(self):
        self.socket.disconnectFromHost()

    def read(self):
        ins = QtCore.QDataStream(self.socket)
        ins.setVersion(QtCore.QDataStream.Qt_4_2)

        while not ins.atEnd():
            if self.block_size == 0:
                if self.socket.bytesAvailable() < 4:
                    return
                self.block_size = ins.readUInt32()
            if self.socket.bytesAvailable() < self.block_size:
                return
            data = ins.readQString()
            self.block_size = 0
            self.message_stream.on_next(data)

    def write(self, data):
        block = QtCore.QByteArray()
        out = QtCore.QDataStream(block, QtCore.QIODevice.ReadWrite)
        out.setVersion(QtCore.QDataStream.Qt_4_2)
        out.writeUInt32(2 * len(data) + 4)
        out.writeQString(data)
        if self.socket.state() == QtNetwork.QAbstractSocket.ConnectedState:
            self.socket.write(block)

    def _on_error(self):
        self.disconnect_()