Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions de.peeeq.wurstscript/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ dependencies {
implementation 'org.xerial:sqlite-jdbc:3.46.1.3'
implementation 'com.github.inwc3:jmpq3:e28f6999c0'
implementation 'com.github.inwc3:wc3libs:a69318d921'
implementation 'com.github.wurstscript:wurst-project-config:2c7ccd1a5f'
implementation('com.github.wurstscript:wurstsetup:393cf5ea39') {
exclude group: 'org.eclipse.jgit', module: 'org.eclipse.jgit'
exclude group: 'org.eclipse.jgit', module: 'org.eclipse.jgit.ssh.apache'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,12 @@
import config.WurstProjectConfigData;
import de.peeeq.wurstscript.WLogger;
import net.moonlightflower.wc3libs.port.GameVersion;
import org.wurstscript.projectconfig.Wc3PatchTarget;

import java.io.IOException;
import java.lang.reflect.Method;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.Optional;

import static de.peeeq.wurstio.languageserver.ProjectConfigBuilder.FILE_NAME;
Expand All @@ -24,181 +22,133 @@ public enum ScriptMode {

public enum Wc3Patch {
REFORGED,
CLASSIC,
PRE_129
}

private final Optional<ScriptMode> scriptMode;
private final Optional<Wc3Patch> wc3Patch;
private final org.wurstscript.projectconfig.WurstBuildConfig sharedConfig;

private WurstBuildConfig(Optional<ScriptMode> scriptMode, Optional<Wc3Patch> wc3Patch) {
this.scriptMode = scriptMode;
this.wc3Patch = wc3Patch;
private WurstBuildConfig(org.wurstscript.projectconfig.WurstBuildConfig sharedConfig) {
this.sharedConfig = sharedConfig == null ? org.wurstscript.projectconfig.WurstBuildConfig.empty() : sharedConfig;
}

public static WurstBuildConfig empty() {
return new WurstBuildConfig(Optional.empty(), Optional.empty());
return new WurstBuildConfig(org.wurstscript.projectconfig.WurstBuildConfig.empty());
}

public static WurstBuildConfig fromWorkspaceRoot(WFile workspaceRoot) {
if (workspaceRoot == null) {
return empty();
}
return fromBuildFile(Path.of(workspaceRoot.toString(), FILE_NAME));
}

public static WurstBuildConfig fromProject(WurstProjectConfigData projectConfig, WFile workspaceRoot) {
WurstBuildConfig fileConfig = fromWorkspaceRoot(workspaceRoot);
Optional<ScriptMode> scriptMode = readEnumGetter(projectConfig, "getScriptMode", ScriptMode::valueOf)
.or(fileConfig::scriptMode);
Optional<Wc3Patch> wc3Patch = readEnumGetter(projectConfig, "getWc3Patch", WurstBuildConfig::parsePatchName)
.or(fileConfig::wc3Patch);
return new WurstBuildConfig(scriptMode, wc3Patch);
if (projectConfig == null) {
return fileConfig;
}
Optional<org.wurstscript.projectconfig.ScriptMode> scriptMode = readStringGetter(projectConfig, "getScriptMode")
.flatMap(WurstBuildConfig::parseSharedScriptMode)
.or(fileConfig.sharedConfig::scriptMode);
Optional<Wc3PatchTarget> wc3Patch = readStringGetter(projectConfig, "getWc3Patch")
.flatMap(Wc3PatchTarget::parse)
.or(fileConfig.sharedConfig::wc3Patch);
return new WurstBuildConfig(new org.wurstscript.projectconfig.WurstBuildConfig(scriptMode, wc3Patch));
}

static WurstBuildConfig fromBuildFile(Path buildFile) {
if (!Files.exists(buildFile)) {
return empty();
}
Optional<ScriptMode> scriptMode = Optional.empty();
Optional<Wc3Patch> wc3Patch = Optional.empty();
try {
for (String rawLine : Files.readAllLines(buildFile)) {
String line = stripComment(rawLine).trim();
if (line.isEmpty() || Character.isWhitespace(rawLine.charAt(0))) {
continue;
}
int colon = line.indexOf(':');
if (colon < 0) {
continue;
}
String key = line.substring(0, colon).trim();
String value = normalizeScalar(line.substring(colon + 1).trim());
if (key.equals("scriptMode")) {
scriptMode = parseScriptMode(value);
} else if (key.equals("wc3Patch")) {
wc3Patch = parsePatch(value);
}
}
return new WurstBuildConfig(org.wurstscript.projectconfig.WurstBuildConfig.fromBuildFile(buildFile));
} catch (IOException e) {
WLogger.warning("Could not read " + buildFile + " for build settings", e);
return empty();
}
return new WurstBuildConfig(scriptMode, wc3Patch);
}

public Optional<ScriptMode> scriptMode() {
return scriptMode;
return sharedConfig.scriptMode().map(mode -> ScriptMode.valueOf(mode.name()));
}

public Optional<Wc3Patch> wc3Patch() {
return wc3Patch;
return sharedConfig.wc3Patch().map(WurstBuildConfig::patchKind);
Comment thread
Frotty marked this conversation as resolved.
}

public Optional<String> wc3PatchName() {
return sharedConfig.wc3Patch().map(Wc3PatchTarget::name);
}

public Optional<GameVersion> configuredGameVersion() {
return sharedConfig.wc3Patch()
.map(Wc3PatchTarget::gameVersion)
.map(GameVersion::new);
}

public Wc3Patch wc3PatchOrReforged() {
return wc3Patch.orElse(Wc3Patch.REFORGED);
return wc3Patch().orElse(Wc3Patch.REFORGED);
}

public GameVersion fallbackGameVersion() {
if (wc3PatchOrReforged() == Wc3Patch.PRE_129) {
return new GameVersion("1.28");
}
return GameVersion.VERSION_1_32;
return configuredGameVersion().orElse(GameVersion.VERSION_1_32);
}

public List<String> applyToCompileArgs(List<String> compileArgs) {
if (!scriptMode.isPresent()) {
return compileArgs;
}
List<String> result = new ArrayList<>();
for (String arg : compileArgs) {
if (!"-lua".equals(arg)) {
result.add(arg);
}
}
if (scriptMode.get() == ScriptMode.LUA) {
result.add("-lua");
}
return result;
return sharedConfig.applyToCompileArgs(compileArgs);
}

public boolean shouldUseReforgedLaunchArgs(Optional<GameVersion> detectedVersion) {
return detectedVersion
.map(version -> version.compareTo(GameVersion.VERSION_1_32) >= 0)
.orElse(wc3PatchOrReforged() == Wc3Patch.REFORGED);
return sharedConfig.shouldUseReforgedLaunchArgs(versionString(detectedVersion));
}

public boolean shouldUseClassicWindowArg(Optional<GameVersion> detectedVersion) {
return detectedVersion
.map(version -> version.compareTo(GameVersion.VERSION_1_31) < 0)
.orElse(wc3PatchOrReforged() == Wc3Patch.PRE_129);
return sharedConfig.shouldUseClassicWindowArg(versionString(detectedVersion));
}

public boolean shouldCopyRunMapToWarcraftMapDir(Optional<GameVersion> detectedVersion) {
return detectedVersion
.map(version -> version.compareTo(GameVersion.VERSION_1_32) < 0)
.orElse(wc3PatchOrReforged() == Wc3Patch.PRE_129);
return sharedConfig.shouldCopyRunMapToWarcraftMapDir(versionString(detectedVersion));
}

public boolean shouldUseInstallDirForMaps(Optional<GameVersion> detectedVersion) {
return detectedVersion.orElseGet(this::fallbackGameVersion)
.compareTo(new GameVersion("1.27.9")) <= 0;
Optional<GameVersion> effectiveVersion = detectedVersion == null ? Optional.empty() : detectedVersion;
return effectiveVersion.or(this::configuredGameVersion)
.map(version -> version.compareTo(new GameVersion("1.27.9")) <= 0)
.orElse(false);
}

private static String stripComment(String line) {
int commentStart = line.indexOf('#');
return commentStart >= 0 ? line.substring(0, commentStart) : line;
}

private static String normalizeScalar(String value) {
String result = value;
if ((result.startsWith("\"") && result.endsWith("\""))
|| (result.startsWith("'") && result.endsWith("'"))) {
result = result.substring(1, result.length() - 1);
}
return result.trim();
private static Optional<String> versionString(Optional<GameVersion> version) {
return version == null ? Optional.empty() : version.map(GameVersion::toString);
}

private static Optional<ScriptMode> parseScriptMode(String value) {
String normalized = value.toUpperCase(Locale.ROOT);
private static Optional<org.wurstscript.projectconfig.ScriptMode> parseSharedScriptMode(String value) {
try {
return Optional.of(ScriptMode.valueOf(normalized));
} catch (IllegalArgumentException e) {
WLogger.warning("Ignoring unknown scriptMode in wurst.build: " + value);
return Optional.of(org.wurstscript.projectconfig.ScriptMode.valueOf(value.trim().toUpperCase()));
} catch (IllegalArgumentException | NullPointerException e) {
return Optional.empty();
}
}

private static Optional<Wc3Patch> parsePatch(String value) {
try {
return Optional.of(parsePatchName(value));
} catch (IllegalArgumentException e) {
WLogger.warning("Ignoring unknown wc3Patch in wurst.build: " + value);
return Optional.empty();
private static Wc3Patch patchKind(Wc3PatchTarget target) {
if (target.kind() == Wc3PatchTarget.Kind.PRE_129) {
return Wc3Patch.PRE_129;
}
}

private static Wc3Patch parsePatchName(String value) {
String normalized = value.toUpperCase(Locale.ROOT)
.replace(".", "_")
.replace("-", "_");
if (normalized.equals("PRE1_29")) {
normalized = "PRE_129";
if (target.kind() == Wc3PatchTarget.Kind.CLASSIC) {
return Wc3Patch.CLASSIC;
}
return Wc3Patch.valueOf(normalized);
}

private interface EnumParser<T> {
T parse(String value);
return Wc3Patch.REFORGED;
}

private static <T> Optional<T> readEnumGetter(WurstProjectConfigData projectConfig, String getterName, EnumParser<T> parser) {
private static Optional<String> readStringGetter(WurstProjectConfigData projectConfig, String getterName) {
try {
Method getter = projectConfig.getClass().getMethod(getterName);
Object value = getter.invoke(projectConfig);
if (value == null) {
return Optional.empty();
}
return Optional.of(parser.parse(value.toString()));
return Optional.of(value.toString());
} catch (NoSuchMethodException ignored) {
return Optional.empty();
} catch (Exception e) {
WLogger.warning("Could not read " + getterName + " from wurst.build config", e);
WLogger.debug("Could not read " + getterName + " from wurst.build config: " + e);
return Optional.empty();
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import de.peeeq.wurstio.languageserver.ModelManager;
import de.peeeq.wurstio.languageserver.ProjectConfigBuilder;
import de.peeeq.wurstio.languageserver.WFile;
import de.peeeq.wurstio.languageserver.WurstBuildConfig;
import de.peeeq.wurstio.languageserver.WurstLanguageServer;
import de.peeeq.wurstio.map.importer.ImportFile;
import de.peeeq.wurstio.mpq.MpqEditor;
Expand Down Expand Up @@ -62,6 +63,7 @@ public abstract class MapRequest extends UserRequest<Object> {
protected final WFile workspaceRoot;
protected final RunArgs runArgs;
protected final Optional<String> wc3Path;
protected final WurstBuildConfig buildConfig;
protected final W3InstallationData w3data;
protected final TimeTaker timeTaker;

Expand Down Expand Up @@ -104,8 +106,9 @@ public MapRequest(WurstLanguageServer langServer, Optional<File> map, List<Strin
this.workspaceRoot = workspaceRoot;
this.runArgs = new RunArgs(compileArgs);
this.wc3Path = wc3Path;
this.buildConfig = WurstBuildConfig.fromWorkspaceRoot(workspaceRoot);
if (gameExePath.isPresent() && StringUtils.isNotBlank(gameExePath.get())) {
this.w3data = new W3InstallationData(Optional.of(new File(gameExePath.get())), Optional.empty());
this.w3data = new W3InstallationData(Optional.of(new File(gameExePath.get())), buildConfig.configuredGameVersion());
} else {
this.w3data = getBestW3InstallationData();
}
Expand Down Expand Up @@ -929,21 +932,30 @@ protected File renameJhcrOutput(File buildDir) throws IOException {
}

private W3InstallationData getBestW3InstallationData() throws RequestFailedException {
Optional<GameVersion> configuredVersion = buildConfig.configuredGameVersion();
boolean needsGameExe = this instanceof RunMap && !runArgs.isHotReload();
if (configuredVersion.isPresent()) {
WLogger.info("Using wurst.build wc3Patch " + buildConfig.wc3PatchName().orElse(configuredVersion.get().toString())
+ " (" + configuredVersion.get() + ").");
}
if (Orient.isLinuxSystem()) {
// no Warcraft installation supported on Linux
return new W3InstallationData(Optional.empty(), Optional.empty());
return new W3InstallationData(Optional.empty(), configuredVersion);
}
if (!needsGameExe && configuredVersion.isPresent()) {
return new W3InstallationData(Optional.empty(), configuredVersion);
}
if (wc3Path.isPresent() && StringUtils.isNotBlank(wc3Path.get())) {
W3InstallationData w3data = new W3InstallationData(langServer, new File(wc3Path.get()),
this instanceof RunMap && !runArgs.isHotReload());
if (w3data.getWc3PatchVersion().isEmpty()) {
needsGameExe, configuredVersion);
if (w3data.getWc3PatchVersion().isEmpty() && !configuredVersion.isPresent()) {
WLogger.warning("Could not determine Warcraft III version at specified path: " + wc3Path
+ ". Falling back to wurst.build patch target.");
+ ". Falling back to default launch behavior.");
}

return w3data;
} else {
return new W3InstallationData(langServer, this instanceof RunMap && !runArgs.isHotReload());
return new W3InstallationData(langServer, needsGameExe, configuredVersion);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
import config.WurstProjectConfig;
import config.WurstProjectConfigData;
import de.peeeq.wurstio.gui.WurstGuiImpl;
import de.peeeq.wurstio.languageserver.WurstBuildConfig;
import de.peeeq.wurstio.languageserver.ModelManager;
import de.peeeq.wurstio.languageserver.WFile;
import de.peeeq.wurstio.languageserver.WurstLanguageServer;
Expand Down Expand Up @@ -41,7 +40,6 @@
public class RunMap extends MapRequest {

private @Nullable File customTarget = null;
private @Nullable WurstBuildConfig buildConfig = null;


public RunMap(WurstLanguageServer langServer, WFile workspaceRoot, Optional<String> wc3Path, Optional<File> map,
Expand All @@ -68,8 +66,6 @@ public Object execute(ModelManager modelManager) throws IOException {
throw new RequestFailedException(MessageType.Error, FILE_NAME + " file doesn't exist or is invalid. " +
"Please install your project using grill or the wurst setup tool.");
}
buildConfig = WurstBuildConfig.fromProject(projectConfig, workspaceRoot);

// TODO use normal compiler for this, avoid code duplication
WurstGui gui = new WurstGuiImpl(getWorkspaceAbsolute());
try {
Expand Down Expand Up @@ -140,7 +136,6 @@ private void startGame(WurstGui gui, CompilationResult result) throws Exception
gui.sendProgress("Starting Warcraft 3...");

File mapCopy = cachedMapFile.get();
WurstBuildConfig buildConfig = getBuildConfig();
Optional<GameVersion> detectedGameVersion = w3data.getWc3PatchVersion();
if (buildConfig.shouldCopyRunMapToWarcraftMapDir(detectedGameVersion)) {
mapCopy = copyToWarcraftMapDir(cachedMapFile.get());
Expand Down Expand Up @@ -325,7 +320,7 @@ private Optional<String> findMapDocumentPath(String testMapName, File myDocument
}
}

if (getBuildConfig().shouldUseInstallDirForMaps(w3data.getWc3PatchVersion())) {
if (buildConfig.shouldUseInstallDirForMaps(w3data.getWc3PatchVersion())) {
Comment thread
Frotty marked this conversation as resolved.
Outdated
// 1.27 and lower compat
WLogger.info("Version 1.27 or lower detected, changing file location");
documentPath = wc3Path;
Expand All @@ -341,12 +336,4 @@ private Optional<String> findMapDocumentPath(String testMapName, File myDocument
}
return documentPath;
}

private WurstBuildConfig getBuildConfig() {
if (buildConfig == null) {
buildConfig = WurstBuildConfig.fromWorkspaceRoot(workspaceRoot);
}
return buildConfig;
}

}
Loading
Loading