Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
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
95 changes: 95 additions & 0 deletions src/LocalLevelLoader.hx
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
package src;

import haxe.io.Bytes;
import haxe.io.Path;
import mis.MisParser;
import src.Mission;
import src.ResourceLoader;
import src.MarbleGame;
import src.Console;

class LocalLevelLoader {
public static var currentLocalPath:String = null;
public static var currentMission:Mission = null;

public static function init() {
#if js
setupWebPostMessage();
notifyReady();
#end
}

public static function notifyReady() {
#if js
if (js.Browser.window.opener != null) {
try {
Console.log("Notifying level editor that MBHaxe is ready...");
js.Browser.window.opener.postMessage({ type: "mbhaxe-ready" }, "*");
} catch (e:Dynamic) {}
}
try {
var channel = new js.html.BroadcastChannel("mbhaxe-level-editor");
channel.postMessage({ type: "mbhaxe-ready" });
} catch (e:Dynamic) {}
#end
}

static function setupWebPostMessage() {
#if js
function handleMessage(data:Dynamic) {
if (data == null || data.type != "loadLevel" || data.files == null) return;
Console.log("Received level load message via postMessage/BroadcastChannel");

var mission:Mission = null;

var filesAccess:haxe.DynamicAccess<Dynamic> = data.files;
for (k in filesAccess.keys()) {
var fileData:Dynamic = filesAccess.get(k);
var bytes:Bytes = null;
if (Std.isOfType(fileData, String)) {
bytes = Bytes.ofString(fileData);
} else {
bytes = Bytes.ofData(fileData);
}
ResourceLoader.registerLocalFile(k, bytes);

if (StringTools.endsWith(k.toLowerCase(), ".mis")) {
mission = createLocalMission(k, bytes.toString());
}
}

if (mission == null) {
Console.error("postMessage loadLevel missing .mis file in files payload");
return;
}

MarbleGame.instance.playMission(mission);
}

js.Browser.window.addEventListener("message", (e:js.html.MessageEvent) -> {
handleMessage(e.data);
});

try {
var channel = new js.html.BroadcastChannel("mbhaxe-level-editor");
channel.onmessage = (e:js.html.MessageEvent) -> {
handleMessage(e.data);
};
} catch (e:Dynamic) {}
#end
}

public static function createLocalMission(misRelPath:String, misText:String):Mission {
var misParser = new MisParser(misText);
var parsed = misParser.parse();
var mInfo = misParser.parseMissionInfo();

var mission = Mission.fromMissionInfo(misRelPath, mInfo);
mission.isCustom = true;
mission.isLocal = true;
mission.game = mInfo.game?.toLowerCase();

currentMission = mission;
return mission;
}
}
2 changes: 2 additions & 0 deletions src/Main.hx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import src.Console;
import hxd.Key;
import src.Util;
import src.ResourceLoader;
import src.LocalLevelLoader;
#if js
import fs.ManifestFileSystem;
import fs.ManifestBuilder;
Expand Down Expand Up @@ -108,6 +109,7 @@ class Main extends hxd.App {

new ProfilerUI(s2d);

LocalLevelLoader.init();
loaded = true;
});
} catch (e) {
Expand Down
7 changes: 7 additions & 0 deletions src/Mission.hx
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ class Mission {
public var game:String;
public var hasEgg:Bool;
public var isCustom:Bool;
public var isLocal:Bool = false;
public var gameMode:String;
#if hl
public var addedAt:Int64;
Expand Down Expand Up @@ -237,6 +238,10 @@ class Mission {
#end
if (!StringTools.endsWith(path, ".dif"))
path += ".dif";
if (ResourceLoader.existsInZip(path))
return path;
if (ResourceLoader.existsInZip(fname))
return fname;
if (ResourceLoader.exists(path))
return path;
if (StringTools.contains(path, 'interiors_mbg/'))
Expand All @@ -254,6 +259,8 @@ class Mission {
path = StringTools.replace(path, "lbinteriors", "interiors"); // This shit ew
if (ResourceLoader.exists(path))
return path;
if (ResourceLoader.exists(fname))
return fname;
Console.error("Interior resource not found: " + rawElementPath);
return "";
}
Expand Down
22 changes: 22 additions & 0 deletions src/ResourceLoader.hx
Original file line number Diff line number Diff line change
Expand Up @@ -283,10 +283,16 @@ class ResourceLoader {
#if (js || android)
path = StringTools.replace(path, "data/", "");
#end
if (ResourceLoader.existsInZip(path))
return path;
if (ResourceLoader.existsInZip(fname))
return fname;
if (ResourceLoader.exists(path))
return path;
if (ResourceLoader.exists(dirpath + fname))
return dirpath + fname;
if (ResourceLoader.exists(fname))
return fname;
return "";
}

Expand Down Expand Up @@ -553,6 +559,13 @@ class ResourceLoader {
return fileSystem.exists(path);
}

public static function existsInZip(path:String):Bool {
#if (js || android)
path = StringTools.replace(path, "data/", "");
#end
return zipFilesystem.exists(path.toLowerCase());
}

public static function clearInteriorResources() {
interiorResources = new Map();
}
Expand Down Expand Up @@ -610,4 +623,13 @@ class ResourceLoader {
zipFilesystem.set(fname, zfe);
}
}

public static function registerLocalFile(path:String, bytes:haxe.io.Bytes) {
path = StringTools.replace(path, "\\", "/").toLowerCase();
#if (js || android)
path = StringTools.replace(path, "data/", "");
#end
var zfe = new BytesFileEntry(path, bytes);
zipFilesystem.set(path, zfe);
}
}
4 changes: 2 additions & 2 deletions src/gui/EndGameGui.hx
Original file line number Diff line number Diff line change
Expand Up @@ -396,7 +396,7 @@ class EndGameGui extends GuiControl {
var rewindUsed = MarbleGame.instance.world.rewindUsed;
var cheatsUsed = MarbleGame.instance.world.cheatsUsed;

if (idx <= 4) {
if (idx <= 4 && !mission.isLocal) {
setButtonStates(false);
var end = new EnterNameDlg(idx, (name) -> {
setButtonStates(true);
Expand Down Expand Up @@ -440,7 +440,7 @@ class EndGameGui extends GuiControl {
scoreSubmitted = true;
});
this.addChild(end);
} else {
} else if (!mission.isLocal) {
// Check if we can submit LB scores
var lbPath = mission.path;
if (mission.isClaMission)
Expand Down