diff --git a/README.md b/README.md
index d5cdf04..09bdf67 100644
--- a/README.md
+++ b/README.md
@@ -43,7 +43,7 @@
If you want a bug to be fixed, open up an issue on the Github Repo and describe the issue, with steps to reproduce, operating system information, and/or terminal logs if applicable. If the program doesn't automatically open up with a terminal by default, then open up a terminal either by right-clicking and clicking 'Open in Terminal' in the context menu that pops up on Linux systems or on Windows systems, click the bar that shows the path to Snark and type 'cmd', then type in the name of the executable and hit enter (on Linux systems you need to type in './' before the executable name, otherwise the system will think it's a terminal command and not an executable). If it is a feature request, tag it as a feature request and describe what you want to have implemented into Snark. You can check the Official Snark Development Tracker to see your bug report or feature request while it's in progress.
External Libraries/Programs Used
- Snark uses some open-source libraries for proper usage, these libraries along with their licenses are shown in the table below:
+ Snark uses some libraries for proper usage, these libraries along with their licenses are shown in the table below:
diff --git a/helpers.py b/helpers.py
index ba8d3d7..c8b0c73 100644
--- a/helpers.py
+++ b/helpers.py
@@ -150,50 +150,85 @@ def __init__(self, qc):
self.qcLoc = os.path.dirname(qc)
self.cbarFrmt = False
- def crowbarFormatCheck(self):
+ def relPathCheck(self):
checks = 0
count = -1
- cd = False
- cdTex = 0
+ cd = ""
+ cdTex = ""
newCD = ""
- cdRef = 0
+ cdLoc = 0
newCDtex = ""
- cdTexR = 0
+ cdTexLoc = 0
self.newQC = self.qcf
self.newQCPath = ""
while checks < 2:
count += 1
- qcL = self.qcf[count]
- if qcL.startswith("$cdtex"):
- if qcL.find('\"./textures/\"') != -1:
- cdTex = 1
- cdTexR = count
+ try:
+ qcL = self.qcf[count]
+ if qcL.startswith("$cdtex"):
+ cdTexLoc = count
+ # Getting the string inside the $cdtex command, y'know, the thing inside the quotes? Yeah, that thing.
+ start = 0
+ end = 0
+ if qcL.find('\"') != -1:
+ start = qcL.find('\"')
+ else:
+ start = qcL.find("\'")
+
+ if qcL.find('\"', start+1) != -1:
+ end = qcL.find('\"', start+1)
+ else:
+ end = qcL.find("\'", start+1)
+ cdTex = qcL[start+1:end]
+ print(f"cdtex directory: {cdTex}")
checks += 1
- elif qcL.find('\".\"') != -1:
- cdTex = 2
- cdTexR = count
+ elif qcL.startswith("$cd"):
+ cdLoc = count
+ # Getting the string inside the $cdtex command, y'know, the thing inside the quotes? Yeah, that thing.
+ start = 0
+ end = 0
+ if qcL.find('\"') != -1:
+ start = qcL.find('\"')
+ else:
+ start = qcL.find("\'")
+
+ if qcL.find('\"', start+1) != -1:
+ end = qcL.find('\"', start+1)
+ else:
+ end = qcL.find("\'", start+1)
+ cd = qcL[start+1:end]
+ print(f"cdtex directory: {cdTex}")
checks += 1
- elif qcL.startswith("$cd") and qcL.find('\".\"') != -1:
- cd = True
- cdRef = count
- checks += 1
- if cd or cdTex != 0:
+ except:
+ print("Something went wrong during cd checks! The model may not compile properly!")
+ break
+ if cd or cdTex != "":
self.cbarFrmt = True
print(cd)
print(cdTex)
- if cd:
- newCD = self.qcf[cdRef]
- newCD = newCD.replace('\".\"', f'\"{self.qcLoc}\"')
- self.newQC[cdRef] = newCD
+ if cd != "":
+ newCD = self.qcf[cdLoc]
+ if cd == "." or cd == "./":
+ newCD = newCD.replace(cd, f'{self.qcLoc}')
+ elif cd.startswith("./"):
+ newCD = newCD.replace(cd, f'{self.qcLoc}/{cd[2:]}')
+ else:
+ newCD = newCD.replace(cd, f'{self.qcLoc}/{cd}')
+ self.newQC[cdLoc] = newCD
print(newCD)
- if cdTex == 1:
- newCDtex = self.qcf[cdTexR]
- newCDtex = newCDtex.replace('\"./textures/\"', f'\"{self.qcLoc}/textures/\"')
- self.newQC[cdTexR] = newCDtex
+ if cdTex != "":
+ newCDtex = self.qcf[cdTexLoc]
+ if cdTex == "." or cdTex == "./":
+ newCDtex = newCDtex.replace(cdTex, f'{self.qcLoc}')
+ elif cdTex.startswith("./"):
+ newCDtex = newCDtex.replace(cdTex, f'{self.qcLoc}/{cdTex[2:]}')
+ else:
+ newCDtex = newCDtex.replace(cdTex, f'{self.qcLoc}/{cdTex}')
+ self.newQC[cdTexLoc] = newCDtex
elif cdTex == 2:
- newCDtex = self.qcf[cdTexR]
+ newCDtex = self.qcf[cdTexLoc]
newCDtex = newCDtex.replace('\".\"', f'\"{self.qcLoc}\"')
- self.newQC[cdTexR] = newCDtex
+ self.newQC[cdTexLoc] = newCDtex
self.newQCPath = os.path.join(self.qcLoc, "temp.qc")
f = open(self.newQCPath, "w")
f.write("".join(self.newQC))
@@ -221,6 +256,7 @@ def getMDLname(self):
def check1024px(self):
checks = 0
count = -1
+ cdTex = ""
newCDtex = ""
self.newQC = self.qcf
self.newQCPath = ""
@@ -229,53 +265,48 @@ def check1024px(self):
count += 1
qcL = self.qcf[count]
if qcL.startswith("$cdtex"):
- if qcL.find('\"./textures/\"') != -1:
- cdTex = 1
- checks += 1
- elif qcL.find('\".\"') != -1:
- cdTex = 2
- checks += 1
- if cdTex != 0:
- if cdTex == 1:
- count = -1
- texPath = os.path.join(self.qcLoc, "textures/")
- textures = os.listdir(texPath)
- while count < len(textures)-1:
- count += 1
- tex = textures[count]
- fTex = os.path.join(self.qcLoc,tex)
- if os.path.isfile(fTex):
- try:
- width, height = get_image_size.get_image_size(os.path.join(self.qcLoc,tex))
- except get_image_size.UnknownImageFormat:
- width, height = -1, -1
- if width > 512 or height > 512:
- self.found1024 = True
- elif cdTex == 2:
- count = -1
- files = os.listdir(self.qcLoc)
- textures = []
- while count < len(files)-1:
- count += 1
- if files[count].endswith('.bmp'):
- textures.append(files[count])
- count = -1
- while count < len(textures)-1:
- count += 1
- tex = textures[count]
- fTex = os.path.join(self.qcLoc,tex)
- if os.path.isfile(fTex):
- try:
- width, height = get_image_size.get_image_size(os.path.join(self.qcLoc,tex))
- except get_image_size.UnknownImageFormat:
- width, height = -1, -1
- if width > 512 or height > 512:
- self.found1024 = True
+ # Getting the string inside the $cdtex command, y'know, the thing inside the quotes? Yeah, that thing.
+ start = 0
+ end = 0
+ if qcL.find('\"') != -1:
+ start = qcL.find('\"')
+ else:
+ start = qcL.find("\'")
+
+ if qcL.find('\"', start+1) != -1:
+ end = qcL.find('\"', start+1)
+ else:
+ end = qcL.find("\'", start+1)
+ cdTex = qcL[start+1:end]
+ print(f"cdtex directory: {cdTex}")
+ checks += 1
+ if cdTex != "":
+ # if cdTex == 1:
+ count = -1
+ if cdTex == "." or cdTex == "./":
+ texPath = self.qcLoc
+ elif cdTex.startswith("./"):
+ texPath = os.path.join(self.qcLoc, cdTex[2:])
+ else:
+ texPath = os.path.join(self.qcLoc, cdTex)
+ textures = os.listdir(texPath)
+ while count < len(textures)-1:
+ count += 1
+ tex = textures[count]
+ fTex = os.path.join(self.qcLoc,tex)
+ if os.path.isfile(fTex) and tex.endswith(".bmp"):
+ try:
+ width, height = get_image_size.get_image_size(fTex)
+ except get_image_size.UnknownImageFormat:
+ width, height = -1, -1
+ if width > 512 or height > 512:
+ self.found1024 = True
return self.found1024
def checkCHROME(self):
checks = 0
count = -1
+ cdTex = ""
newCDtex = ""
texmodes = []
self.newQC = self.qcf
@@ -285,52 +316,44 @@ def checkCHROME(self):
count += 1
qcL = self.qcf[count]
if qcL.startswith("$cdtex"):
- if qcL.find('\"./textures/\"') != -1:
- cdTex = 1
- checks += 1
- elif qcL.find('\".\"') != -1:
- cdTex = 2
- checks += 1
- if cdTex != 0:
- if cdTex == 1:
- count = -1
- texPath = os.path.join(self.qcLoc, "textures/")
- textures = os.listdir(texPath)
- while count < len(textures)-1:
- count += 1
- tex = textures[count]
- fTex = os.path.join(self.qcLoc,tex)
- texL = tex.lower()
- print(tex)
- if texL.find("chrome") != -1 and os.path.isfile(fTex):
- try:
- width, height = get_image_size.get_image_size(os.path.join(texPath,tex))
- except get_image_size.UnknownImageFormat:
- width, height = -1, -1
- if not width == 64 or not height == 64:
- self.fndUnlChr = True
- elif cdTex == 2:
- count = -1
- files = os.listdir(self.qcLoc)
- textures = []
- while count < len(files)-1:
- count += 1
- if files[count].endswith('.bmp'):
- textures.append(files[count])
- count = -1
- while count < len(textures)-1:
- count += 1
- tex = textures[count]
- fTex = os.path.join(self.qcLoc,tex)
- texL = tex.lower()
- print(tex)
- if texL.find("chrome") != -1 and os.path.isfile(fTex):
- try:
- width, height = get_image_size.get_image_size(fTex)
- except get_image_size.UnknownImageFormat:
- width, height = -1, -1
- if not width == 64 or not height == 64:
- self.fndUnlChr = True
+ # Getting the string inside the $cdtex command, y'know, the thing inside the quotes? Yeah, that thing.
+ start = 0
+ end = 0
+ if qcL.find('\"') != -1:
+ start = qcL.find('\"')
+ else:
+ start = qcL.find("\'")
+
+ if qcL.find('\"', start+1) != -1:
+ end = qcL.find('\"', start+1)
+ else:
+ end = qcL.find("\'", start+1)
+ cdTex = qcL[start+1:end]
+ print(f"cdtex directory: {cdTex}")
+ checks += 1
+ if cdTex != "":
+ # if cdTex == 1:
+ count = -1
+ if cdTex == "." or cdTex == "./":
+ texPath = self.qcLoc
+ elif cdTex.startswith("./"):
+ texPath = os.path.join(self.qcLoc, cdTex[2:])
+ else:
+ texPath = os.path.join(self.qcLoc, cdTex)
+ textures = os.listdir(texPath)
+ while count < len(textures)-1:
+ count += 1
+ tex = textures[count]
+ fTex = os.path.join(self.qcLoc,tex)
+ texL = tex.lower()
+ print(tex)
+ if texL.find("chrome") != -1 and os.path.isfile(fTex) and tex.endswith('.bmp'):
+ try:
+ width, height = get_image_size.get_image_size(fTex)
+ except get_image_size.UnknownImageFormat:
+ width, height = -1, -1
+ if not width == 64 or not height == 64:
+ self.fndUnlChr = True
return self.fndUnlChr
def checkTRM(self, renderM:int):
count = -1
diff --git a/menus.py b/menus.py
index 9120ab9..624b69d 100644
--- a/menus.py
+++ b/menus.py
@@ -248,13 +248,17 @@ def __init__(self, template, master, updFunc, startHidden:bool=False):
cList = open("save/compilers.txt", "r")
cOptions = cList.read().split('\n')
cOptions.pop(len(cOptions)-1)
+ cList.close()
self.selComp = "GoldSRC"
- self.gameSel = ttk.Combobox(master, values=cOptions)
+ self.comps = GamesHandler(cOptions)
+ self.gameSel = ttk.Combobox(master, values=self.comps.gNames)
self.gameSel.current(0)
self.gameSel.bind("<>", self.chComp)
self.setupLabel = Label(master, text="Compiler Setup", background=thme["bg"], foreground=thme["txt"])
self.nameLabel = Label(self.top, text="Name: ", background=thme["bg"], foreground=thme["txt"])
- self.pathLabel = Label(self.top, text="Custom path: ", background=thme["bg"], foreground=thme["txt"])
+ self.pathLabel = Label(self.top, text="Path: ", background=thme["bg"], foreground=thme["txt"])
+ self.typeLabel = Label(self.top, text="Engine Type: ")
+ self.cPathLabel = Label(self.top, text="Custom path: ", background=thme["bg"], foreground=thme["txt"])
self.name = StringVar()
self.name.set(cOptions[0])
self.nameEntry = Entry(self.top, textvariable=self.name, width=50)
@@ -265,6 +269,9 @@ def __init__(self, template, master, updFunc, startHidden:bool=False):
self.csPathButton = Button(self.top, text="Save Path", command=self.savePath)
if not startHidden:
self.show()
+
+ self.addGame = Button(self.top, text="Add New Game", command=self.addNComp)
+ self.saveGame = Button(self.top, text="Save Game", command=self.saveComp)
# Applying theme
self.applyTheme(master)
@@ -303,6 +310,45 @@ def applyTheme(self, master):
except:
pass
+ def addNComp(self):
+ pass
+ """self.gameSel.set("")
+ self.name.set("")
+ self.typeSel.current(0)
+ self.hrBool.set(False)
+ self.ucBool.set(False)
+ self.fbBool.set(False)
+ self.newGame = True"""
+
+ def saveComp(self):
+ pass
+ """if self.newGame:
+ # Newgrounds Reference!?!?!
+ self.nG = self.name.get()
+ if not self.nG.lower() == "goldsrc" or not self.nG.lower() == "svengine":
+ oList = open("save/games.txt", "w")
+ self.gOptions.append(f"{self.nG}~")
+ nList = '\n'.join(self.gOptions)
+ nList = nList + '\n'
+ oList.write(nList)
+ oList.close()
+ uJS = {
+ self.nG: {
+ "type": self.typeSel.get(),
+ "capabilities": {
+ "fullbright": self.fbBool.get(),
+ "1024px": self.hrBool.get(),
+ "unlockedChrome": self.ucBool.get()
+ }
+ }
+ }
+ js = open(f"save/user/comp{self.nG}.json", "w")
+ js.write(json.dumps(uJS, sort_keys=True, indent=5))
+ js.close()
+ self.games = GamesHandler(self.gOptions)
+ self.gameSel["values"] = self.games.gNames
+ self.updFunc(self.games)"""
+
def inputHandler(self, e=False):
self.csPath.set(self.csPathEntry.get())
self.csPaths[self.gameSel.get()] = self.csPath.get()
@@ -341,7 +387,7 @@ def chComp(self, e):
self.hiddenEdit = False
self.nameLabel.grid(column=1, row=4, sticky=(W))
self.nameEntry.grid(column=2, row=4, sticky=(W))
- self.pathLabel.grid(column=1, row=5, sticky="w")
+ self.cPathLabel.grid(column=1, row=5, sticky="w")
self.csPathEntry.grid(column=2, row=5, sticky="w")
self.csPathButton.grid(column=3,row=5,sticky="w", padx=(5,0))
# If editing options were available and the compiler has editing disabled
@@ -349,7 +395,7 @@ def chComp(self, e):
self.hiddenEdit = True
self.nameLabel.grid_remove()
self.nameEntry.grid_remove()
- self.pathLabel.grid(column=1, row=4, sticky="w")
+ self.cPathLabel.grid(column=1, row=4, sticky="w")
self.csPathEntry.grid(column=2, row=4, sticky="w")
self.csPathButton.grid(column=3,row=4,sticky="w", padx=(5,0))
@@ -366,13 +412,13 @@ def show(self):
self.top.grid(column=1, row=4, sticky="nsew")
self.nameLabel.grid(column=1, row=0, sticky=(W))
self.nameEntry.grid(column=2, row=0, sticky=(W))
- self.pathLabel.grid(column=1, row=1, sticky="w")
+ self.cPathLabel.grid(column=1, row=1, sticky="w")
self.csPathEntry.grid(column=2, row=1, sticky="w", padx=(15,0))
self.csPathButton.grid(column=3,row=1,sticky="w", padx=(5,0))
else:
self.hiddenEdit = True
self.top.grid(column=1, row=4, sticky="nsew")
- self.pathLabel.grid(column=1, row=0, sticky="w")
+ self.cPathLabel.grid(column=1, row=0, sticky="w")
self.csPathEntry.grid(column=2, row=0, sticky="w", padx=(15,0))
self.csPathButton.grid(column=3,row=0,sticky="w", padx=(5,0))
@@ -452,7 +498,7 @@ def __init__(self, template, master, startHidden:bool=False):
self.logVal = BooleanVar(self.advOpt, value=False)
self.logChk = Checkbutton(self.advOpt, text="Write log to file", variable=self.logVal, command=self.setLog)
self.mVal = BooleanVar(self.advOpt, value=self.presetDat["-m"])
- self.mChk = Checkbutton(self.advOpt, text="GoldSRC compatability", variable=self.mVal)
+ self.mChk = Checkbutton(self.advOpt, text="GoldSRC compatibility", variable=self.mVal)
self.uVal = BooleanVar(self.advOpt, value=self.presetDat["-u"])
self.uChk = Checkbutton(self.advOpt, text="Fix UV shifts", variable=self.uVal)
self.vVal = BooleanVar(self.advOpt, value=self.presetDat["-V"])
@@ -633,6 +679,7 @@ def startDecomp(self):
output = self.out.get()
gotArgs = False
cmdArgs = self.getArgs()
+ error = False
if not cmdArgs == "" or not cmdArgs == " ":
gotArgs = True
if output == "" or output == None:
@@ -654,6 +701,25 @@ def startDecomp(self):
# So instead I have to use wine for Mac systems
"""elif sys.platform == 'darwin':
tOutput = subprocess.getoutput(f'wine third_party/mdldec_win32.exe \"{mdl}\"')"""
+ # Checking for errors (especially the 'unknown Studio MDL format')
+ if tOutput.find("unknown Studio MDL format version 6") != -1:
+ # Telling the file moving part of the function that we are decompiling a v6 MDL file.
+ error = True
+ if sys.platform == 'linux':
+ shutil.copy(mdl, './')
+ tOutput = subprocess.getoutput(f'wine \"{os.getcwd()}/third_party/mdl6dec.exe\" \"{os.path.basename(mdl)}\" -p \"MDL6job\"')
+ os.remove(f"{os.path.basename(mdl)}")
+ # Moving the decompiler output to the output folder!
+ if not os.path.exists(output):
+ os.mkdir(output)
+ for f in os.listdir('MDL6job'):
+ print(f)
+ shutil.copy(f"MDL6job/{f}", os.path.join(output, f))
+ shutil.rmtree('MDL6job')
+ else:
+ tOutput = subprocess.getoutput(f'\"{os.getcwd()}/third_party/mdl6dec.exe\" \"{mdl}\" -p \"{output}\"')
+ elif tOutput.find("ERROR:") != -1:
+ error = True
print(tOutput)
self.console.setOutput(tOutput)
if self.logVal.get():
@@ -663,29 +729,31 @@ def startDecomp(self):
log.write(tOutput)
log.close()
# Moving files to output directory (this is a workaround to a bug with Xash3D's model decompiler)
- filesToMove = []
- mdlFolder = os.path.dirname(mdl)
- anims = os.path.join(mdlFolder, 'anims/')
- texFolder = os.path.join(mdlFolder, 'textures/')
- for f in os.listdir(mdlFolder):
- print(f)
- if f.endswith("smd") or f.endswith("qc"):
- shutil.copy(f"{mdlFolder}/{f}", os.path.join(output, f))
- os.remove(f"{mdlFolder}/{f}")
- elif f.endswith("bmp") and not self.tVal.get():
- shutil.copy(f"{mdlFolder}/{f}", os.path.join(output, f))
- os.remove(f"{mdlFolder}/{f}")
- shutil.copytree(anims, os.path.join(output, 'anims/'))
- if self.tVal.get():
- shutil.copytree(texFolder, os.path.join(output, 'textures/'))
+ if not error:
+ if not os.path.exists(output):
+ os.mkdir(output)
+ mdlFolder = os.path.dirname(mdl)
+ anims = os.path.join(mdlFolder, 'anims/')
+ texFolder = os.path.join(mdlFolder, 'textures/')
+ for f in os.listdir(mdlFolder):
+ print(f)
+ if f.endswith("smd") or f.endswith("qc"):
+ shutil.copy(f"{mdlFolder}/{f}", os.path.join(output, f))
+ os.remove(f"{mdlFolder}/{f}")
+ elif f.endswith("bmp") and not self.tVal.get():
+ shutil.copy(f"{mdlFolder}/{f}", os.path.join(output, f))
+ os.remove(f"{mdlFolder}/{f}")
+ shutil.copytree(anims, os.path.join(output, 'anims/'))
+ if self.tVal.get():
+ shutil.copytree(texFolder, os.path.join(output, 'textures/'))
+ try:
+ shutil.rmtree(texFolder)
+ except:
+ pass
try:
- shutil.rmtree(texFolder)
+ shutil.rmtree(anims)
except:
pass
- try:
- shutil.rmtree(anims)
- except:
- pass
class CompMenu():
def __init__(self, template, master, startHidden:bool=False):
@@ -1124,7 +1192,7 @@ def compatChk(self, e=False):
if not gameDat["capabilities"]["1024px"] and handler.check1024px():
warnings.append("WARNING: The selected game does not support textures higher than 512x512, please downscale the offending textures!")
else:
- if handler.check1024px() and gameDat["capabilities"]["unlockedChrome"]:
+ if handler.check1024px() and gameDat["capabilities"]["1024px"]:
warnings.append("WARNING: The selected compiler does not support textures higher than 512x512, please downscale the offending textures!")
elif handler.check1024px():
warnings.append("WARNING: The selected compiler and game does not support textures higher than 512x512, please downscale the offending textures!")
@@ -1264,7 +1332,7 @@ def startCompile(self):
cOpts = self.getCompilerOptions()
# Checking if the QC file supplied uses relative pathing for $cd and $cdtexture as the compiler cannot find the files otherwise
qcRelChk = QCHandler(mdl)
- qcRelChk.crowbarFormatCheck()
+ qcRelChk.relPathCheck()
if qcRelChk.cbarFrmt:
mdl = qcRelChk.newQCPath
@@ -1354,7 +1422,7 @@ def __init__(self, template, master, startHidden:bool=False):
self.ver = vnum.read().replace("(OS)", sys.platform)
self.setupLabel = Label(master, text=f"Snark {self.ver} by:", background=thme["bg"], foreground=thme["txt"])
credits = ["PostScript", "\nusing:", "MDLDec by Flying With Gauss", "get_image_size by Paulo Scardine", "TkTooltip by DaedalicEntertainment",
- "JSONC by John Carter"
+ "JSONC by John Carter", "MDL6Dec by GeckoN"
]
self.nameLabel = Label(master, text="\n".join(credits), background=thme["bg"], fg=thme["txt"])
# Tooltips
diff --git a/third_party/mdl6dec.exe b/third_party/mdl6dec.exe
new file mode 100644
index 0000000..1041520
Binary files /dev/null and b/third_party/mdl6dec.exe differ
diff --git a/version.txt b/version.txt
index 824a641..f35b749 100644
--- a/version.txt
+++ b/version.txt
@@ -1 +1 @@
-v0.2.3-(OS)-alpha
+v0.2.4-(OS)-alpha