Compare commits

...

7 Commits

Author SHA1 Message Date
black-sliver
53ef2aa786 setup.py: downgrade cx_freeze (#865)
Latest cx_freeze breaks tkinter/tcl on linux
2022-09-13 08:36:09 +02:00
TheBigSalarius
156e9e0e43 FF1: Throw exception for Noverworld 2022-09-12 03:48:07 +02:00
Fabian Dill
ef46979bd8 SC2: fix client freezing on exit while SC2 is running (#1011) 2022-09-12 02:08:33 +02:00
Fabian Dill
b2aa251c47 SC2: fix bitflag overflow when multiple instances of an Item are acquired (#1008) 2022-09-12 01:51:25 +02:00
Fabian Dill
e204a0fce6 Subnautica: fix missed item and correct other item pool counts to fit it 2022-09-12 01:44:10 +02:00
TheBigSalarius
bb386d3bd7 FF1: fix FF1Client messaging and scoped lua messaging with printjson
Corrects the issue causing the client and lua messaging not displaying properly after the printjson changes
2022-09-12 01:19:51 +02:00
Fabian Dill
88a225764a FF1: fix printjson 2022-09-12 01:19:51 +02:00
10 changed files with 102 additions and 86 deletions

View File

@@ -5,6 +5,7 @@ import urllib.parse
import sys
import typing
import time
import functools
import ModuleUpdate
ModuleUpdate.update()
@@ -17,7 +18,8 @@ if __name__ == "__main__":
Utils.init_logging("TextClient", exception_logger="Client")
from MultiServer import CommandProcessor
from NetUtils import Endpoint, decode, NetworkItem, encode, JSONtoTextParser, ClientStatus, Permission, NetworkSlot
from NetUtils import Endpoint, decode, NetworkItem, encode, JSONtoTextParser, \
ClientStatus, Permission, NetworkSlot, RawJSONtoTextParser
from Utils import Version, stream_input
from worlds import network_data_package, AutoWorldRegister
import os
@@ -204,6 +206,10 @@ class CommonContext:
# execution
self.keep_alive_task = asyncio.create_task(keep_alive(self), name="Bouncy")
@functools.cached_property
def raw_text_parser(self) -> RawJSONtoTextParser:
return RawJSONtoTextParser(self)
@property
def total_locations(self) -> typing.Optional[int]:
"""Will return None until connected."""

View File

@@ -1,4 +1,5 @@
import asyncio
import copy
import json
import time
from asyncio import StreamReader, StreamWriter
@@ -6,7 +7,7 @@ from typing import List
import Utils
from CommonClient import CommonContext, server_loop, gui_enabled, console_loop, ClientCommandProcessor, logger, \
from CommonClient import CommonContext, server_loop, gui_enabled, ClientCommandProcessor, logger, \
get_base_parser
SYSTEM_MESSAGE_ID = 0
@@ -64,7 +65,7 @@ class FF1Context(CommonContext):
def _set_message(self, msg: str, msg_id: int):
if DISPLAY_MSGS:
self.messages[(time.time(), msg_id)] = msg
self.messages[time.time(), msg_id] = msg
def on_package(self, cmd: str, args: dict):
if cmd == 'Connected':
@@ -73,32 +74,28 @@ class FF1Context(CommonContext):
msg = args['text']
if ': !' not in msg:
self._set_message(msg, SYSTEM_MESSAGE_ID)
elif cmd == "ReceivedItems":
msg = f"Received {', '.join([self.item_names[item.item] for item in args['items']])}"
self._set_message(msg, SYSTEM_MESSAGE_ID)
elif cmd == 'PrintJSON':
print_type = args['type']
item = args['item']
receiving_player_id = args['receiving']
receiving_player_name = self.player_names[receiving_player_id]
sending_player_id = item.player
sending_player_name = self.player_names[item.player]
if print_type == 'Hint':
msg = f"Hint: Your {self.item_names[item.item]} is at" \
f" {self.player_names[item.player]}'s {self.location_names[item.location]}"
self._set_message(msg, item.item)
elif print_type == 'ItemSend' and receiving_player_id != self.slot:
if sending_player_id == self.slot:
if receiving_player_id == self.slot:
msg = f"You found your own {self.item_names[item.item]}"
else:
msg = f"You sent {self.item_names[item.item]} to {receiving_player_name}"
else:
if receiving_player_id == sending_player_id:
msg = f"{sending_player_name} found their {self.item_names[item.item]}"
else:
msg = f"{sending_player_name} sent {self.item_names[item.item]} to " \
f"{receiving_player_name}"
def on_print_json(self, args: dict):
if self.ui:
self.ui.print_json(copy.deepcopy(args["data"]))
else:
text = self.jsontotextparser(copy.deepcopy(args["data"]))
logger.info(text)
relevant = args.get("type", None) in {"Hint", "ItemSend"}
if relevant:
item = args["item"]
# goes to this world
if self.slot_concerns_self(args["receiving"]):
relevant = True
# found in this world
elif self.slot_concerns_self(item.player):
relevant = True
# not related
else:
relevant = False
if relevant:
item = args["item"]
msg = self.raw_text_parser(copy.deepcopy(args["data"]))
self._set_message(msg, item.item)
def run_gui(self):

View File

@@ -743,6 +743,7 @@ async def countdown(ctx: Context, timer: int):
broadcast_countdown(ctx, 0, f"[Server]: GO")
ctx.countdown_timer = 0
def broadcast_text_all(ctx: Context, text: str, additional_arguments: dict = {}):
old_clients, new_clients = [], []
@@ -755,8 +756,10 @@ def broadcast_text_all(ctx: Context, text: str, additional_arguments: dict = {})
ctx.broadcast(old_clients, [{"cmd": "Print", "text": text }])
ctx.broadcast(new_clients, [{**{"cmd": "PrintJSON", "data": [{ "text": text }]}, **additional_arguments}])
def broadcast_countdown(ctx: Context, timer: int, message: str):
broadcast_text_all(ctx, message, { "type": "Countdown", "countdown": timer })
broadcast_text_all(ctx, message, {"type": "Countdown", "countdown": timer})
def get_players_string(ctx: Context):
auth_clients = {(c.team, c.slot) for c in ctx.endpoints if c.auth}

View File

@@ -15,9 +15,6 @@ import typing
from json import loads, dumps
import ModuleUpdate
ModuleUpdate.update()
from Utils import init_logging, messagebox
if __name__ == "__main__":

View File

@@ -19,10 +19,11 @@ from sc2.data import Race
from sc2.main import run_game
from sc2.player import Bot
import NetUtils
from MultiServer import mark_raw
from Utils import init_logging, is_windows
from worlds.sc2wol import SC2WoLWorld
from worlds.sc2wol.Items import lookup_id_to_name, item_table
from worlds.sc2wol.Items import lookup_id_to_name, item_table, ItemData, type_flaggroups
from worlds.sc2wol.Locations import SC2WOL_LOC_ID_OFFSET
from worlds.sc2wol.MissionTables import lookup_id_to_mission
from worlds.sc2wol.Regions import MissionInfo
@@ -135,7 +136,7 @@ class SC2Context(CommonContext):
last_loc_list = None
difficulty_override = -1
mission_id_to_location_ids: typing.Dict[int, typing.List[int]] = {}
raw_text_parser: RawJSONtoTextParser
last_bot: typing.Optional[ArchipelagoBot] = None
def __init__(self, *args, **kwargs):
super(SC2Context, self).__init__(*args, **kwargs)
@@ -164,10 +165,13 @@ class SC2Context(CommonContext):
check_mod_install()
def on_print_json(self, args: dict):
# goes to this world
if "receiving" in args and self.slot_concerns_self(args["receiving"]):
relevant = True
# found in this world
elif "item" in args and self.slot_concerns_self(args["item"].player):
relevant = True
# not related
else:
relevant = False
@@ -355,6 +359,8 @@ class SC2Context(CommonContext):
async def shutdown(self):
await super(SC2Context, self).shutdown()
if self.last_bot:
self.last_bot.want_close = True
if self.sc2_run_task:
self.sc2_run_task.cancel()
@@ -431,47 +437,27 @@ wol_default_categories = [
]
def calculate_items(items):
unit_unlocks = 0
armory1_unlocks = 0
armory2_unlocks = 0
upgrade_unlocks = 0
building_unlocks = 0
merc_unlocks = 0
lab_unlocks = 0
protoss_unlock = 0
minerals = 0
vespene = 0
supply = 0
def calculate_items(items: typing.List[NetUtils.NetworkItem]) -> typing.List[int]:
network_item: NetUtils.NetworkItem
accumulators: typing.List[int] = [0 for _ in type_flaggroups]
for item in items:
data = lookup_id_to_name[item.item]
for network_item in items:
name: str = lookup_id_to_name[network_item.item]
item_data: ItemData = item_table[name]
if item_table[data].type == "Unit":
unit_unlocks += (1 << item_table[data].number)
elif item_table[data].type == "Upgrade":
upgrade_unlocks += (1 << item_table[data].number)
elif item_table[data].type == "Armory 1":
armory1_unlocks += (1 << item_table[data].number)
elif item_table[data].type == "Armory 2":
armory2_unlocks += (1 << item_table[data].number)
elif item_table[data].type == "Building":
building_unlocks += (1 << item_table[data].number)
elif item_table[data].type == "Mercenary":
merc_unlocks += (1 << item_table[data].number)
elif item_table[data].type == "Laboratory":
lab_unlocks += (1 << item_table[data].number)
elif item_table[data].type == "Protoss":
protoss_unlock += (1 << item_table[data].number)
elif item_table[data].type == "Minerals":
minerals += item_table[data].number
elif item_table[data].type == "Vespene":
vespene += item_table[data].number
elif item_table[data].type == "Supply":
supply += item_table[data].number
# exists exactly once
if item_data.quantity == 1:
accumulators[type_flaggroups[item_data.type]] |= 1 << item_data.number
return [unit_unlocks, upgrade_unlocks, armory1_unlocks, armory2_unlocks, building_unlocks, merc_unlocks,
lab_unlocks, protoss_unlock, minerals, vespene, supply]
# exists multiple times
elif item_data.type == "Upgrade":
accumulators[type_flaggroups[item_data.type]] += 1 << item_data.number
# sum
else:
accumulators[type_flaggroups[item_data.type]] += item_data.number
return accumulators
def calc_difficulty(difficulty):
@@ -502,7 +488,7 @@ class ArchipelagoBot(sc2.bot_ai.BotAI):
setup_done: bool
ctx: SC2Context
mission_id: int
want_close: bool = False
can_read_game = False
last_received_update: int = 0
@@ -510,12 +496,17 @@ class ArchipelagoBot(sc2.bot_ai.BotAI):
def __init__(self, ctx: SC2Context, mission_id):
self.setup_done = False
self.ctx = ctx
self.ctx.last_bot = self
self.mission_id = mission_id
self.boni = [False for _ in range(max_bonus)]
super(ArchipelagoBot, self).__init__()
async def on_step(self, iteration: int):
if self.want_close:
self.want_close = False
await self._client.leave()
return
game_state = 0
if not self.setup_done:
self.setup_done = True

View File

@@ -17,7 +17,7 @@ from Launcher import components, icon_paths
# This is a bit jank. We need cx-Freeze to be able to run anything from this script, so install it
import subprocess
import pkg_resources
requirement = 'cx-Freeze>=6.11'
requirement = 'cx-Freeze==6.10'
try:
pkg_resources.require(requirement)
import cx_Freeze
@@ -70,7 +70,7 @@ def _threaded_hash(filepath):
# cx_Freeze's build command runs other commands. Override to accept --yes and store that.
class BuildCommand(cx_Freeze.command.build.Build):
class BuildCommand(cx_Freeze.dist.build):
user_options = [
('yes', 'y', 'Answer "yes" to all questions.'),
]
@@ -87,8 +87,8 @@ class BuildCommand(cx_Freeze.command.build.Build):
# Override cx_Freeze's build_exe command for pre and post build steps
class BuildExeCommand(cx_Freeze.command.build_exe.BuildEXE):
user_options = cx_Freeze.command.build_exe.BuildEXE.user_options + [
class BuildExeCommand(cx_Freeze.dist.build_exe):
user_options = cx_Freeze.dist.build_exe.user_options + [
('yes', 'y', 'Answer "yes" to all questions.'),
('extra-data=', None, 'Additional files to add.'),
]

View File

@@ -66,7 +66,10 @@ class FF1World(World):
def goal_rule_and_shards(state):
return goal_rule(state) and state.has("Shard", self.player, 32)
terminated_event.access_rule = goal_rule_and_shards
if "MARK" in items.keys():
# Fail generation for Noverworld and provide link to old FFR website
raise Exception("FFR Noverworld seeds must be generated on an older version of FFR. Please ensure you generated the settings using "
"4-4-0.finalfantasyrandomizer.com")
menu_region.locations.append(terminated_event)
self.world.regions += [menu_region]

View File

@@ -163,3 +163,17 @@ filler_items: typing.Tuple[str, ...] = (
lookup_id_to_name: typing.Dict[int, str] = {data.code: item_name for item_name, data in get_full_item_list().items() if
data.code}
# Map type to expected int
type_flaggroups: typing.Dict[str, int] = {
"Unit": 0,
"Upgrade": 1,
"Armory 1": 2,
"Armory 2": 3,
"Building": 4,
"Mercenary": 5,
"Laboratory": 6,
"Protoss": 7,
"Minerals": 8,
"Vespene": 9,
"Supply": 10,
}

View File

@@ -139,7 +139,7 @@ item_table: Dict[int, ItemDict] = {
'name': 'Power Transmitter Fragment',
'tech_type': 'PowerTransmitterFragment'},
35032: {'classification': ItemClassification.progression,
'count': 4,
'count': 5,
'name': 'Prawn Suit Fragment',
'tech_type': 'ExosuitFragment'},
35033: {'classification': ItemClassification.useful,
@@ -163,7 +163,7 @@ item_table: Dict[int, ItemDict] = {
'name': 'Scanner Room Fragment',
'tech_type': 'BaseMapRoomFragment'},
35038: {'classification': ItemClassification.progression,
'count': 5,
'count': 4,
'name': 'Seamoth Fragment',
'tech_type': 'SeamothFragment'},
35039: {'classification': ItemClassification.progression,
@@ -203,9 +203,9 @@ item_table: Dict[int, ItemDict] = {
'name': 'Picture Frame',
'tech_type': 'PictureFrameFragment'},
35048: {'classification': ItemClassification.filler,
'count': 2,
'name': 'Bench Fragment',
'tech_type': 'BenchFragment'},
'count': 1,
'name': 'Bench',
'tech_type': 'Bench'},
35049: {'classification': ItemClassification.filler,
'count': 1,
'name': 'Basic Plant Pot',
@@ -333,7 +333,12 @@ item_table: Dict[int, ItemDict] = {
35080: {'classification': ItemClassification.filler,
'count': 1,
'name': 'Water Filtration Machine',
'tech_type': 'BaseFiltrationMachine'}}
'tech_type': 'BaseFiltrationMachine'},
35081: {'classification': ItemClassification.progression,
'count': 1,
'name': 'Ultra High Capacity Tank',
'tech_type': 'HighCapacityTank'},
}
advancement_item_names: Set[str] = set()
non_advancement_item_names: Set[str] = set()

View File

@@ -41,7 +41,7 @@ class SubnauticaWorld(World):
location_name_to_id = all_locations
option_definitions = Options.options
data_version = 6
data_version = 7
required_client_version = (0, 3, 5)
prefill_items: List[Item]