Bläddra i källkod

Working CIM Port Report data collection.

Fixed bug in PlayerInput that was squashing the to_player flag.
(So we weren't getting the data from the game being send to
the player.)
Steve Thielemann 5 år sedan
förälder
incheckning
da773cfae3
2 ändrade filer med 176 tillägg och 7 borttagningar
  1. 175 6
      flexible.py
  2. 1 1
      tcp-proxy.py

+ 175 - 6
flexible.py

@@ -4,7 +4,9 @@ from twisted.internet import defer
 from colorama import Fore, Back, Style
 from twisted.python import log
 
+from itertools import cycle
 import pendulum
+from pprint import pformat
 
 
 def merge(color_string):
@@ -52,6 +54,7 @@ class PlayerInput(object):
 
         keywords:
         abort_blank : Abort if they give us blank text.
+        name : Stores the input in self.keep dict.
 
         """
         log.msg("PlayerInput({0}, {1}, {2}".format(user_prompt, limit, kw))
@@ -74,7 +77,8 @@ class PlayerInput(object):
         self.game.to_player = False
 
         # Display prompt
-        self.queue_game.put(self.r + self.nl + self.c + user_prompt + " " + self.cp)
+        # self.queue_game.put(self.r + self.nl + self.c + user_prompt + " " + self.cp)
+        self.queue_game.put(self.r + self.c + user_prompt + self.r + " " + self.cp)
         # Set "Background of prompt"
         self.queue_game.put(" " * limit + "\b" * limit)
 
@@ -107,6 +111,7 @@ class PlayerInput(object):
                 line = self.input
                 self.input = ""
                 assert not self.deferred is None
+                self.game.to_player = self.to_player
 
                 # If they gave us the keyword name, save the value as that name
                 if "name" in self.kw:
@@ -144,10 +149,157 @@ class PlayerInput(object):
     def output(self, line):
         """ A default display of what they just input. """
         log.msg("PlayerInput.output({0})".format(line))
-        self.game.queue_game.put(self.r + self.nl + "[{0}]".format(line) + self.nl)
+        self.game.queue_game.put(self.r + "[{0}]".format(line) + self.nl)
         return line
 
 
+PORT_CLASSES = {
+    1: "BBS",
+    2: "BSB",
+    3: "SBB",
+    4: "SSB",
+    5: "SBS",
+    6: "BSS",
+    7: "SSS",
+    8: "BBB",
+}
+CLASSES_PORT = {v: k for k, v in PORT_CLASSES.items()}
+import re
+
+
+class CIMPortReport(object):
+    def __init__(self, game):
+        self.game = game
+        self.queue_game = game.queue_game
+        self.queue_player = game.queue_player
+        self.observer = game.observer
+        # Yes, at this point we would activate
+        self.prompt = game.buffer
+        self.save = self.observer.save()
+
+        # I actually don't want the player input, but I'll grab it anyway.
+        self.observer.connect("player", self.player)
+
+        self.observer.connect("prompt", self.game_prompt)
+        self.observer.connect("game-line", self.game_line)
+
+        # If we want it, it's here.
+        self.defer = None
+        self.to_player = self.game.to_player
+        log.msg("to_player (stored)", self.to_player)
+
+        # Hide what's happening from the player
+        self.game.to_player = False
+
+        self.queue_player.put("^")  # Activate CIM
+        self.state = 1
+        self.portdata = {}
+        self.portcycle = cycle(["/", "-", "\\", "|"])
+
+    def game_prompt(self, prompt):
+        if prompt == ": ":
+            if self.state == 1:
+                # Ok, then we're ready to request the port report
+                self.portcycle = cycle(["/", "-", "\\", "|"])
+                self.queue_player.put("R")
+                self.state = 2
+            if self.state == 2:
+                self.queue_player.put("Q")
+                self.state = 3
+        if re.match(r"Command \[TL=.* \(\?=Help\)\? :", prompt):
+            if self.state == 3:
+                # Ok, time to exit
+                # exit from this...
+                self.game.to_player = self.to_player
+                self.observer.load(self.save)
+                self.save = None
+
+                self.queue_game.put("\b \b\r\n")
+
+                if not self.defer is None:
+                    self.defer.callback(self.portdata)
+                    self.defer = None
+
+    def game_line(self, line):
+        if line == "" or line == ": ":
+            return
+        if line == ": ENDINTERROG":
+            return
+
+        # This should be the CIM Report Data -- parse it
+        if self.portcycle:
+            if len(self.portdata) % 10 == 0:
+                self.queue_game.put("\b" + next(self.portcycle))
+
+        work = line.replace("%", "")
+
+        parts = re.split(r"(?<=\d)\s", work)
+
+        if len(parts) == 8:
+            port = int(parts[0].strip())
+            data = dict()
+
+            def portBS(info):
+                if info[0] == "-":
+                    bs = "B"
+                else:
+                    bs = "S"
+                return (bs, int(info[1:].strip()))
+
+            data["fuel"] = dict()
+            data["fuel"]["sale"], data["fuel"]["units"] = portBS(parts[1])
+            data["fuel"]["pct"] = int(parts[2].strip())
+            data["org"] = dict()
+            data["org"]["sale"], data["org"]["units"] = portBS(parts[3])
+            data["org"]["pct"] = int(parts[4].strip())
+            data["equ"] = dict()
+            data["equ"]["sale"], data["equ"]["units"] = portBS(parts[5])
+            data["equ"]["pct"] = int(parts[6].strip())
+
+            # Store what this port is buying/selling
+            data["port"] = (
+                data["fuel"]["sale"] + data["org"]["sale"] + data["equ"]["sale"]
+            )
+
+            # Convert BBS/SBB to Class number 1-8
+            data["class"] = CLASSES_PORT[data["port"]]
+            self.portdata[port] = data
+        else:
+            log.msg("CIMPortReport:", line, "???")
+
+    def __del__(self):
+        log.msg("CIMPortReport {0} RIP".format(self))
+
+    def whenDone(self):
+        self.defer = defer.Deferred()
+        # Call this to chain something after we exit.
+        return self.defer
+
+    def player(self, chunk):
+        """ Data from player (in bytes). """
+        chunk = chunk.decode("utf-8", "ignore")
+        key = chunk.upper()
+        log.msg("CIMPortReport.player({0}) : I AM stopping...".format(key))
+
+        # Stop the keepalive if we are activating something else
+        # or leaving...
+        # self.keepalive.stop()
+
+        self.queue_game.put("\b \b\r\n")
+
+        if not self.defer is None:
+            # We have something, so:
+            self.game.to_player = self.to_player
+            self.observer.load(self.save)
+            self.save = None
+            self.defer.errback(Exception("User Abort"))
+            self.defer = None
+        else:
+            # Still "exit" out.
+            self.game.to_player = self.to_player
+            self.observer.load(self.save)
+
+
 class ProxyMenu(object):
     def __init__(self, game):
         self.nl = "\n\r"
@@ -155,7 +307,7 @@ class ProxyMenu(object):
         self.r = Style.RESET_ALL
         self.c1 = merge(Style.BRIGHT + Fore.BLUE)
         self.c2 = merge(Style.NORMAL + Fore.CYAN)
-
+        self.portdata = None
         self.game = game
         self.queue_game = game.queue_game
         self.observer = game.observer
@@ -202,6 +354,11 @@ class ProxyMenu(object):
         log.msg("ProxyMenu.awake()")
         self.game.queue_player.put(" ")
 
+    def port_report(self, portdata):
+        self.portdata = portdata
+        self.queue_game.put("Loaded {0} records.".format(len(portdata)) + self.nl)
+        self.welcome_back()
+
     def player(self, chunk):
         """ Data from player (in bytes). """
         chunk = chunk.decode("utf-8", "ignore")
@@ -219,20 +376,31 @@ class ProxyMenu(object):
             self.queue_game.put(
                 self.nl + self.c1 + "Current time " + now.to_datetime_string() + self.nl
             )
+        elif key == "P":
+            self.queue_game.put(self.c + key + self.r + self.nl)
+            # Activate CIM Port Report
+            report = CIMPortReport(self.game)
+            d = report.whenDone()
+            d.addCallback(self.port_report)
+            d.addErrback(self.welcome_back)
+            return
+        elif key == "D":
+            self.queue_game.put(self.c + key + self.r + self.nl)
+            self.queue_game.put(pformat(self.portdata).replace("\n", "\n\r") + self.nl)
         elif key == "Q":
             self.queue_game.put(self.c + key + self.r + self.nl)
 
             # This is an example of chaining PlayerInput prompt calls.
 
             ask = PlayerInput(self.game)
-            d = ask.prompt("What is your quest?", 20, name="quest", abort_blank=True)
+            d = ask.prompt("What is your quest?", 40, name="quest", abort_blank=True)
 
             # Display the user's input
             d.addCallback(ask.output)
 
             d.addCallback(
                 lambda ignore: ask.prompt(
-                    "What is your favorite color?", 5, name="color"
+                    "What is your favorite color?", 10, name="color"
                 )
             )
             d.addCallback(ask.output)
@@ -240,7 +408,7 @@ class ProxyMenu(object):
             d.addCallback(
                 lambda ignore: ask.prompt(
                     "What is the meaning of the squirrel?",
-                    40,
+                    12,
                     name="squirrel",
                     digits=True,
                 )
@@ -249,6 +417,7 @@ class ProxyMenu(object):
 
             def show_values(show):
                 log.msg(show)
+                self.queue_game.put(pformat(show).replace("\n", "\n\r") + self.nl)
 
             d.addCallback(lambda ignore: show_values(ask.keep))
             d.addCallback(self.welcome_back)

+ 1 - 1
tcp-proxy.py

@@ -13,7 +13,7 @@ import pendulum
 from subprocess import check_output
 
 from colorama import Fore, Back, Style
-from itertools import cycle
+
 from deprecated import deprecated
 from pprint import pformat