From efc5e5c0a011a21dcc1233f6f36cf78ec43a9bc0 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Joann=20M=C3=B5ndresku?= Date: Fri, 17 May 2024 20:32:09 +0300 Subject: [PATCH] Scale contracts. Warning-as-a-MOTD. Restructure flask routes. --- app.py | 150 +++++++++++++++++++++++++------------------- contracts.py | 17 ++++- data/contracts.json | 3 + 3 files changed, 101 insertions(+), 69 deletions(-) diff --git a/app.py b/app.py index eaef3d5..9ad2d15 100644 --- a/app.py +++ b/app.py @@ -22,76 +22,93 @@ app = Flask(__name__) contracts.load_contracts() db_store.create_backups_db() -@app.route('/ei/', 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/', 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/', 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//', methods=['POST']) def ei_ps_routes(userid, method): diff --git a/contracts.py b/contracts.py index f47a63a..0f40b9b 100644 --- a/contracts.py +++ b/contracts.py @@ -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"] diff --git a/data/contracts.json b/data/contracts.json index 0202e05..87897e9 100644 --- a/data/contracts.json +++ b/data/contracts.json @@ -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": [ [ @@ -117,6 +119,7 @@ "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": [ [ -- 2.25.1