home · contact · privacy
Server/py: Improve comments.
[plomrogue] / plomrogue-server.py
index b921f4baa0ee9c6e8c3a122270f65ab718dfe73d..72e0fdb7225504833e7772a03919836b3d88dda0 100755 (executable)
@@ -6,6 +6,13 @@ import shutil
 import time
 
 
+def strong_write(file, string):
+    """Apply write(string), flush(), and os.fsync() to file."""
+    file.write(string)
+    file.flush()
+    os.fsync(file)
+
+
 def setup_server_io():
     """Fill IO files DB with proper file( path)s. Write process IO test string.
 
@@ -25,8 +32,7 @@ def setup_server_io():
     io_db["teststring"] = str(os.getpid()) + " " + str(time.time())
     os.makedirs(io_db["path_server"], exist_ok=True)
     io_db["file_out"] = open(io_db["path_out"], "w")
-    io_db["file_out"].write(io_db["teststring"] + "\n")
-    io_db["file_out"].flush()
+    strong_write(io_db["file_out"], io_db["teststring"] + "\n")
     if os.access(io_db["path_in"], os.F_OK):
         os.remove(io_db["path_in"])
     io_db["file_in"] = open(io_db["path_in"], "w")
@@ -101,9 +107,7 @@ def atomic_write(path, text, do_append=False):
         if os.access(path, os.F_OK):
             shutil.copyfile(path, path_tmp)
     file = open(path_tmp, mode)
-    file.write(text)
-    file.flush()
-    os.fsync(file.fileno())
+    strong_write(file, text)
     file.close()
     if os.access(path, os.F_OK):
         os.remove(path)
@@ -160,7 +164,7 @@ def save_world():
 
     string = ""
     for key in world_db:
-        if dict != type(world_db[key]):
+        if dict != type(world_db[key]) and key != "MAP":
             string = string + key + " " + str(world_db[key]) + "\n"
     string = string + helper("ThingActions", "TA_ID")
     string = string + helper("ThingTypes", "TT_ID", {"TT_CORPSE_ID": False})
@@ -270,7 +274,7 @@ def try_worldstate_update():
             string = string + line + "\n"
         # TODO: no proper user-subjective map
         atomic_write(io_db["path_worldstate"], string)
-        atomic_write(io_db["path_out"], "WORLD_UPDATED\n", do_append=True)
+        strong_write(io_db["file_out"], "WORLD_UPDATED\n")
         io_db["worldstate_updateable"] = False
 
 
@@ -377,6 +381,25 @@ def setter(category, key, min, max):
     return f
 
 
+def new_Thing(type):
+    """Return prototype for Thing of T_TYPE of type."""
+    return {
+        "T_LIFEPOINTS": world_db["ThingTypes"][type]["TT_LIFEPOINTS"],
+        "T_ARGUMENT": 0,
+        "T_PROGRESS": 0,
+        "T_SATIATION": 0,
+        "T_COMMAND": 0,
+        "T_TYPE": type,
+        "T_POSY": 0,
+        "T_POSX": 0,
+        "T_CARRIES": [],
+        "carried": False,
+        "T_MEMTHING": [],
+        "T_MEMMAP": False,
+        "T_MEMDEPTHMAP": False
+    }
+
+
 def id_setter(id, category, id_store=False, start_at_1=False):
     """Set ID of object of category to manipulate ID unused? Create new one.
 
@@ -414,8 +437,7 @@ def id_setter(id, category, id_store=False, start_at_1=False):
 
 def command_ping():
     """Send PONG line to server output file."""
-    io_db["file_out"].write("PONG\n")
-    io_db["file_out"].flush()
+    strong_write(io_db["file_out"], "PONG\n")
 
 
 def command_quit():
@@ -435,8 +457,18 @@ def command_seedmap(seed_string):
 
 
 def command_makeworld(seed_string):
-    # DUMMY.
+    """(Re-)build game world, i.e. map, things, to a new turn 1 from seed.
+
+    Make seed world_db["SEED_RANDOMNESS"] and world_db["SEED_MAP"]. Do more
+    only with a "wait" ThingAction and world["PLAYER_TYPE"] matching ThingType
+    of TT_START_NUMBER > 0. Then, world_db["Things"] emptied, call remake_map()
+    and set world_db["WORLD_ACTIVE"], world_db["TURN"] to 1. Build new Things
+    according to ThingTypes' TT_START_NUMBERS, with Thing of ID 0 to ThingType
+    of ID = world["PLAYER_TYPE"]. Place Things randomly, and actors not on each
+    other. Init player's FOV/memory map. Write "NEW_WORLD" line to out file.
+    """
     setter(None, "SEED_RANDOMNESS", 0, 4294967295)(seed_string)
