fix patcher functionality (hints TODO)

This commit is contained in:
duncathan 2021-12-01 01:28:01 -06:00
parent ea83e7643f
commit e38dcdb197
2 changed files with 57 additions and 28 deletions

View file

@ -1,5 +1,5 @@
from pathlib import Path from pathlib import Path
from typing import Optional from typing import Callable, Optional
from lupa import LuaRuntime from lupa import LuaRuntime
import logging import logging
import shutil import shutil
@ -8,15 +8,27 @@ pre_edited_cs = __import__("pre-edited-cs")
CSVERSION = 3 CSVERSION = 3
def patch_files(patch_data: dict, output_dir: Path): def patch_files(patch_data: dict, output_dir: Path, progress_update: Callable[[str, float], None]):
progress_update("Copying base files...", 0.0)
ensure_base_files_exist(output_dir) ensure_base_files_exist(output_dir)
TscFile = LuaRuntime().eval(Path(__file__).parent.joinpath("tsc_file.lua").read_text()) mapcount = len(patch_data["maps"].keys())
for mapname, mapdata in patch_data["maps"].items():
lua_file = Path(__file__).parent.joinpath("tsc_file.lua").read_text()
try:
TscFile = LuaRuntime().execute(lua_file)
except Exception as e:
print(lua_file)
raise e
for i, (mapname, mapdata) in enumerate(patch_data["maps"].items()):
progress_update(f"Patching {mapname}...", i/mapcount)
patch_map(mapname, mapdata, TscFile, output_dir) patch_map(mapname, mapdata, TscFile, output_dir)
progress_update("Copying MyChar...", 1.0)
patch_mychar(patch_data["mychar"], output_dir) patch_mychar(patch_data["mychar"], output_dir)
progress_update("Copying hash...", 1.0)
patch_hash(patch_data["hash"], output_dir) patch_hash(patch_data["hash"], output_dir)
def ensure_base_files_exist(output_dir: Path): def ensure_base_files_exist(output_dir: Path):
@ -25,16 +37,19 @@ def ensure_base_files_exist(output_dir: Path):
version = output_dir.joinpath("data", "Stage", "_version.txt") version = output_dir.joinpath("data", "Stage", "_version.txt")
keep_existing_files = version.exists() and int(version.read_text()) >= CSVERSION keep_existing_files = version.exists() and int(version.read_text()) >= CSVERSION
def should_ignore(path: Path, names: list[str]): def should_ignore(path: str, names: list[str]):
if not keep_existing_files: base = ["__init__.py", "__pycache__"]
return [] if keep_existing_files:
return [path.joinpath(name) for name in names if path.joinpath(name).exists() and path.joinpath(name).is_file()] p = Path(path)
base.extend([p.joinpath(name) for name in names if p.joinpath(name).exists() and p.joinpath(name).is_file()])
shutil.copytree(internal_copy, output_dir, ignore=should_ignore) return base
shutil.copytree(internal_copy, output_dir, ignore=should_ignore, dirs_exist_ok=True)
output_dir.joinpath("data", "Plaintext").mkdir(exist_ok=True)
def patch_map(mapname: str, mapdata: dict[str, dict], TscFile, output_dir: Path): def patch_map(mapname: str, mapdata: dict[str, dict], TscFile, output_dir: Path):
mappath = output_dir.joinpath("data", "Stage", f"{mapname}.tsc") mappath = output_dir.joinpath("data", "Stage", f"{mapname}.tsc")
tsc_file = TscFile.new({}, mappath.read_bytes(), logging.getLogger("caver")) tsc_file = TscFile.new(TscFile, mappath.read_bytes(), logging.getLogger("caver"))
for event, script in mapdata["pickups"].items(): for event, script in mapdata["pickups"].items():
TscFile.placeItemAtLocation(tsc_file, script, event, mapname) TscFile.placeItemAtLocation(tsc_file, script, event, mapname)
@ -44,9 +59,13 @@ def patch_map(mapname: str, mapdata: dict[str, dict], TscFile, output_dir: Path)
for event, script in mapdata["entrances"].items(): for event, script in mapdata["entrances"].items():
TscFile.placeTraAtEntrance(tsc_file, script, event, mapname) TscFile.placeTraAtEntrance(tsc_file, script, event, mapname)
for event, script in mapdata["hints"].items():
TscFile.placeHintAtEvent(tsc_file, script, event, mapname)
mappath.write_bytes(TscFile.getText(tsc_file)) chars = TscFile.getText(tsc_file).values()
output_dir.joinpath("data", "Plaintext", f"{mapname}.txt") mappath.write_bytes(bytes(chars))
output_dir.joinpath("data", "Plaintext", f"{mapname}.txt").write_text(TscFile.getPlaintext(tsc_file))
def patch_mychar(mychar: Optional[str], output_dir: Path): def patch_mychar(mychar: Optional[str], output_dir: Path):
if mychar is None: if mychar is None:

