This allows multiple client/connector pairs to run at the same time. It also includes a few other miscellaneous small changes that accumulated as I went. They can be split if desired - Whatever the `client_socket:send` line (~440) was doing with that missing operator, it's no longer doing. Don't ask me how it was working before. Lua is witchcraft. - Removed the `settimeout(2)` which causes the infamous emulator freeze (and replaced it with a `settimeout(0)` when the server socket is created). It appears to be unnecessary to set a timeout for discovering a client. Maybe at some point in time it was useful to keep the success rate for connecting high, but it seems to not be a problem if the timeout is 0 instead. - Also updated the Emerald setup to remove mention of the freezing. - Connector script now picks the first port that's not in use in a range of 5 ports. - To summarize why I was previously under the impression that multiple running scripts would not detect when a port was in use: 1. Calling `socket.bind` in the existing script will first create an ipv6 socket. 2. A second concurrent script trying to bind to the same port would I think fail to create an ipv6 socket but then succeed in creating an ipv4 socket on the same port. 3. That second socket could never communicate with a client; extra clients would just bounce off the first script. 4. The third concurrent script will then fail on both and actually give an `address already in use` error. - I'm not _really_ sure what's going on there. But forcing one or the other by calling `socket.tcp4()` or `socket.tcp6()` means that only one script will believe it has the port while any others will give `address already in use` as you'd expect. - As a side note, our `socket.lua` is much wonkier than I had previously thought. I understand some parts were added for LADX and when BizHawk 2.9 came out, but as far back as the file's history in this repo, it has provided a strange, modified interface as compared to the file it was originally derived from, to no benefit as far as I can tell. - The connector script closes `server` once it finds a client and opens a new one if the connection drops. I'm not sure this ultimately has an effect, but it seems more proper. - If the connector script's main function returns because of some error or refusal to proceed, the script no longer tries to resume the coroutine it was part of, which would flood the log with irrelevant errors. - Creating `SyncError`s in `guarded_read` and `guarded_write` would raise its own error because the wrong variable was being used in its message. - A call to `_bizhawk.connect` can take a while as the client tries the possible ports. There's a modification that will wait on either the `connect` or the exit event. And if the exit event fires while still looking for a connector script, this cancels the `connect` so the window can close. - Related: It takes 2-3 seconds for a call to `asyncio.open_connection` to come back with any sort of response on my machine, which can be significant now that we're trying multiple ports in sequence. I guess it could fire off 5 tasks at once. Might cause some weirdness if there exist multiple scripts and multiple clients looking for each other at the same time. - Also related: The first time a client attempts to connect to a script, they accept each other and start communicating as expected. The second client to try that port seems to believe it connects and will then time out on the first message. And then all subsequent attempts to connect to that port by any client will be refused (as expected) until the script shuts down or restarts. I haven't been able to explain this behavior. It adds more time to a client's search for a script, but doesn't ultimately cause problems. |
||
---|---|---|
.. | ||
data | ||
docs | ||
test | ||
LICENSE | ||
README.md | ||
__init__.py | ||
client.py | ||
data.py | ||
items.py | ||
locations.py | ||
options.py | ||
pokemon.py | ||
regions.py | ||
rom.py | ||
rules.py | ||
sanity_check.py | ||
util.py |
README.md
Pokemon Emerald
Version 1.2.0
This README contains general info useful for understanding the world. Pretty much all the long lists of locations,
regions, and items are stored in data/
and (mostly) loaded in by data.py
. Access rules are in rules.py
. Check
data/README.md for more detailed information on the JSON files holding most of the data.
Warps
Quick note to start, you should not be defining or modifying encoded warps from this repository. They're encoded in the
source code repository for the mod, and then assigned to regions in data/regions/
. All warps in the game already exist
within extracted_data.json
, and all relevant warps are already placed in data/regions/
(unless they were deleted
accidentally).
Many warps are actually two or three events acting as one logical warp. Doorways, for example, are often 2 tiles wide indoors but only 1 tile wide outdoors. Both indoor warps point to the outdoor warp, and the outdoor warp points to only one of the indoor warps. We want to describe warps logically in a way that retains information about individual warp events. That way a 2-tile-wide doorway doesnt look like a one-way warp next to an unrelated two-way warp, but if we want to randomize the destinations of those warps, we can still get back each individual id of the multi-tile warp.
This is how warps are encoded:
{source_map}:{source_warp_ids}/{dest_map}:{dest_warp_ids}[!]
source_map
: The map the warp events are located insource_warp_ids
: The ids of all adjacent warp events in source_map which lead to the same destination (these must be in ascending order)dest_map
: The map of the warp event to which this one is connecteddest_warp_ids
: The ids of the warp events in dest_map[!]
: If the warp expects to lead to a destination which doesnot lead back to it, add a ! to the end
Example: MAP_LAVARIDGE_TOWN_HOUSE:0,1/MAP_LAVARIDGE_TOWN:4
Example 2: MAP_AQUA_HIDEOUT_B1F:14/MAP_AQUA_HIDEOUT_B1F:12!
Note: A warp must have its destination set to another warp event. However, that does not guarantee that the destination warp event will warp back to the source.
Note 2: Some warps only act as destinations and cannot actually be interacted with by the player as sources. These are usually places you fall from a hole above. At the time of writing, these are actually not accounted for, but there are no instances where it changes logical access.
Note 3: Some warp destinations go to the map MAP_DYNAMIC
and have a special warp id. These edge cases are:
- The Moving Truck
- Terra Cave
- Marine Cave
- The Department Store Elevator
- Secret Bases
- The Trade Center
- The Union Room
- The Record Corner
- 2P/4P Battle Colosseum
Note 4: The trick house on Route 110 changes the warp destinations of its entrance and ending room as you progress through the puzzles, but the source code only sets the trick house up for the first puzzle, and I assume the destination gets overwritten at run time when certain flags are set.