• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

wurstscript / WurstScript / 271

29 Sep 2025 12:12PM UTC coverage: 64.649% (+2.4%) from 62.222%
271

Pull #1096

circleci

Frotty
Merge branch 'perf-improvements' of https://github.com/wurstscript/WurstScript into perf-improvements
Pull Request #1096: Perf improvements

18202 of 28155 relevant lines covered (64.65%)

0.65 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
de.peeeq.wurstscript/src/main/java/de/peeeq/wurstio/languageserver/requests/MapRequest.java
1
package de.peeeq.wurstio.languageserver.requests;
2

3
import com.google.common.base.Charsets;
4
import com.google.common.io.Files;
5
import config.WurstProjectConfigData;
6
import de.peeeq.wurstio.Pjass;
7
import de.peeeq.wurstio.TimeTaker;
8
import de.peeeq.wurstio.UtilsIO;
9
import de.peeeq.wurstio.WurstCompilerJassImpl;
10
import de.peeeq.wurstio.languageserver.ModelManager;
11
import de.peeeq.wurstio.languageserver.ProjectConfigBuilder;
12
import de.peeeq.wurstio.languageserver.WFile;
13
import de.peeeq.wurstio.languageserver.WurstLanguageServer;
14
import de.peeeq.wurstio.mpq.MpqEditor;
15
import de.peeeq.wurstio.mpq.MpqEditorFactory;
16
import de.peeeq.wurstio.utils.W3InstallationData;
17
import de.peeeq.wurstscript.RunArgs;
18
import de.peeeq.wurstscript.WLogger;
19
import de.peeeq.wurstscript.ast.CompilationUnit;
20
import de.peeeq.wurstscript.ast.WImport;
21
import de.peeeq.wurstscript.ast.WPackage;
22
import de.peeeq.wurstscript.ast.WurstModel;
23
import de.peeeq.wurstscript.attributes.CompileError;
24
import de.peeeq.wurstscript.gui.WurstGui;
25
import de.peeeq.wurstscript.jassAst.JassProg;
26
import de.peeeq.wurstscript.jassprinter.JassPrinter;
27
import de.peeeq.wurstscript.luaAst.LuaCompilationUnit;
28
import de.peeeq.wurstscript.parser.WPos;
29
import de.peeeq.wurstscript.utils.LineOffsets;
30
import de.peeeq.wurstscript.utils.Utils;
31
import net.moonlightflower.wc3libs.bin.app.W3I;
32
import net.moonlightflower.wc3libs.port.GameVersion;
33
import net.moonlightflower.wc3libs.port.Orient;
34
import org.apache.commons.lang.StringUtils;
35
import org.eclipse.lsp4j.MessageParams;
36
import org.eclipse.lsp4j.MessageType;
37
import org.eclipse.lsp4j.services.LanguageClient;
38
import org.jetbrains.annotations.Nullable;
39

40
import java.io.File;
41
import java.io.FileNotFoundException;
42
import java.io.IOException;
43
import java.nio.channels.NonWritableChannelException;
44
import java.nio.charset.StandardCharsets;
45
import java.nio.file.Path;
46
import java.nio.file.Paths;
47
import java.nio.file.StandardOpenOption;
48
import java.time.Duration;
49
import java.util.*;
50
import java.util.concurrent.CompletableFuture;
51
import java.util.concurrent.atomic.AtomicReference;
52
import java.util.stream.Collectors;
53