View file

@ -1,8 +1,11 @@
local TscFile = {} local TscFile = {}
function TscFile:new(contents, py_logging) function TscFile:new(contents)
self.log = py_logging o = {}
setmetatable(o, self)
self.__index = self
self._text = self:_codec(contents, 'decode') self._text = self:_codec(contents, 'decode')
return o
end end
function TscFile:placeItemAtLocation(script, event, mapname) function TscFile:placeItemAtLocation(script, event, mapname)
@ -10,7 +13,7 @@ function TscFile:placeItemAtLocation(script, event, mapname)
self._text, wasChanged = self:_stringReplace(self._text, "<EVE....", script, event) self._text, wasChanged = self:_stringReplace(self._text, "<EVE....", script, event)
if not wasChanged then if not wasChanged then
local template = 'Unable to place script "%s" at [%s] event "%s".' local template = 'Unable to place script "%s" at [%s] event "%s".'
self.log.error(template:format(script, mapname, event)) error(template:format(script, mapname, event))
end end
end end
@ -19,7 +22,7 @@ function TscFile:placeSongAtCue(songid, event, originalid, mapname)
self._text, wasChanged = self:_stringReplace(self._text, "<CMU" .. originalid, "<CMU" .. songid, event, {"<CMU0015", "<CMU0000"}) self._text, wasChanged = self:_stringReplace(self._text, "<CMU" .. originalid, "<CMU" .. songid, event, {"<CMU0015", "<CMU0000"})
if not wasChanged then if not wasChanged then
local template = "Unable to replace [%s] event #%s's music cue with %q." local template = "Unable to replace [%s] event #%s's music cue with %q."
self.log.warning(template:format(mapname, event, songid)) error(template:format(mapname, event, songid))
end end
end end
@ -27,6 +30,10 @@ function TscFile:placeTraAtEntrance(script, event, mapname)
return -- TODO for entrance rando return -- TODO for entrance rando
end end
function TscFile:placeHintAtEvent(script, event, mapname)
return -- TODO
end
function TscFile:_stringReplace(text, needle, replacement, label, overrides) function TscFile:_stringReplace(text, needle, replacement, label, overrides)
overrides = overrides or {} overrides = overrides or {}
local pStart, pEnd = self:_getLabelPositionRange(label) local pStart, pEnd = self:_getLabelPositionRange(label)
@ -37,11 +44,11 @@ function TscFile:_stringReplace(text, needle, replacement, label, overrides)
i = text:find(needle, pStart) i = text:find(needle, pStart)
if i == nil then if i == nil then
self.log.debug(('Unable to replace "%s" with "%s"'):format(needle, replacement)) -- print(('Unable to replace "%s" with "%s"'):format(needle, replacement))
return text, false return text, false
elseif i > pEnd then elseif i > pEnd then
-- This is totally normal and can be ignored. -- This is totally normal and can be ignored.
self.log.debug(('Found "%s", but was outside of label.'):format(needle, replacement)) -- print(('Found "%s", but was outside of label.'):format(needle, replacement))
return text, false return text, false
end end
@ -112,7 +119,7 @@ function TscFile:_getLabelPositionRange(label)
end end
if labelStart == nil then if labelStart == nil then
self.log.error(("%s: Could not find label: %s"):format(self.mapName, label)) error(("%s: Could not find label: %s"):format(self.mapName, label))
labelStart = 1 labelStart = 1
end end
@ -147,20 +154,23 @@ function TscFile:_codec(text, mode)
error('Unknown codec mode: ' .. tostring(mode)) error('Unknown codec mode: ' .. tostring(mode))
end end
self.log.debug(" filesize", #chars)
self.log.debug(" encoding char:", encodingChar)
self.log.debug(" encoding char position:", encodingCharPosition)
-- Encode or decode. -- Encode or decode.
for pos, char in ipairs(chars) do for pos, char in ipairs(chars) do
if pos ~= encodingCharPosition then if pos ~= encodingCharPosition then
local byte = (char:byte() + encodingChar) % 256 local byte = (char:byte() + encodingChar) % 256
chars[pos] = string.char(byte) if mode == 'decode' then
chars[pos] = string.char(byte)
else
chars[pos] = byte
end
elseif mode == 'encode' then
chars[pos] = char:byte()
end end
end end
local decoded = table.concat(chars) if mode == 'encode' then
return chars
return decoded end
return table.concat(chars)
end end
return TscFile return TscFile