+    setter(None, "SEED_MAP", 0, 4294967295)(seed_string)
     player_will_be_generated = False
     playertype = world_db["PLAYER_TYPE"]
     for ThingType in world_db["ThingTypes"]:
@@ -456,42 +488,37 @@ def command_makeworld(seed_string):
         print("Ignoring beyond SEED_MAP: " +
               "No thing action with name 'wait' defined.")
         return
-    setter(None, "SEED_MAP", 0, 4294967295)(seed_string)
     world_db["Things"] = {}
     remake_map()
     world_db["WORLD_ACTIVE"] = 1
     world_db["TURN"] = 1
     for i in range(world_db["ThingTypes"][playertype]["TT_START_NUMBER"]):
-        world_db["Things"][id_setter(-1, "Things")] = {
-            "T_LIFEPOINTS": world_db["ThingTypes"][playertype]["TT_LIFEPOINTS"],
-            "T_TYPE": playertype,
-            "T_POSY": 0, # randomize safely
-            "T_POSX": 0, # randomize safely
-            "T_ARGUMENT": 0,
-            "T_PROGRESS": 0,
-            "T_SATIATION": 0,
-            "T_COMMAND": 0,
-            "T_CARRIES": [],
-            "carried": False,
-            "T_MEMTHING": [],
-            "T_MEMMAP": False,
-            "T_MEMDEPTHMAP": False
-        }
-    # generate fov map?
-    # TODO: Generate things (player first, with updated memory)
-    atomic_write(io_db["path_out"], "NEW_WORLD\n", do_append=True)
+        id = id_setter(-1, "Things")
+        world_db["Things"][id] = new_Thing(playertype)
+    # TODO: Positioning. Init player's FOV / memory map.
+    for type in world_db["ThingTypes"]:
+        for i in range(world_db["ThingTypes"][type]["TT_START_NUMBER"]):
+            id = id_setter(-1, "Things")
+            world_db["Things"][id] = new_Thing(playertype)
+    # TODO: Positioning.
+    strong_write(io_db["file_out"], "NEW_WORLD\n")
 
 
 def command_maplength(maplength_string):
-    # DUMMY.
+    """Redefine map length. Invalidate map, therefore lose all things on it."""
     set_world_inactive()
-    # TODO: remove map (is this necessary? no memory management trouble …)
     world_db["Things"] = {}
     setter(None, "MAP_LENGTH", 1, 256)(maplength_string)
 
 
 def command_worldactive(worldactive_string):
-    # DUMMY.
+    """Toggle world_db["WORLD_ACTIVE"] if possible.
+
+    An active world can always be set inactive. An inactive world can only be
+    set active with a "wait" ThingAction, and a player Thing (of ID 0). On
+    activation, rebuild all Things' FOVs and map memories.
+    """
+    # In original version, map existence was also tested (unnecessarily?).
     val = integer_test(worldactive_string, 0, 1)
     if val:
         if 0 != world_db["WORLD_ACTIVE"]:
@@ -510,8 +537,7 @@ def command_worldactive(worldactive_string):
                 if 0 == Thing:
                     player_exists = True
                     break
-            map_exists = "MAP" in world_db
-            if wait_exists and player_exists and map_exists:
+            if wait_exists and player_exists:
                 # TODO: rebuild all things' FOVs, map memories
                 world_db["WORLD_ACTIVE"] = 1
 
@@ -539,21 +565,8 @@ def command_tid(id_string):
         if world_db["ThingTypes"] == {}:
             print("Ignoring: No ThingType to settle new Thing in.")
             return
-        world_db["Things"][id] = {
-            "T_LIFEPOINTS": 0,
-            "T_ARGUMENT": 0,
-            "T_PROGRESS": 0,
-            "T_SATIATION": 0,
-            "T_COMMAND": 0,
-            "T_TYPE": list(world_db["ThingTypes"].keys())[0],
-            "T_POSY": 0,
-            "T_POSX": 0,
-            "T_CARRIES": [],
-            "carried": False,
-            "T_MEMTHING": [],
-            "T_MEMMAP": False,
-            "T_MEMDEPTHMAP": False
-        }
+        type = list(world_db["ThingTypes"].keys())[0]
+        world_db["Things"][id] = new_Thing(type)
 
 
 test_Thing_id = test_for_id_maker(command_tid, "Thing")
@@ -797,7 +810,7 @@ commands_db = {
 
 """World state database. With sane default values."""
 world_db = {
-    "TURN": 1,
+    "TURN": 0,
     "SEED_MAP": 0,
     "SEED_RANDOMNESS": 0,
     "PLAYER_TYPE": 0,