v6,sm64ex: Add support for offline singeplayer seeds (#301)
This commit is contained in:
parent
15e0763ed5
commit
97b1ae5ee9
|
@ -53,6 +53,10 @@ def download_slot_file(room_id, player_id: int):
|
||||||
fname = name.rsplit("/", 1)[0]+".zip"
|
fname = name.rsplit("/", 1)[0]+".zip"
|
||||||
elif slot_data.game == "Ocarina of Time":
|
elif slot_data.game == "Ocarina of Time":
|
||||||
fname = f"AP_{app.jinja_env.filters['suuid'](room_id)}_P{slot_data.player_id}_{slot_data.player_name}.apz5"
|
fname = f"AP_{app.jinja_env.filters['suuid'](room_id)}_P{slot_data.player_id}_{slot_data.player_name}.apz5"
|
||||||
|
elif slot_data.game == "VVVVVV":
|
||||||
|
fname = f"AP_{app.jinja_env.filters['suuid'](room_id)}_SP.apv6"
|
||||||
|
elif slot_data.game == "Super Mario 64":
|
||||||
|
fname = f"AP_{app.jinja_env.filters['suuid'](room_id)}_SP.apsm64ex"
|
||||||
else:
|
else:
|
||||||
return "Game download not supported."
|
return "Game download not supported."
|
||||||
return send_file(io.BytesIO(slot_data.data), as_attachment=True, attachment_filename=fname)
|
return send_file(io.BytesIO(slot_data.data), as_attachment=True, attachment_filename=fname)
|
||||||
|
|
|
@ -54,13 +54,19 @@ In case you are using the Archipelago Website, the IP should be `archipelago.gg`
|
||||||
|
|
||||||
If everything worked out, you will see a textbox informing you the connection has been established after the story intro.
|
If everything worked out, you will see a textbox informing you the connection has been established after the story intro.
|
||||||
|
|
||||||
|
# Playing offline
|
||||||
|
|
||||||
|
To play offline, first generate a seed on the game's settings page.
|
||||||
|
Create a room and download the `.apsm64ex` file, and start the game with the `--sm64ap_file FileName` launch argument.
|
||||||
|
|
||||||
## Installation Troubleshooting
|
## Installation Troubleshooting
|
||||||
|
|
||||||
Start the game from the command line to view helpful messages regarding SM64EX.
|
Start the game from the command line to view helpful messages regarding SM64EX.
|
||||||
|
|
||||||
### Game doesn't start after compiling
|
### Game doesn't start after compiling
|
||||||
|
|
||||||
Most likely you forgot to set the launch options. `--sm64ap_name YourName` and `--sm64ap_ip ServerIP:Port` are required for startup.
|
Most likely you forgot to set the launch options. `--sm64ap_name YourName` and `--sm64ap_ip ServerIP:Port` are required for startup for Multiworlds, and
|
||||||
|
`--sm64ap_file FileName` is required for (offline) singleplayer.
|
||||||
If your Name or Password have spaces in them, surround them in quotes.
|
If your Name or Password have spaces in them, surround them in quotes.
|
||||||
|
|
||||||
## Game Troubleshooting
|
## Game Troubleshooting
|
||||||
|
|
|
@ -20,13 +20,19 @@ In case you are using the Archipelago Website, the IP should be `archipelago.gg`
|
||||||
|
|
||||||
If everything worked out, you will see a textbox informing you the connection has been established after the story intro.
|
If everything worked out, you will see a textbox informing you the connection has been established after the story intro.
|
||||||
|
|
||||||
|
# Playing offline
|
||||||
|
|
||||||
|
To play offline, first generate a seed on the game's settings page.
|
||||||
|
Create a room and download the `.apv6` file, and start the game with the `-v6ap_file FileName` launch argument.
|
||||||
|
|
||||||
## Installation Troubleshooting
|
## Installation Troubleshooting
|
||||||
|
|
||||||
Start the game from the command line to view helpful messages regarding V6AP. These will look something like "V6AP: Message"
|
Start the game from the command line to view helpful messages regarding V6AP. These will look something like "V6AP: Message"
|
||||||
|
|
||||||
### Game no longer starts after copying the .exe
|
### Game no longer starts after copying the .exe
|
||||||
|
|
||||||
Most likely you forgot to set the launch options. `-v6ap_name YourName` and `-v6ap_ip ServerIP:Port` are required for startup.
|
Most likely you forgot to set the launch options. `-v6ap_name YourName` and `-v6ap_ip ServerIP:Port` are required for startup for Multiworlds, and
|
||||||
|
`-v6ap_file FileName` is required for (offline) singleplayer.
|
||||||
If your Name or Password have spaces in them, surround them in quotes.
|
If your Name or Password have spaces in them, surround them in quotes.
|
||||||
|
|
||||||
## Game Troubleshooting
|
## Game Troubleshooting
|
||||||
|
|
|
@ -34,6 +34,12 @@
|
||||||
{% elif patch.game == "Ocarina of Time" %}
|
{% elif patch.game == "Ocarina of Time" %}
|
||||||
<a href="{{ url_for("download_slot_file", room_id=room.id, player_id=patch.player_id) }}" download>
|
<a href="{{ url_for("download_slot_file", room_id=room.id, player_id=patch.player_id) }}" download>
|
||||||
Download APZ5 File...</a>
|
Download APZ5 File...</a>
|
||||||
|
{% elif patch.game == "VVVVVV" and room.seed.slots|length == 1 %}
|
||||||
|
<a href="{{ url_for("download_slot_file", room_id=room.id, player_id=patch.player_id) }}" download>
|
||||||
|
Download APV6 File...</a>
|
||||||
|
{% elif patch.game == "Super Mario 64" and room.seed.slots|length == 1 %}
|
||||||
|
<a href="{{ url_for("download_slot_file", room_id=room.id, player_id=patch.player_id) }}" download>
|
||||||
|
Download APSM64EX File...</a>
|
||||||
{% elif patch.game in ["A Link to the Past", "Secret of Evermore", "Super Metroid"] %}
|
{% elif patch.game in ["A Link to the Past", "Secret of Evermore", "Super Metroid"] %}
|
||||||
<a href="{{ url_for("download_patch", patch_id=patch.id, room_id=room.id) }}" download>
|
<a href="{{ url_for("download_patch", patch_id=patch.id, room_id=room.id) }}" download>
|
||||||
Download Patch File...</a>
|
Download Patch File...</a>
|
||||||
|
|
|
@ -47,6 +47,15 @@ def upload_zip_to_db(zfile: zipfile.ZipFile, owner=None, meta={"race": False}, s
|
||||||
player_id=metadata["player_id"],
|
player_id=metadata["player_id"],
|
||||||
game="Minecraft"))
|
game="Minecraft"))
|
||||||
|
|
||||||
|
elif file.filename.endswith(".apv6"):
|
||||||
|
_, seed_name, slot_id, slot_name = file.filename.split('.')[0].split('_', 3)
|
||||||
|
slots.add(Slot(data=zfile.open(file, "r").read(), player_name=slot_name,
|
||||||
|
player_id=int(slot_id[1:]), game="VVVVVV"))
|
||||||
|
elif file.filename.endswith(".apsm64ex"):
|
||||||
|
_, seed_name, slot_id, slot_name = file.filename.split('.')[0].split('_', 3)
|
||||||
|
slots.add(Slot(data=zfile.open(file, "r").read(), player_name=slot_name,
|
||||||
|
player_id=int(slot_id[1:]), game="Super Mario 64"))
|
||||||
|
|
||||||
elif file.filename.endswith(".zip"):
|
elif file.filename.endswith(".zip"):
|
||||||
# Factorio mods need a specific name or they do not function
|
# Factorio mods need a specific name or they do not function
|
||||||
_, seed_name, slot_id, slot_name = file.filename.rsplit("_", 1)[0].split("-", 3)
|
_, seed_name, slot_id, slot_name = file.filename.rsplit("_", 1)[0].split("-", 3)
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
import typing
|
import typing
|
||||||
|
import os
|
||||||
|
import json
|
||||||
from .Items import item_table, cannon_item_table, SM64Item
|
from .Items import item_table, cannon_item_table, SM64Item
|
||||||
from .Locations import location_table, SM64Location
|
from .Locations import location_table, SM64Location
|
||||||
from .Options import sm64_options
|
from .Options import sm64_options
|
||||||
|
@ -87,3 +89,24 @@ class SM64World(World):
|
||||||
"StarsToFinish": self.world.StarsToFinish[self.player].value,
|
"StarsToFinish": self.world.StarsToFinish[self.player].value,
|
||||||
"DeathLink": self.world.DeathLink[self.player].value,
|
"DeathLink": self.world.DeathLink[self.player].value,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def generate_output(self, output_directory: str):
|
||||||
|
if self.world.players != 1:
|
||||||
|
return
|
||||||
|
data = {
|
||||||
|
"slot_data": self.fill_slot_data(),
|
||||||
|
"location_to_item": {self.location_name_to_id[i] : item_table[self.world.get_location(i, self.player).item.name] for i in self.location_name_to_id},
|
||||||
|
"data_package": {
|
||||||
|
"data": {
|
||||||
|
"games": {
|
||||||
|
self.game: {
|
||||||
|
"item_name_to_id": self.item_name_to_id,
|
||||||
|
"location_name_to_id": self.location_name_to_id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
filename = f"AP_{self.world.seed_name}_P{self.player}_{self.world.get_player_name(self.player)}.apsm64ex"
|
||||||
|
with open(os.path.join(output_directory, filename), 'w') as f:
|
||||||
|
json.dump(data, f)
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import typing
|
import typing
|
||||||
|
import os, json
|
||||||
from .Items import item_table, V6Item
|
from .Items import item_table, V6Item
|
||||||
from .Locations import location_table, V6Location
|
from .Locations import location_table, V6Location
|
||||||
from .Options import v6_options
|
from .Options import v6_options
|
||||||
|
@ -61,3 +61,24 @@ class V6World(World):
|
||||||
"DeathLink": self.world.DeathLink[self.player].value,
|
"DeathLink": self.world.DeathLink[self.player].value,
|
||||||
"DeathLink_Amnesty": self.world.DeathLinkAmnesty[self.player].value
|
"DeathLink_Amnesty": self.world.DeathLinkAmnesty[self.player].value
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def generate_output(self, output_directory: str):
|
||||||
|
if self.world.players != 1:
|
||||||
|
return
|
||||||
|
data = {
|
||||||
|
"slot_data": self.fill_slot_data(),
|
||||||
|
"location_to_item": {self.location_name_to_id[i] : item_table[self.world.get_location(i, self.player).item.name] for i in self.location_name_to_id},
|
||||||
|
"data_package": {
|
||||||
|
"data": {
|
||||||
|
"games": {
|
||||||
|
self.game: {
|
||||||
|
"item_name_to_id": self.item_name_to_id,
|
||||||
|
"location_name_to_id": self.location_name_to_id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
filename = f"AP_{self.world.seed_name}_P{self.player}_{self.world.get_player_name(self.player)}.apv6"
|
||||||
|
with open(os.path.join(output_directory, filename), 'w') as f:
|
||||||
|
json.dump(data, f)
|
||||||
|
|
Loading…
Reference in New Issue