• 🏆 Texturing Contest #33 is OPEN! Contestants must re-texture a SD unit model found in-game (Warcraft 3 Classic), recreating the unit into a peaceful NPC version. 🔗Click here to enter!
  • It's time for the first HD Modeling Contest of 2024. Join the theme discussion for Hive's HD Modeling Contest #6! Click here to post your idea!

How to run map with WC3 executable?

Status
Not open for further replies.
Level 15
Joined
Aug 7, 2013
Messages
1,337
Hi,

For Wurst there is the runmap command that takes a WC3 Map and runs it in windowed WC3.

How can this be done on the command line, or how does wurst do this in VSCode?
 
Level 15
Joined
Aug 7, 2013
Messages
1,337
Ah great, I got this to work in Python. Even better, I was able to run WC3 in a background process, so I could keep running code my main thread, and then kill WC3 whenever. I also made it to automatically copy a map file if its not in the WC3 user map file when they try to run a map.

Python:
"""

"""

import multiprocessing
import os
import shutil
import subprocess
import uuid

import psutil

WC3_X86_EXE_WIN_10 = "C:\\Program Files (x86)\\Warcraft III\\Warcraft III.exe"
WC3_MAP_DIR_WIN_10 = "C:\\Users\\sethmachine\\OneDrive\\Documents\\Warcraft III\\Maps"
OUTDIR = os.path.join(WC3_MAP_DIR_WIN_10, 'wc3-runner')

def _run(args):
    p = subprocess.Popen(args, stdout=subprocess.PIPE, shell=False)
    out, err = p.communicate()
    return out, err

def kill(proc_pid):
    """Taken from SO: https://stackoverflow.com/questions/4789837/how-to-terminate-a-python-subprocess-launched-with-shell-true

    :param proc_pid:
    :return:
    """
    process = psutil.Process(proc_pid)
    for proc in process.children(recursive=True):
        proc.kill()
    process.kill()

class Wc3_Runner():
    def __init__(self, wc3_exe=WC3_X86_EXE_WIN_10, wc3_mapdir=WC3_MAP_DIR_WIN_10):
        assert os.path.exists(wc3_exe)
        assert os.path.exists(wc3_mapdir)
        self.exe = wc3_exe
        self.mapdir = wc3_mapdir
        self.wc3_process = None

    def run(self, window=True):
        """Launches Warcraft III Frozen Throne in windowed mode (default).

        :param window:
        :return:
        """
        if self.wc3_process:
            raise ValueError('WC3 Process is already running.')
        args = [self.exe, '-window']
        if not window:
            args.remove('-window')
        proc = multiprocessing.Process(target=_run, args=(args,))
        proc.daemon = True
        proc.start()
        self.wc3_process = proc
        return self.wc3_process

    def run_map(self, infile, outdir, window=True, replace_existing=True):
        """Map file must be located in WC3 User maps directory.  If not it will be copied over in a temp directory.

        :param infile:
        :param window:
        :param outdir: output directory to create if the map file is not in the map directory
        :return:
        """
        if self.wc3_process:
            raise ValueError('WC3 Process is already running.')
        mapfile = infile
        if self.mapdir not in infile:
            outdir = os.path.join(self.mapdir, outdir)
            if not os.path.exists(outdir):
                os.mkdir(outdir)
            bn = os.path.basename(infile)
            outfile = os.path.join(outdir, bn)
            if os.path.exists(outfile) and not replace_existing:
                raise FileExistsError('Map file exists in output directory.  Choose a different output directory.')
            shutil.copyfile(infile, outfile)
            mapfile = outfile
        args = [self.exe, '-window', '-loadfile', mapfile]
        print(' ' .join(args))
        if not window:
            args.remove('-window')
        proc = multiprocessing.Process(target=_run, args=(args,))
        # proc.daemon = True
        proc.start()
        self.wc3_process = proc
        return self.wc3_process

    def close(self):
        """Terminates the process running Warcraft III.

        :return:
        """
        if not self.wc3_process:
            raise ValueError('Warcraft III process not started.')
        kill(self.wc3_process.pid)
        self.wc3_process = None

    def quit(self):
        self.close()

    def exit(self):
        self.close()

    def __repr__(self):
        return 'Warcraft III executable: {}\nWarcraft III user map directory: {}'.format(self.exe, self.mapdir)


if __name__ == '__main__':
    w = Wc3_Runner()
    p = w.run_map('data/test/GlacialCopy4.w3x', 'foobar', replace_existing=True)
 
Status
Not open for further replies.
Top