54
public abstract class MapRequest extends UserRequest<Object> {
55
    protected final WurstLanguageServer langServer;
56
    protected final Optional<File> map;
57
    protected final List<String> compileArgs;
58
    protected final WFile workspaceRoot;
59
    protected final RunArgs runArgs;
60
    protected final Optional<String> wc3Path;
61
    protected final W3InstallationData w3data;
62
    protected final TimeTaker timeTaker;
63

64
    public static long mapLastModified = 0L;
×
65
    public static String mapPath = "";
×
66

67
    private static Long lastMapModified = 0L;
×
68
    private static String lastMapPath = "";
×
69

70
    /**
71
     * makes the compilation slower, but more safe by discarding results from the editor and working on a copy of the model
72
     */
73
    protected SafetyLevel safeCompilation = SafetyLevel.KindOfSafe;
×
74

75
    public TimeTaker getTimeTaker() {
76
        return timeTaker;
×
77
    }
78

79

80
    enum SafetyLevel {
×
81
        QuickAndDirty, KindOfSafe
×
82
    }
83

84
    public static class CompilationResult {
×
85
        public File script;
86
        public File w3i;
87
    }
88

89
    public MapRequest(WurstLanguageServer langServer, Optional<File> map, List<String> compileArgs, WFile workspaceRoot,
90
                      Optional<String> wc3Path, Optional<String> gameExePath) {
×
91
        this.langServer = langServer;
×
92
        this.map = map;
×
93
        this.compileArgs = compileArgs;
×
94
        this.workspaceRoot = workspaceRoot;
×
95
        this.runArgs = new RunArgs(compileArgs);
×
96
        this.wc3Path = wc3Path;
×
97
        if (gameExePath.isPresent() && StringUtils.isNotBlank(gameExePath.get())) {
×
98
            this.w3data = new W3InstallationData(Optional.of(new File(gameExePath.get())), Optional.of(GameVersion.VERSION_1_29));
×
99
        } else {
100
            this.w3data = getBestW3InstallationData();
×
101
        }
102
        if (runArgs.isMeasureTimes()) {
×
103
            this.timeTaker = new TimeTaker.Recording();
×
104
        } else {
105
            this.timeTaker = new TimeTaker.Default();
×
106
        }
107
    }
×
108

109
    @Override
110
    public void handleException(LanguageClient languageClient, Throwable err, CompletableFuture<Object> resFut) {
111
        if (err instanceof RequestFailedException) {
×
112
            RequestFailedException rfe = (RequestFailedException) err;
×
113
            languageClient.showMessage(new MessageParams(rfe.getMessageType(), rfe.getMessage()));
×
114
            resFut.complete(new Object());
×
115
        } else {
×
116
            super.handleException(languageClient, err, resFut);
×
117
        }
118
    }
×
119

120
    protected File compileMap(File projectFolder, WurstGui gui, Optional<File> mapCopy, RunArgs runArgs, WurstModel model,
121
                              WurstProjectConfigData projectConfigData, boolean isProd) {
122
        try (@Nullable MpqEditor mpqEditor = MpqEditorFactory.getEditor(mapCopy)) {
×
123
            if (mpqEditor != null && !mpqEditor.canWrite()) {
×
124
                WLogger.severe("The supplied map is invalid/corrupted/protected and Wurst cannot write to it.\n" +
×
125
                    "Please supply a valid .w3x input map that can be opened in the world editor.");
126
                throw new NonWritableChannelException();
×
127
            }
128
            WurstCompilerJassImpl compiler = new WurstCompilerJassImpl(timeTaker, projectFolder, gui, mpqEditor, runArgs);
×
129
            compiler.setMapFile(mapCopy);
×
130
            purgeUnimportedFiles(model);
×
131

132
            gui.sendProgress("Check program");
×
133
            compiler.checkProg(model);
×
134

135
            if (gui.getErrorCount() > 0) {
×
136
                throw new RequestFailedException(MessageType.Warning, "Could not compile project: ", gui.getErrorList().get(0));
×
137
            }
138

139
            print("translating program ... ");
×
140
            compiler.translateProgToIm(model);
×
141

142
            if (gui.getErrorCount() > 0) {
×
143
                throw new RequestFailedException(MessageType.Error, "Could not compile project (error in translation): " + gui.getErrorList().get(0));
×
144
            }
145

146
            timeTaker.measure("Runinng Compiletime Functions", () -> compiler.runCompiletime(projectConfigData, isProd, runArgs.isCompiletimeCache()));
×
147

148
            if (runArgs.isLua()) {
×
149
                print("Translating program to Lua ... ");
×
150
                Optional<LuaCompilationUnit> luaCode = Optional.ofNullable(compiler.transformProgToLua());
×
151

152
                if (!luaCode.isPresent()) {
×
153
                    print("Could not compile project\n");
×
154
                    throw new RuntimeException("Could not compile project (error in LUA translation)");
×
155
                }
156

157
                StringBuilder sb = new StringBuilder();
×
158
                luaCode.get().print(sb, 0);
×
159

160
                String compiledMapScript = sb.toString();
×
161
                File buildDir = getBuildDir();
×
162
                File outFile = new File(buildDir, "compiled.lua");
×
163
                Files.write(compiledMapScript.getBytes(Charsets.UTF_8), outFile);
×
164
                return outFile;
×
165

166
            } else {
167
                print("Translating program to jass ... ");
×
168
                compiler.transformProgToJass();
×
169

170
                Optional<JassProg> jassProg = Optional.ofNullable(compiler.getProg());
×
171
                if (!jassProg.isPresent()) {
×
172
                    print("Could not compile project\n");
×
173
                    throw new RuntimeException("Could not compile project (error in JASS translation)");
×
174
                }
175

176
                gui.sendProgress("Printing program");
×
177
                JassPrinter printer = new JassPrinter(!runArgs.isOptimize(), jassProg.get());
×
178
                String compiledMapScript = printer.printProg();
×
179
                File buildDir = getBuildDir();
×
180
                File outFile = new File(buildDir, "compiled.j.txt");
×
181
                Files.write(compiledMapScript.getBytes(Charsets.UTF_8), outFile);
×
182

183
                if (!runArgs.isDisablePjass()) {
×
184
                    gui.sendProgress("Running PJass");
×
185
                    timeTaker.beginPhase("Pjass execution");
×
186
                    Pjass.Result pJassResult = Pjass.runPjass(outFile,
×
187
                        new File(buildDir, "common.j").getAbsolutePath(),
×
188
                        new File(buildDir, "blizzard.j").getAbsolutePath());
×
189
                    WLogger.info(pJassResult.getMessage());
×
190
                    if (!pJassResult.isOk()) {
×
191
                        for (CompileError err : pJassResult.getErrors()) {
×
192
                            gui.sendError(err);
×
193
                        }
×
194
                        throw new RuntimeException("Could not compile project (PJass error)");
×
195
                    }
196
                    timeTaker.endPhase();
×
197
                }
198

199
                if (runArgs.isHotStartmap()) {
×
200
                    gui.sendProgress("Running JHCR");
×
201
                    return runJassHotCodeReload(outFile);
×
202
                }
203
                return outFile;
×
204
            }
205
        } catch (Exception e) {
×
206
            throw new RuntimeException(e);
×
207
        }
208
    }
209

210
    private File runJassHotCodeReload(File mapScript) throws IOException, InterruptedException {
211
        File buildDir = getBuildDir();
×
212
        File commonJ = new File(buildDir, "common.j");
×
213
        File blizzardJ = new File(buildDir, "blizzard.j");
×
214

215
        if (!commonJ.exists()) {
×
216
            throw new IOException("Could not find file " + commonJ.getAbsolutePath());
×
217
        }
218

219
        if (!blizzardJ.exists()) {
×
220
            throw new IOException("Could not find file " + blizzardJ.getAbsolutePath());
×
221
        }
222

223
        ProcessBuilder pb = new ProcessBuilder(langServer.getConfigProvider().getJhcrExe(), "init", commonJ.getName(), blizzardJ.getName(), mapScript.getName());
×
224
        pb.directory(buildDir);
×
225
        Utils.exec(pb, Duration.ofSeconds(30), System.err::println);
×
226
        return new File(buildDir, "jhcr_war3map.j");
×
227
    }
228

229
    /**
230
     * removes everything compilation unit which is neither
231
     * - inside a wurst folder
232
     * - a jass file
233
     * - imported by a file in a wurst folder
234
     */
235
    private void purgeUnimportedFiles(WurstModel model) {
236

237
        Set<CompilationUnit> imported = model.stream()
×
238
            .filter(cu -> isInWurstFolder(cu.getCuInfo().getFile()) || cu.getCuInfo().getFile().endsWith(".j")).collect(Collectors.toSet());
×
239
        addImports(imported, imported);
×
240

241
        model.removeIf(cu -> !imported.contains(cu));
×
242
    }
×
243

244
    private boolean isInWurstFolder(String file) {
245
        Path p = Paths.get(file);
×
246
        Path w;
247
        try {
248
            w = workspaceRoot.getPath();
×
249
        } catch (FileNotFoundException e) {
×
250
            return false;
×
251
        }
×
252
        return p.startsWith(w)
×
253
            && java.nio.file.Files.exists(p)
×
254
            && Utils.isWurstFile(file);
×
255
    }
256

257
    protected File getBuildDir() {
258
        File buildDir;
259
        try {
260
            buildDir = new File(workspaceRoot.getFile(), "_build");
×
261
        } catch (FileNotFoundException e) {
×
262
            throw new RuntimeException("Cannot get build dir", e);
×
263
        }
×
264
        if (!buildDir.exists()) {
×
265
            UtilsIO.mkdirs(buildDir);
×
266
        }
267
        return buildDir;
×
268
    }
269

270
    private void addImports(Set<CompilationUnit> result, Set<CompilationUnit> toAdd) {
271
        Set<CompilationUnit> imported =
×
272
            toAdd.stream()
×
273
                .flatMap((CompilationUnit cu) -> cu.getPackages().stream())
×
274
                .flatMap((WPackage p) -> p.getImports().stream())
×
275
                .map(WImport::attrImportedPackage)
×
276
                .filter(Objects::nonNull)
×
277
                .map(WPackage::attrCompilationUnit)
×
278
                .collect(Collectors.toSet());
×
279
        boolean changed = result.addAll(imported);
×
280
        if (changed) {
×
281
            // recursive call terminates, as there are only finitely many compilation units
282
            addImports(result, imported);
×
283
        }
284
    }
×
285

286
    protected void print(String s) {
287
        WLogger.info(s);
×
288
    }
×
289

290
    protected void println(String s) {
291
        WLogger.info(s);
×
292
    }
×
293

294

295
    protected File compileScript(WurstGui gui, ModelManager modelManager, List<String> compileArgs, Optional<File> mapCopy,
296
                                 WurstProjectConfigData projectConfigData, boolean isProd, File scriptFile) throws Exception {
297
        RunArgs runArgs = new RunArgs(compileArgs);
×
298

299
        gui.sendProgress("Compiling Script");
×
300
        print("Compile Script : ");
×
301
        for (File dep : modelManager.getDependencyWurstFiles()) {
×
302
            WLogger.info("dep: " + dep.getPath());
×
303
        }
×
304
        print("Dependencies done.");
×
305
        if (safeCompilation != RunMap.SafetyLevel.QuickAndDirty) {
×
306
            // it is safer to rebuild the project, instead of taking the current editor state
307
            gui.sendProgress("Cleaning project");
×
308
            modelManager.clean();
×
309
            gui.sendProgress("Building project");
×
310
            modelManager.buildProject();
×
311
        }
312

313
        replaceBaseScriptWithConfig(modelManager, scriptFile);
×
314

315
        if (modelManager.hasErrors()) {
×
316
            for (CompileError compileError : modelManager.getParseErrors()) {
×
317
                gui.sendError(compileError);
×
318
            }
×
319
            throw new RequestFailedException(MessageType.Warning, "Cannot run code with syntax errors.");
×
320
        }
321

322
        WurstModel model = modelManager.getModel();
×
323
        if (safeCompilation != RunMap.SafetyLevel.QuickAndDirty) {
×
324
            // compilation will alter the model (e.g. remove unused imports),
325
            // so it is safer to create a copy
326
            model = ModelManager.copy(model);
×
327
        }
328

329
        return compileMap(modelManager.getProjectPath(), gui, mapCopy, runArgs, model, projectConfigData, isProd);
×
330
    }
331

332
    private static void replaceBaseScriptWithConfig(ModelManager modelManager, File scriptFile) throws IOException {
333
        Optional<CompilationUnit> war3mapJ = modelManager.getModel()
×
334
            .stream()
×
335
            .filter((CompilationUnit cu) -> cu.getCuInfo().getFile().endsWith("war3map.j"))
×
336
            .findFirst();
×
337

338
        if (war3mapJ.isPresent()) {
×
339
            modelManager.syncCompilationUnitContent(WFile.create(war3mapJ.get().getCuInfo().getFile()),
×
340
                java.nio.file.Files.readString(scriptFile.toPath()));
×
341
        }
342
    }
×
343

344

345
    protected CompilationResult compileScript(ModelManager modelManager, WurstGui gui, Optional<File> testMap, WurstProjectConfigData projectConfigData, File buildDir, boolean isProd) throws Exception {
346
        if (testMap.isPresent() && testMap.get().exists()) {
×
347
            boolean deleteOk = testMap.get().delete();
×
348
            if (!deleteOk) {
×
349
                throw new RequestFailedException(MessageType.Error, "Could not delete old mapfile: " + testMap);
×
350
            }
351
        }
352
        if (map.isPresent() && testMap.isPresent()) {
×
353
            Files.copy(map.get(), testMap.get());
×
354
        }
355

356
        CompilationResult result;
357

358
        if (runArgs.isHotReload()) {
×
359
            // For hot reload use cached war3map if it exists
360
            result = new CompilationResult();
×
361
            result.script = new File(buildDir, "war3mapj_with_config.j.txt");
×
362
            if (!result.script.exists()) {
×
363
                result.script = new File(new File(workspaceRoot.getFile(), "wurst"), "war3map.j");
×
364
            }
365
            if (!result.script.exists()) {
×
366
                throw new RequestFailedException(MessageType.Error, "Could not find war3map.j file");
×
367
            }
368
        } else {
369
            timeTaker.beginPhase("load map script");
×
370
            File scriptFile = loadMapScript(testMap, modelManager, gui);
×
371
            timeTaker.endPhase();
×
372
            result = applyProjectConfig(gui, testMap, buildDir, projectConfigData, scriptFile);
×
373
        }
374

375

376
        // first compile the script:
377
        result.script = compileScript(gui, modelManager, compileArgs, testMap, projectConfigData, isProd, result.script);
×
378

379
        Optional<WurstModel> model = Optional.ofNullable(modelManager.getModel());
×
380
        if (!model.isPresent()
×
381
            || model
382
            .get()
×
383
            .stream()
×
384
            .noneMatch((CompilationUnit cu) -> cu.getCuInfo().getFile().endsWith("war3map.j"))) {
×
385
            println("No 'war3map.j' file could be found inside the map nor inside the wurst folder");
×
386
            println("If you compile the map with WurstPack once, this file should be in your wurst-folder. ");
×
387
            println("We will try to start the map now, but it will probably fail. ");
×
388
        }
389
        return result;
×
390
    }
391

392
    private static boolean startsWith(byte[] data, byte[] prefix) {
393
        if (data.length < prefix.length) return false;
×
394
        for (int i = 0; i < prefix.length; i++) {
×
395
            if (data[i] != prefix[i]) return false;
×
396
        }
397
        return true;
×
398
    }
399

400
    private File loadMapScript(Optional<File> mapCopy, ModelManager modelManager, WurstGui gui) throws Exception {
401
        File scriptFile = new File(new File(workspaceRoot.getFile(), "wurst"), "war3map.j");
×
402
        // If runargs are no extract, either use existing or throw error
403
        // Otherwise try loading from map, if map was saved with wurst, try existing script, otherwise error
404
        if (!mapCopy.isPresent() || runArgs.isNoExtractMapScript()) {
×
405
            System.out.println("No extract map script enabled - not extracting.");
×
406
            if (scriptFile.exists()) {
×
407
                System.out.println("war3map.j exists at wurst root.");
×
408
                CompilationUnit compilationUnit = modelManager.getCompilationUnit(WFile.create(scriptFile));
×
409
                if (compilationUnit == null) {
×
410
                    modelManager.syncCompilationUnit(WFile.create(scriptFile));
×
411
                }
412
                return scriptFile;
×
413
            } else {
414
                throw new CompileError(new WPos("", new LineOffsets(), 0, 0),
×
415
                    "RunArg noExtractMapScript is set but no war3map.j is provided inside the wurst folder");
416
            }
417
        }
418
        if (MapRequest.mapLastModified > lastMapModified || !MapRequest.mapPath.equals(lastMapPath)) {
×
419
            lastMapModified = MapRequest.mapLastModified;
×
420
            lastMapPath = MapRequest.mapPath;
×
421
            System.out.println("Map not cached yet, extracting script");
×
422
            byte[] extractedScript = null;
×
423
            try (@Nullable MpqEditor mpqEditor = MpqEditorFactory.getEditor(mapCopy, true)) {
×
424
                if (mpqEditor.hasFile("war3map.j")) {
×
425
                    extractedScript = mpqEditor.extractFile("war3map.j");
×
426
                }
427
            }
428
            if (extractedScript == null) {
×
429
                if (scriptFile.exists()) {
×
430
                    String msg = "No war3map.j in map file, using old extracted file";
×
431
                    WLogger.info(msg);
×
432
                } else {
×
433
                    CompileError err = new CompileError(new WPos(mapCopy.toString(), new LineOffsets(), 0, 0),
×
434
                        "No war3map.j found in map file.");
435
                    gui.showInfoMessage(err.getMessage());
×
436
                    WLogger.severe(err);
×
437
                }
×
438
            } else if (startsWith(extractedScript, JassPrinter.WURST_COMMENT_RAW.getBytes(StandardCharsets.UTF_8))) {
×
439
                WLogger.info("map has already been compiled with wurst");
×
440
                // file generated by wurst, do not use
441
                if (scriptFile.exists()) {
×
442
                    String msg = "Cannot use war3map.j from map file, because it already was compiled with wurst. " + "Using war3map.j from Wurst directory instead.";
×
443
                    WLogger.info(msg);
×
444
                } else {
×
445
                    CompileError err = new CompileError(new WPos(mapCopy.toString(), new LineOffsets(), 0, 0),
×
446
                        "Cannot use war3map.j from map file, because it already was compiled with wurst. " + "Please add war3map.j to the wurst directory.");
447
                    gui.showInfoMessage(err.getMessage());
×
448
                    WLogger.severe(err);
×
449
                }
×
450
            } else {
451
                WLogger.info("new map, use extracted");
×
452
                // write mapfile from map to workspace
453
                Files.write(extractedScript, scriptFile);
×
454
            }
455
        } else {
×
456
            System.out.println("Map not modified, not extracting script");
×
457
        }
458

459

460
        return scriptFile;
×
461
    }
462

463
    private CompilationResult applyProjectConfig(WurstGui gui, Optional<File> testMap, File buildDir, WurstProjectConfigData projectConfig, File scriptFile) {
464
        AtomicReference<CompilationResult> result = new AtomicReference<>();
×
465
        gui.sendProgress("Applying Map Config...");
×
466
        timeTaker.measure("Applying Map Config", () -> {
×
467
            try {
468
                result.set(ProjectConfigBuilder.apply(projectConfig, testMap.get(), scriptFile, buildDir, runArgs, w3data));
×
469
            } catch (IOException e) {
×
470
                throw new RuntimeException(e);
×
471
            }
×
472
        });
×
473
        return result.get();
×
474
    }
475

476
    private W3InstallationData getBestW3InstallationData() throws RequestFailedException {
477
        if (Orient.isLinuxSystem()) {
×
478
            // no Warcraft installation supported on Linux
479
            return new W3InstallationData(Optional.empty(), Optional.empty());
×
480
        }
481
        if (wc3Path.isPresent() && StringUtils.isNotBlank(wc3Path.get())) {
×
482
            W3InstallationData w3data = new W3InstallationData(langServer, new File(wc3Path.get()),
×
483
                this instanceof RunMap && !runArgs.isHotReload());
×
484
            if (w3data.getWc3PatchVersion().isEmpty()) {
×
485
                throw new RequestFailedException(MessageType.Error, "Could not find Warcraft III installation at specified path: " + wc3Path);
×
486
            }
487

488
            return w3data;
×
489
        } else {
490
            return new W3InstallationData(langServer, this instanceof RunMap && !runArgs.isHotReload());
×
491
        }
492
    }
493

494
    protected void injectMapData(WurstGui gui, Optional<File> testMap, CompilationResult result) throws Exception {
495
        gui.sendProgress("Injecting map data");
×
496
        timeTaker.beginPhase("Injecting map data");
×
497
        try (MpqEditor mpqEditor = MpqEditorFactory.getEditor(testMap)) {
×
498
            String mapScriptName;
499
            if (runArgs.isLua()) {
×
500
                mapScriptName = "war3map.lua";
×
501
                injectExternalLuaFiles(result.script);
×
502
            } else {
503
                mapScriptName = "war3map.j";
×
504
            }
505
            // delete both original mapscripts, just to be sure:
506
            mpqEditor.deleteFile("war3map.j");
×
507
            mpqEditor.deleteFile("war3map.lua");
×
508
            if (result.w3i != null) {
×
509
                mpqEditor.deleteFile(W3I.GAME_PATH.getName());
×
510
                mpqEditor.insertFile(W3I.GAME_PATH.getName(), result.w3i);
×
511
            }
512
            mpqEditor.insertFile(mapScriptName, result.script);
×
513
        }
514
        timeTaker.endPhase();
×
515
    }
×
516

517
    private void injectExternalLuaFiles(File script) {
518
        File luaDir;
519
        try {
520
            luaDir = new File(workspaceRoot.getFile(), "lua");
×
521
        } catch (FileNotFoundException e) {
×
522
            throw new RuntimeException("Cannot get build dir", e);
×
523
        }
×
524
        if (luaDir.exists()) {
×
525
            File[] children = luaDir.listFiles();
×
526
            if (children != null) {
×
527
                Arrays.stream(children).forEach(child -> {
×
528
                    try {
529
                        byte[] bytes = java.nio.file.Files.readAllBytes(child.toPath());
×
530
                        if (child.getName().startsWith("pre_")) {
×
531
                            byte[] existingBytes = java.nio.file.Files.readAllBytes(script.toPath());
×
532
                            java.nio.file.Files.write(
×
533
                                script.toPath(),
×
534
                                bytes);
535
                            java.nio.file.Files.write(
×
536
                                script.toPath(),
×
537
                                existingBytes,
538
                                StandardOpenOption.APPEND);
539
                        } else {
×
540
                            java.nio.file.Files.write(
×
541
                                script.toPath(),
×
542
                                bytes,
543
                                StandardOpenOption.APPEND);
544
                        }
545
                    } catch (IOException e) {
×
546
                        throw new RuntimeException(e);
×
547
                    }
×
548
                });
×
549
            }
550
        }
551
    }
×
552

553

554
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc