Scale contracts. Warning-as-a-MOTD. Restructure flask routes.
authorJoann Mõndresku <joann@cernodile.com>
Fri, 17 May 2024 17:32:09 +0000 (20:32 +0300)
committerJoann Mõndresku <joann@cernodile.com>
Fri, 17 May 2024 17:32:09 +0000 (20:32 +0300)
app.py
contracts.py
data/contracts.json

diff --git a/app.py b/app.py
index eaef3d5e8776c2d3a915faedc57fded8114ddbd1..9ad2d1580a78afd65c54f4dbe435890b5a85706a 100644 (file)
--- a/app.py
+++ b/app.py
@@ -22,76 +22,93 @@ app = Flask(__name__)
 contracts.load_contracts()
 db_store.create_backups_db()
 
-@app.route('/ei/<path:subpath>', methods=['POST'])
-def ei_routes(subpath):
-       print("REQ: /ei/" + subpath)
-       if subpath == "daily_gift_info":
-               DateInfo = (datetime.datetime.now() - datetime.datetime(1970, 1, 1))
-               GiftResponse = EIProto.DailyGiftInfo()
-               GiftResponse.current_day = DateInfo.days
-               GiftResponse.seconds_to_next_day = 86400 - DateInfo.seconds
-               return base64.b64encode(GiftResponse.SerializeToString())
+# /ei/ routes
+@app.route('/ei/first_contact', methods=['POST'])
+def ei_first_contact():
        data = base64.b64decode(request.form["data"].replace(" ", "+"))
-       if subpath == "first_contact":
-               ContactReq = EIProto.EggIncFirstContactRequest()
-               ContactReq.ParseFromString(data)
-               ContactResp = EIProto.EggIncFirstContactResponse()
-               Backups = db_store.get_backups(ContactReq.user_id)
-               if len(Backups) > 0:
-                       # Lets process backups - check for any forced ones first
-                       now = datetime.datetime.now()
-                       cleanup_ids = []
-                       for backup in Backups:
-                               if backup[2] == True:
-                                       # Force backup found - lets serialize the payload
-                                       SaveBackup = EIProto.Backup()
-                                       try:
-                                               SaveBackup.ParseFromString(base64.b64decode(zlib.decompress(backup[3])))
-                                               SaveBackup.force_backup = True
-                                               SaveBackup.force_offer_backup = True
-                                               ContactResp.backup.CopyFrom(SaveBackup)
-                                               db_store.update_backup(backup[0], backup[3], False)
-                                               break
-                                       except:
-                                               print("Failed to force serve backup - perhaps some logic error?")
-                                               break
-                               else:
-                                       then = datetime.datetime.fromtimestamp(backup[1])
-                                       if (now - then).days > 1:
-                                               cleanup_ids.append(backup[0])
-                       if len(cleanup_ids) > 0:
-                               db_store.cleanup_backups(cleanup_ids)
-                       # TODO: Check for soul eggs/eggs of prophecy and determine algorithm for "is it worth offering?"
-               elif ContactReq.user_id in upgrade_cache:
-                       print("Found an unupgraded save - lets upgrade the permit level to Pro")
-                       ContactResp.backup.CopyFrom(cache[ContactReq.user_id])
-                       del upgrade_cache[ContactReq.user_id]
-               return base64.b64encode(ContactResp.SerializeToString())
-       elif subpath == "save_backup":
-               SaveBackup = EIProto.Backup()
-               SaveBackup.ParseFromString(bytes(data))
-               #print(SaveBackup)
-               if SaveBackup.game.permit_level == 0:
-                       SaveBackup.game.permit_level = 1
-                       SaveBackup.force_backup = True
-                       SaveBackup.force_offer_backup = True
-                       upgrade_cache[SaveBackup.user_id] = SaveBackup
-               else:
-                       # start storing backups after permit upgrades
-                       db_store.add_backup(SaveBackup.user_id, base64.b64encode(zlib.compress(SaveBackup.SerializeToString())))
-       elif subpath == "get_periodicals":
-               PeriodicalResp = EIProto.PeriodicalsResponse()
-               for evt in events.get_active_events():
-                       e = PeriodicalResp.events.events.add()
-                       e.CopyFrom(evt)
-               for contract in contracts.get_active_contracts():
-                       c = PeriodicalResp.contracts.contracts.add()
-                       c.CopyFrom(contract)
-               return base64.b64encode(PeriodicalResp.SerializeToString())
+       ContactReq = EIProto.EggIncFirstContactRequest()
+       ContactReq.ParseFromString(data)
+       ContactResp = EIProto.EggIncFirstContactResponse()
+       Backups = db_store.get_backups(ContactReq.user_id)
+       if len(Backups) > 0:
+               # Lets process backups - check for any forced ones first
+               now = datetime.datetime.now()
+               cleanup_ids = []
+               for backup in Backups:
+                       if backup[2] == True:
+                               # Force backup found - lets serialize the payload
+                               SaveBackup = EIProto.Backup()
+                               try:
+                                       SaveBackup.ParseFromString(base64.b64decode(zlib.decompress(backup[3])))
+                                       SaveBackup.force_backup = True
+                                       SaveBackup.force_offer_backup = True
+                                       ContactResp.backup.CopyFrom(SaveBackup)
+                                       db_store.update_backup(backup[0], backup[3], False)
+                                       break
+                               except:
+                                       print("Failed to force serve backup - perhaps some logic error?")
+                                       break
+                       else:
+                               then = datetime.datetime.fromtimestamp(backup[1])
+                       if (now - then).days > 1:
+                                       cleanup_ids.append(backup[0])
+               if len(cleanup_ids) > 0:
+                       db_store.cleanup_backups(cleanup_ids)
+               # TODO: Check for soul eggs/eggs of prophecy and determine algorithm for "is it worth offering?"
+       elif ContactReq.user_id in upgrade_cache:
+               print("Found an unupgraded save - lets upgrade the permit level to Pro")
+               ContactResp.backup.CopyFrom(cache[ContactReq.user_id])
+               del upgrade_cache[ContactReq.user_id]
+       return base64.b64encode(ContactResp.SerializeToString())
+
+@app.route('/ei/save_backup', methods=['POST'])
+def ei_save_backup():
+       data = base64.b64decode(request.form["data"].replace(" ", "+"))
+       SaveBackup = EIProto.Backup()
+       SaveBackup.ParseFromString(bytes(data))
+       #print(SaveBackup)
+       if SaveBackup.game.permit_level == 0:
+               SaveBackup.game.permit_level = 1
+               SaveBackup.force_backup = True
+               SaveBackup.force_offer_backup = True
+               upgrade_cache[SaveBackup.user_id] = SaveBackup
        else:
-               print("DATA", base64.b64encode(data))
+               # start storing backups after permit upgrades
+               db_store.add_backup(SaveBackup.user_id, base64.b64encode(zlib.compress(SaveBackup.SerializeToString())))
        return ""
 
+@app.route('/ei/daily_gift_info', methods=['POST'])
+def ei_daily_gift_info():
+       DateInfo = (datetime.datetime.now() - datetime.datetime(1970, 1, 1))
+       GiftResponse = EIProto.DailyGiftInfo()
+       GiftResponse.current_day = DateInfo.days
+       GiftResponse.seconds_to_next_day = 86400 - DateInfo.seconds
+       return base64.b64encode(GiftResponse.SerializeToString())
+
+@app.route('/ei/get_periodicals', methods=['POST'])
+def ei_periodicals_request():
+       PeriodicalResp = EIProto.PeriodicalsResponse()
+       PeriodicalResp.contracts.warning_message = "Welcome to reEgg Server Emulator\nLeggacy contracts available every Monday/Friday"
+       for evt in events.get_active_events():
+               e = PeriodicalResp.events.events.add()
+               e.CopyFrom(evt)
+       for contract in contracts.get_active_contracts():
+               c = PeriodicalResp.contracts.contracts.add()
+               c.CopyFrom(contract)
+       return base64.b64encode(PeriodicalResp.SerializeToString())
+
+@app.route('/ei/<path:subpath>', methods=['POST'])
+def ei_unidentified_routes(subpath):
+       print("UNIMPLEMENTED REQ: /ei/" + subpath)
+       if not request.form or "data" not in request.form:
+               print("No data included in request")
+               return "", 404
+       data = base64.b64decode(request.form["data"].replace(" ", "+"))
+       print("DATA", base64.b64encode(data))
+       return "", 404
+
+
+# /ei_data/ routes
 @app.route('/ei_data/<path:subpath>', methods=['POST'])
 def ei_data_rotues(subpath):
        print("REQ /ei_data/" + subpath)
@@ -104,6 +121,7 @@ def ei_data_rotues(subpath):
                print(request.form)
        return ""
 
+# /ei_ps/ routes (custom)
 # TODO: ratelimit this
 @app.route('/ei_ps/<userid>/<method>', methods=['POST'])
 def ei_ps_routes(userid, method):
index f47a63adb53e53c921f7cdf5277d7dec96e90a98..0f40b9b4f284b2e1300fecab05fabd06ef1c54de 100644 (file)
@@ -2,6 +2,10 @@
 import ei_pb2 as EIProto
 import json
 import time
+import math
+
+# TODO: Co-op contracts, toggle this off when we have them
+ALL_SOLO_CONTRACTS = True
 
 # Keep a cache of all contracts
 contract_epoch = int(time.time())
@@ -16,9 +20,9 @@ def get_active_contracts():
        time_since_epoch = time.time() - contract_epoch
        i = 0
        for contract in global_contract_db["legacy"]:
-               # Leggacy ones are active for a week, one per week
+               # Leggacy ones are active for a week, twice per week
                i += 1
-               expiry_time = (604800 * i) - time_since_epoch
+               expiry_time = (604800 * math.ceil(i / 2)) + (345600 if not i % 2 else 0) - time_since_epoch
                # It's expired, get the next one
                if expiry_time < 0:
                        continue
@@ -41,12 +45,19 @@ def __convert_contract_to_proto(obj):
        contract.minutes_per_token = obj["token_interval"]
        contract.length_seconds = obj["duration"]
        contract.coop_allowed = False
+       scaler = 1.0
+       if ALL_SOLO_CONTRACTS and "coop_members" in obj:
+               # Not all contracts are made equal. If we divide it at an absolute, it becomes too easy
+               # Still need to pinpoint the ratio based on experience.
+               scale_factor = obj["coop_members"] * 0.35
+               if scale_factor > 1.0:
+                       scaler = 1.0 / scale_factor
        for goal_set_src in obj["goalsets"]:
                goal_set = contract.goal_sets.add()
                for goal_src in goal_set_src:
                        goal = goal_set.goals.add()
                        goal.type = EIProto.GoalType.EGGS_LAID
-                       goal.target_amount = goal_src["deliver"]
+                       goal.target_amount = goal_src["deliver"] * scaler
                        goal.reward_type = EIProto.RewardType.Value(goal_src["reward_type"])
                        if goal.reward_type == EIProto.RewardType.BOOST:
                                goal.reward_sub_type = goal_src["reward_str"]
index 0202e05385de1d824eecd7b4c95cabc6a8d9ccda..87897e9e763c6630e2e5b1f8955a5d6715a60d61 100644 (file)
@@ -7,6 +7,7 @@
       "description": "A Quantum rift is causing people to hear different words in a viral video. Scientists have a fix but they need your help.",
       "duration": 345600.0,
       "token_interval": 60.0,
+      "coop_members": 7,
       "egg": "QUANTUM",
       "goalsets": [
         [
@@ -91,6 +92,7 @@
       "description": "A mysterious investor is looking for a lot of edible eggs.\nBut he wants the full amount or nothing.",
       "duration": 799980.0,
       "token_interval": 60.0,
+      "coop_members": 3,
       "egg": "EDIBLE",
       "goalsets": [
         [
       "description": "Spaceflight is booming due to re-usable rockets.\nHelp fill the demand with this contract.",
       "duration": 604800.0,
       "token_interval": 120.0,
+      "coop_members": 6,
       "egg": "ROCKET_FUEL",
       "goalsets": [
         [