marbleland support begin, attempt

This commit is contained in:
RandomityGuy 2023-02-10 00:32:18 +05:30
parent aa93731f04
commit 018b4d8705
13 changed files with 353 additions and 68 deletions

View file

@ -647,18 +647,18 @@ class DifBuilder {
path = StringTools.replace(path, "data/", ""); path = StringTools.replace(path, "data/", "");
#end #end
if (ResourceLoader.fileSystem.exists(Path.directory(path) + "/" + tex + ".jpg")) { if (ResourceLoader.exists(Path.directory(path) + "/" + tex + ".jpg")) {
return true; return true;
} }
if (ResourceLoader.fileSystem.exists(Path.directory(path) + "/" + tex + ".png")) { if (ResourceLoader.exists(Path.directory(path) + "/" + tex + ".png")) {
return true; return true;
} }
var prevDir = Path.directory(Path.directory(path)); var prevDir = Path.directory(Path.directory(path));
if (ResourceLoader.fileSystem.exists(prevDir + "/" + tex + ".jpg")) { if (ResourceLoader.exists(prevDir + "/" + tex + ".jpg")) {
return true; return true;
} }
if (ResourceLoader.fileSystem.exists(prevDir + "/" + tex + ".png")) { if (ResourceLoader.exists(prevDir + "/" + tex + ".png")) {
return true; return true;
} }
@ -669,19 +669,19 @@ class DifBuilder {
tex = tex.split('/')[1]; tex = tex.split('/')[1];
} }
if (ResourceLoader.fileSystem.exists(Path.directory(path) + "/" + tex + ".jpg")) { if (ResourceLoader.exists(Path.directory(path) + "/" + tex + ".jpg")) {
return Path.directory(path) + "/" + tex + ".jpg"; return Path.directory(path) + "/" + tex + ".jpg";
} }
if (ResourceLoader.fileSystem.exists(Path.directory(path) + "/" + tex + ".png")) { if (ResourceLoader.exists(Path.directory(path) + "/" + tex + ".png")) {
return Path.directory(path) + "/" + tex + ".png"; return Path.directory(path) + "/" + tex + ".png";
} }
var prevDir = Path.directory(Path.directory(path)); var prevDir = Path.directory(Path.directory(path));
if (ResourceLoader.fileSystem.exists(prevDir + "/" + tex + ".jpg")) { if (ResourceLoader.exists(prevDir + "/" + tex + ".jpg")) {
return prevDir + "/" + tex + ".jpg"; return prevDir + "/" + tex + ".jpg";
} }
if (ResourceLoader.fileSystem.exists(prevDir + "/" + tex + ".png")) { if (ResourceLoader.exists(prevDir + "/" + tex + ".png")) {
return prevDir + "/" + tex + ".png"; return prevDir + "/" + tex + ".png";
} }
@ -729,7 +729,7 @@ class DifBuilder {
var material:Material; var material:Material;
var texture:Texture; var texture:Texture;
if (canFindTex(grp)) { if (canFindTex(grp)) {
texture = ResourceLoader.getFileEntry(tex(grp)).toImage().toTexture(); texture = ResourceLoader.getTexture(tex(grp)).resource;
texture.wrap = Wrap.Repeat; texture.wrap = Wrap.Repeat;
texture.mipMap = Nearest; texture.mipMap = Nearest;
var exactName = StringTools.replace(texture.name, "data/", ""); var exactName = StringTools.replace(texture.name, "data/", "");

View file

@ -471,7 +471,7 @@ class DtsObject extends GameObject {
} }
function parseIfl(path:String) { function parseIfl(path:String) {
var text = ResourceLoader.fileSystem.get(path).getText(); var text = ResourceLoader.getFileEntry(path).entry.getText();
var lines = text.split('\n'); var lines = text.split('\n');
var keyframes = []; var keyframes = [];
for (line in lines) { for (line in lines) {

68
src/Http.hx Normal file
View file

@ -0,0 +1,68 @@
package src;
import src.Console;
import sys.thread.FixedThreadPool;
typedef HttpRequest = {
var url:String;
var callback:haxe.io.Bytes->Void;
var errCallback:String->Void;
};
class Http {
#if sys
static var threadPool:sys.thread.FixedThreadPool;
static var requests:sys.thread.Deque<HttpRequest> = new sys.thread.Deque<HttpRequest>();
static var responses:sys.thread.Deque<() -> Void> = new sys.thread.Deque<() -> Void>();
#end
public static function init() {
#if sys
threadPool = new sys.thread.FixedThreadPool(4);
threadPool.run(() -> threadLoop());
threadPool.run(() -> threadLoop());
threadPool.run(() -> threadLoop());
threadPool.run(() -> threadLoop());
#end
}
#if sys
static function threadLoop() {
while (true) {
var req = requests.pop(true);
var http = new sys.Http(req.url);
http.onError = (e) -> {
responses.add(() -> req.errCallback(e));
};
http.onBytes = (b) -> {
responses.add(() -> req.callback(b));
};
hl.Gc.blocking(true); // Wtf is this shit
http.request(false);
hl.Gc.blocking(false);
}
}
#end
public static function get(url:String, callback:haxe.io.Bytes->Void, errCallback:String->Void):Void {
var req = {
url: url,
callback: callback,
errCallback: errCallback
};
#if sys
requests.add(req);
#else
js.Browser.window.fetch(url).then(r -> r.arrayBuffer().then(b -> callback(haxe.io.Bytes.ofData(b))), e -> errCallback(e.toString()));
#end
}
public static function loop() {
#if sys
var resp = responses.pop(false);
if (resp != null) {
resp();
}
#end
}
}

View file

@ -1,5 +1,6 @@
package; package;
import src.Marbleland;
import src.Console; import src.Console;
import hxd.Key; import hxd.Key;
import src.Util; import src.Util;
@ -18,6 +19,7 @@ import hxd.res.DefaultFont;
import h2d.Text; import h2d.Text;
import h3d.Vector; import h3d.Vector;
import src.ProfilerUI; import src.ProfilerUI;
import src.Http;
class Main extends hxd.App { class Main extends hxd.App {
var marbleGame:MarbleGame; var marbleGame:MarbleGame;
@ -66,10 +68,13 @@ class Main extends hxd.App {
#end #end
try { try {
Http.init();
haxe.MainLoop.add(() -> Http.loop());
Settings.init(); Settings.init();
ResourceLoader.init(s2d, () -> { ResourceLoader.init(s2d, () -> {
AudioManager.init(); AudioManager.init();
AudioManager.playShell(); AudioManager.playShell();
Marbleland.init();
marbleGame = new MarbleGame(s2d, s3d); marbleGame = new MarbleGame(s2d, s3d);
MarbleGame.canvas.setContent(new MainMenuGui()); MarbleGame.canvas.setContent(new MainMenuGui());

View file

@ -181,6 +181,8 @@ class MarbleWorld extends Scheduler {
public var _ready:Bool = false; public var _ready:Bool = false;
var _loadBegin:Bool = false;
var _loadingLength:Int = 0; var _loadingLength:Int = 0;
var _resourcesLoaded:Int = 0; var _resourcesLoaded:Int = 0;
@ -207,7 +209,15 @@ class MarbleWorld extends Scheduler {
Console.log("*** LOADING MISSION: " + mission.path); Console.log("*** LOADING MISSION: " + mission.path);
this.loadingGui = new LoadingGui(this.mission.title, this.mission.game); this.loadingGui = new LoadingGui(this.mission.title, this.mission.game);
MarbleGame.canvas.setContent(this.loadingGui); MarbleGame.canvas.setContent(this.loadingGui);
if (this.mission.isClaMission) {
this.mission.download(() -> loadBegin());
} else {
loadBegin();
}
}
function loadBegin() {
_loadBegin = true;
function scanMission(simGroup:MissionElementSimGroup) { function scanMission(simGroup:MissionElementSimGroup) {
for (element in simGroup.elements) { for (element in simGroup.elements) {
if ([ if ([
@ -249,8 +259,12 @@ class MarbleWorld extends Scheduler {
} }
public function loadMusic(onFinish:Void->Void) { public function loadMusic(onFinish:Void->Void) {
var musicFileName = 'sound/music/' + this.mission.missionInfo.music; if (this.mission.missionInfo.music != null) {
ResourceLoader.load(musicFileName).entry.load(onFinish); var musicFileName = 'sound/music/' + this.mission.missionInfo.music;
ResourceLoader.load(musicFileName).entry.load(onFinish);
} else {
onFinish();
}
} }
public function postInit() { public function postInit() {
@ -1031,7 +1045,7 @@ class MarbleWorld extends Scheduler {
public function addDtsObject(obj:DtsObject, onFinish:Void->Void) { public function addDtsObject(obj:DtsObject, onFinish:Void->Void) {
function parseIfl(path:String, onFinish:Array<String>->Void) { function parseIfl(path:String, onFinish:Array<String>->Void) {
ResourceLoader.load(path).entry.load(() -> { ResourceLoader.load(path).entry.load(() -> {
var text = ResourceLoader.fileSystem.get(path).getText(); var text = ResourceLoader.getFileEntry(path).entry.getText();
var lines = text.split('\n'); var lines = text.split('\n');
var keyframes = []; var keyframes = [];
for (line in lines) { for (line in lines) {
@ -1294,7 +1308,7 @@ class MarbleWorld extends Scheduler {
}); });
#end #end
} else { } else {
if (this._resourcesLoaded < _loadingLength) if (this._resourcesLoaded < _loadingLength || !this._loadBegin)
return; return;
if (!_ready && !postInited) { if (!_ready && !postInited) {
postInited = true; postInited = true;
@ -2002,22 +2016,12 @@ class MarbleWorld extends Scheduler {
this.replay.name = MarbleGame.instance.recordingName; this.replay.name = MarbleGame.instance.recordingName;
#if hl #if hl
sys.FileSystem.createDirectory(haxe.io.Path.join([Settings.settingsDir, "data", "replays"])); sys.FileSystem.createDirectory(haxe.io.Path.join([Settings.settingsDir, "data", "replays"]));
var replayPath = haxe.io.Path.join([ var replayPath = haxe.io.Path.join([Settings.settingsDir, "data", "replays", '${this.replay.name}.mbr']);
Settings.settingsDir,
"data",
"replays",
'${this.replay.name}.mbr'
]);
if (sys.FileSystem.exists(replayPath)) { if (sys.FileSystem.exists(replayPath)) {
var count = 1; var count = 1;
var found = false; var found = false;
while (!found) { while (!found) {
replayPath = haxe.io.Path.join([ replayPath = haxe.io.Path.join([Settings.settingsDir, "data", "replays", '${this.replay.name} (${count}).mbr']);
Settings.settingsDir,
"data",
"replays",
'${this.replay.name} (${count}).mbr'
]);
if (!sys.FileSystem.exists(replayPath)) { if (!sys.FileSystem.exists(replayPath)) {
this.replay.name += ' (${count})'; this.replay.name += ' (${count})';
found = true; found = true;
@ -2066,7 +2070,8 @@ class MarbleWorld extends Scheduler {
} }
} }
this.playGui.dispose(); if (this.playGui != null)
this.playGui.dispose();
scene.removeChildren(); scene.removeChildren();
for (interior in this.interiors) { for (interior in this.interiors) {
@ -2091,7 +2096,8 @@ class MarbleWorld extends Scheduler {
textureResource.release(); textureResource.release();
} }
sky.dispose(); if (sky != null)
sky.dispose();
this._disposed = true; this._disposed = true;
AudioManager.stopAllSounds(); AudioManager.stopAllSounds();

84
src/Marbleland.hx Normal file
View file

@ -0,0 +1,84 @@
package src;
import haxe.io.BytesInput;
import haxe.zip.Reader;
import hxd.res.Image;
import hxd.BitmapData;
import haxe.Json;
import src.Mission;
import src.Http;
import src.ResourceLoader;
class Marbleland {
public static var goldMissions = [];
public static var ultraMissions = [];
public static var platinumMissions = [];
public static function init() {
Http.get('https://raw.githubusercontent.com/Vanilagy/MarbleBlast/master/src/assets/customs_gold.json', (b) -> {
parseMissionList(b.toString(), "gold");
}, (e) -> {});
Http.get('https://raw.githubusercontent.com/Vanilagy/MarbleBlast/master/src/assets/customs_ultra.json', (b) -> {
parseMissionList(b.toString(), "ultra");
}, (e) -> {});
Http.get('https://raw.githubusercontent.com/Vanilagy/MarbleBlast/master/src/assets/customs_platinum.json', (b) -> {
parseMissionList(b.toString(), "platinum");
}, (e) -> {});
}
static function parseMissionList(s:String, game:String) {
var claJson:Array<Dynamic> = Json.parse(s);
for (missionData in claJson) {
var mission = new Mission();
mission.id = missionData.id;
mission.path = 'missions/' + missionData.baseName;
#if (hl && !android)
mission.path = 'data/' + mission.path;
#end
mission.path = mission.path.toLowerCase();
mission.title = missionData.name;
mission.artist = missionData.artist != null ? missionData.artist : "Unknown Author";
mission.description = missionData.desc != null ? missionData.desc : "";
mission.qualifyTime = missionData.qualifyingTime != null ? missionData.qualifyingTime / 1000 : Math.POSITIVE_INFINITY;
mission.goldTime = missionData.goldTime != null ? missionData.goldTime / 1000 : 0;
mission.game = missionData.modification;
if (missionData.modification == 'platinum')
mission.goldTime = missionData.platinumTime != null ? missionData.platinumTime / 1000 : mission.goldTime;
mission.ultimateTime = missionData.ultimateTime != null ? missionData.ultimateTime / 1000 : 0;
mission.hasEgg = missionData.hasEgg;
mission.isClaMission = true;
switch (game) {
case 'gold':
goldMissions.push(mission);
case 'ultra':
ultraMissions.push(mission);
case 'platinum':
platinumMissions.push(mission);
}
}
}
public static function getMissionImage(id:Int, cb:Image->Void) {
Http.get('https://marbleland.vani.ga/api/level/${id}/image?width=258&height=194', (imageBytes) -> {
var res = new Image(new hxd.fs.BytesFileSystem.BytesFileEntry('${id}.png', imageBytes));
cb(res);
}, (e) -> {
cb(null);
});
}
public static function download(id:Int, cb:Array<haxe.zip.Entry>->Void) {
Http.get('https://marbleblast.vani.ga/api/custom/${id}.zip', (zipData -> {
var reader = new Reader(new BytesInput(zipData));
var entries:Array<haxe.zip.Entry> = null;
try {
entries = [for (x in reader.read()) x];
} catch (e) {}
cb(entries);
}), (e) -> {
cb(null);
});
}
}

View file

@ -1,5 +1,7 @@
package src; package src;
import gui.Canvas;
import gui.MessageBoxOkDlg;
import haxe.Json; import haxe.Json;
import mis.MissionElement.MissionElementItem; import mis.MissionElement.MissionElementItem;
import haxe.io.BytesBuffer; import haxe.io.BytesBuffer;
@ -15,6 +17,8 @@ import hxd.res.Image;
import src.Resource; import src.Resource;
import src.Util; import src.Util;
import src.Console; import src.Console;
import src.Marbleland;
import src.MarbleGame;
class Mission { class Mission {
public var root:MissionElementSimGroup; public var root:MissionElementSimGroup;
@ -45,7 +49,7 @@ class Mission {
public function new() {} public function new() {}
public function load() { public function load() {
var misParser = new MisParser(ResourceLoader.fileSystem.get(this.path).getText()); var misParser = new MisParser(ResourceLoader.getFileEntry(this.path).entry.getText());
var contents = misParser.parse(); var contents = misParser.parse();
root = contents.root; root = contents.root;
@ -60,6 +64,8 @@ class Mission {
} else if (element._type == MissionElementType.SimGroup && !this.hasEgg) { } else if (element._type == MissionElementType.SimGroup && !this.hasEgg) {
scanMission(cast element); scanMission(cast element);
} }
if (element._name == 'MissionInfo')
missionInfo = cast element;
} }
}; };
@ -153,10 +159,17 @@ class Mission {
onLoaded(Tile.fromBitmap(img)); onLoaded(Tile.fromBitmap(img));
return null; return null;
} else { } else {
Console.error("Preview image not found for " + this.path); Marbleland.getMissionImage(this.id, (im) -> {
var img = new BitmapData(1, 1); if (im != null) {
img.setPixel(0, 0, 0); onLoaded(im.toTile());
onLoaded(Tile.fromBitmap(img)); } else {
Console.error("Preview image not found for " + this.path);
var img = new BitmapData(1, 1);
img.setPixel(0, 0, 0);
onLoaded(Tile.fromBitmap(img));
}
});
return null; return null;
} }
} }
@ -175,15 +188,20 @@ class Mission {
#if (js || android) #if (js || android)
path = StringTools.replace(path, "data/", ""); path = StringTools.replace(path, "data/", "");
#end #end
if (ResourceLoader.fileSystem.exists(path)) if (ResourceLoader.exists(path))
return path; return path;
if (StringTools.contains(path, 'interiors_mbg/')) if (StringTools.contains(path, 'interiors_mbg/'))
path = StringTools.replace(path, 'interiors_mbg/', 'interiors/'); path = StringTools.replace(path, 'interiors_mbg/', 'interiors/');
var dirpath = path.substring(0, path.lastIndexOf('/') + 1); var dirpath = path.substring(0, path.lastIndexOf('/') + 1);
if (ResourceLoader.fileSystem.exists(path)) if (ResourceLoader.exists(path))
return path; return path;
if (ResourceLoader.fileSystem.exists(dirpath + fname)) if (ResourceLoader.exists(dirpath + fname))
return dirpath + fname; return dirpath + fname;
if (game == 'gold') {
path = StringTools.replace(path, 'interiors/', 'interiors_mbg/');
if (ResourceLoader.exists(path))
return path;
}
Console.error("Interior resource not found: " + rawElementPath); Console.error("Interior resource not found: " + rawElementPath);
return ""; return "";
} }
@ -200,4 +218,17 @@ class Mission {
return alarmStart; return alarmStart;
} }
public function download(onFinish:Void->Void) {
if (this.isClaMission) {
Marbleland.download(this.id, (zipEntries) -> {
if (zipEntries != null) {
ResourceLoader.loadZip(zipEntries);
onFinish();
} else {
MarbleGame.canvas.pushDialog(new MessageBoxOkDlg("Failed to download mission"));
}
});
}
}
} }

View file

@ -110,22 +110,4 @@ class MissionList {
_build = true; _build = true;
} }
static function parseCLAList() {
var claJson:Array<Dynamic> = Json.parse(ResourceLoader.fileSystem.get("data/cla_list.json").getText());
for (missionData in claJson) {
var mission = new Mission();
mission.id = missionData.id;
mission.artist = missionData.artist;
mission.title = missionData.name;
mission.description = missionData.desc;
mission.qualifyTime = missionData.time;
mission.goldTime = missionData.goldTime;
mission.path = missionData.baseName;
mission.isClaMission = true;
customMissions.push(mission);
}
}
} }

View file

@ -1,5 +1,7 @@
package src; package src;
import hxd.res.Any;
import hxd.fs.BytesFileSystem.BytesFileEntry;
#if (js || android) #if (js || android)
import fs.ManifestLoader; import fs.ManifestLoader;
import fs.ManifestBuilder; import fs.ManifestBuilder;
@ -43,6 +45,7 @@ class ResourceLoader {
static var textureCache:Map<String, Resource<Texture>> = new Map(); static var textureCache:Map<String, Resource<Texture>> = new Map();
static var imageCache:Map<String, Resource<Image>> = new Map(); static var imageCache:Map<String, Resource<Image>> = new Map();
static var audioCache:Map<String, Resource<Sound>> = new Map(); static var audioCache:Map<String, Resource<Sound>> = new Map();
static var zipFilesystem:Map<String, BytesFileEntry> = new Map();
// static var threadPool:FixedThreadPool = new FixedThreadPool(4); // static var threadPool:FixedThreadPool = new FixedThreadPool(4);
@ -256,9 +259,9 @@ class ResourceLoader {
#if (js || android) #if (js || android)
path = StringTools.replace(path, "data/", ""); path = StringTools.replace(path, "data/", "");
#end #end
if (ResourceLoader.fileSystem.exists(path)) if (ResourceLoader.exists(path))
return path; return path;
if (ResourceLoader.fileSystem.exists(dirpath + fname)) if (ResourceLoader.exists(dirpath + fname))
return dirpath + fname; return dirpath + fname;
return ""; return "";
} }
@ -271,6 +274,9 @@ class ResourceLoader {
#if (js || android) #if (js || android)
path = StringTools.replace(path, "data/", ""); path = StringTools.replace(path, "data/", "");
#end #end
if (zipFilesystem.exists(path.toLowerCase())) {
return new hxd.res.Any(loader, zipFilesystem.get(path.toLowerCase()));
}
return ResourceLoader.loader.load(path); return ResourceLoader.loader.load(path);
} }
@ -284,7 +290,10 @@ class ResourceLoader {
var itr:Dif; var itr:Dif;
// var lock = new Lock(); // var lock = new Lock();
// threadPool.run(() -> { // threadPool.run(() -> {
itr = Dif.LoadFromBuffer(fileSystem.get(path).getBytes()); if (zipFilesystem.exists(path.toLowerCase()))
itr = Dif.LoadFromBuffer(zipFilesystem.get(path.toLowerCase()).getBytes());
else
itr = Dif.LoadFromBuffer(fileSystem.get(path).getBytes());
var itrresource = new Resource(itr, path, interiorResources, dif -> {}); var itrresource = new Resource(itr, path, interiorResources, dif -> {});
interiorResources.set(path, itrresource); interiorResources.set(path, itrresource);
// lock.release(); // lock.release();
@ -296,6 +305,7 @@ class ResourceLoader {
public static function loadDts(path:String) { public static function loadDts(path:String) {
path = getProperFilepath(path); path = getProperFilepath(path);
if (dtsResources.exists(path)) if (dtsResources.exists(path))
return dtsResources.get(path); return dtsResources.get(path);
else { else {
@ -314,6 +324,18 @@ class ResourceLoader {
public static function getTexture(path:String) { public static function getTexture(path:String) {
path = getProperFilepath(path); path = getProperFilepath(path);
if (zipFilesystem.exists(path.toLowerCase())) {
var img = new hxd.res.Image(zipFilesystem.get(path.toLowerCase()));
Image.setupTextureFlags = (texObj) -> {
texObj.flags.set(MipMapped);
}
var tex = img.toTexture();
tex.mipMap = Nearest;
var textureresource = new Resource(tex, path, textureCache, tex -> tex.dispose());
textureCache.set(path, textureresource);
return textureresource;
}
if (textureCache.exists(path)) if (textureCache.exists(path))
return textureCache.get(path); return textureCache.get(path);
if (fileSystem.exists(path)) { if (fileSystem.exists(path)) {
@ -336,6 +358,12 @@ class ResourceLoader {
#if (js || android) #if (js || android)
path = StringTools.replace(path, "data/", ""); path = StringTools.replace(path, "data/", "");
#end #end
if (zipFilesystem.exists(path.toLowerCase())) {
var fentry = new hxd.res.Image(zipFilesystem.get(path.toLowerCase()));
var imageresource = new Resource(fentry, path, imageCache, img -> {});
imageCache.set(path, imageresource);
return imageresource;
}
if (imageCache.exists(path)) if (imageCache.exists(path))
return imageCache.get(path); return imageCache.get(path);
if (fileSystem.exists(path)) { if (fileSystem.exists(path)) {
@ -379,10 +407,20 @@ class ResourceLoader {
#if (js || android) #if (js || android)
path = StringTools.replace(path, "data/", ""); path = StringTools.replace(path, "data/", "");
#end #end
if (zipFilesystem.exists(path.toLowerCase())) {
var fentry = zipFilesystem.get(path.toLowerCase());
return new hxd.res.Any(loader, fentry);
}
var file = loader.load(path); var file = loader.load(path);
return file; return file;
} }
public static function exists(path:String) {
if (zipFilesystem.exists(path.toLowerCase()))
return true;
return fileSystem.exists(path);
}
public static function clearInteriorResources() { public static function clearInteriorResources() {
interiorResources = new Map(); interiorResources = new Map();
} }
@ -405,4 +443,17 @@ class ResourceLoader {
} }
return names; return names;
} }
public static function loadZip(entries:Array<haxe.zip.Entry>) {
zipFilesystem.clear(); // We are only allowed to load one zip
for (entry in entries) {
var fname = entry.fileName.toLowerCase();
// fname = "data/" + fname;
if (exists(fname))
continue;
Console.log("Loaded zip entry: " + fname);
var zfe = new BytesFileEntry(fname, entry.data);
zipFilesystem.set(fname, zfe);
}
}
} }

View file

@ -72,8 +72,8 @@ class Sky extends Object {
#if (js || android) #if (js || android)
dmlPath = StringTools.replace(dmlPath, "data/", ""); dmlPath = StringTools.replace(dmlPath, "data/", "");
#end #end
if (ResourceLoader.fileSystem.exists(dmlPath)) { if (ResourceLoader.exists(dmlPath)) {
var dmlFileEntry = ResourceLoader.fileSystem.get(dmlPath); var dmlFileEntry = ResourceLoader.getFileEntry(dmlPath).entry;
dmlFileEntry.load(() -> { dmlFileEntry.load(() -> {
var dmlFile = dmlFileEntry.getText(); var dmlFile = dmlFileEntry.getText();
var dmlDirectory = Path.directory(dmlPath); var dmlDirectory = Path.directory(dmlPath);

View file

@ -61,7 +61,7 @@ class DtsFile {
public function new() {} public function new() {}
public function read(filepath:String) { public function read(filepath:String) {
var f = ResourceLoader.fileSystem.get(filepath); var f = ResourceLoader.getFileEntry(filepath).entry;
var bytes = f.getBytes(); var bytes = f.getBytes();
var br = new BytesReader(bytes); var br = new BytesReader(bytes);

View file

@ -1,5 +1,6 @@
package gui; package gui;
import src.Marbleland;
import h2d.filter.DropShadow; import h2d.filter.DropShadow;
import src.Replay; import src.Replay;
import haxe.ds.Option; import haxe.ds.Option;
@ -50,6 +51,9 @@ class PlayMissionGui extends GuiImage {
#if js #if js
var previewTimeoutHandle:Option<Int> = None; var previewTimeoutHandle:Option<Int> = None;
#end #end
#if hl
var previewToken:Int = 0;
#end
public function new() { public function new() {
MissionList.buildMissionList(); MissionList.buildMissionList();
@ -195,7 +199,7 @@ class PlayMissionGui extends GuiImage {
pmSearch.position = new Vector(315, 325); pmSearch.position = new Vector(315, 325);
pmSearch.extent = new Vector(43, 43); pmSearch.extent = new Vector(43, 43);
pmSearch.pressedAction = (e) -> { pmSearch.pressedAction = (e) -> {
MarbleGame.canvas.pushDialog(new SearchGui(currentGame)); MarbleGame.canvas.pushDialog(new SearchGui(currentGame, currentCategory == "custom"));
} }
pmBox.addChild(pmSearch); pmBox.addChild(pmSearch);
@ -420,6 +424,18 @@ class PlayMissionGui extends GuiImage {
pmDifficultyTopCTab2.vertSizing = Bottom; pmDifficultyTopCTab2.vertSizing = Bottom;
pmDifficultyTopC2.addChild(pmDifficultyTopCTab2); pmDifficultyTopC2.addChild(pmDifficultyTopCTab2);
var pmDifficultyUltraCustom = new GuiButtonText(loadButtonImages("data/ui/play/difficulty_highlight-120"), markerFelt24);
pmDifficultyUltraCustom.position = new Vector(277, 164);
pmDifficultyUltraCustom.ratio = -1 / 16;
pmDifficultyUltraCustom.setExtent(new Vector(120, 31));
pmDifficultyUltraCustom.txtCtrl.text.text = " Custom";
pmDifficultyUltraCustom.pressedAction = (e) -> {
currentList = Marbleland.goldMissions;
currentCategory = "custom";
setCategoryFunc("ultra", "custom");
}
pmDifficultyCtrl.addChild(pmDifficultyUltraCustom);
var pmDifficultyUltraAdvanced = new GuiButtonText(loadButtonImages("data/ui/play/difficulty_highlight-120"), markerFelt24); var pmDifficultyUltraAdvanced = new GuiButtonText(loadButtonImages("data/ui/play/difficulty_highlight-120"), markerFelt24);
pmDifficultyUltraAdvanced.position = new Vector(277, 134); pmDifficultyUltraAdvanced.position = new Vector(277, 134);
pmDifficultyUltraAdvanced.ratio = -1 / 16; pmDifficultyUltraAdvanced.ratio = -1 / 16;
@ -456,6 +472,18 @@ class PlayMissionGui extends GuiImage {
} }
pmDifficultyCtrl.addChild(pmDifficultyUltraIntermediate); pmDifficultyCtrl.addChild(pmDifficultyUltraIntermediate);
var pmDifficultyGoldCustom = new GuiButtonText(loadButtonImages("data/ui/play/difficulty_highlight-120"), markerFelt24);
pmDifficultyGoldCustom.position = new Vector(37, 164);
pmDifficultyGoldCustom.ratio = -1 / 16;
pmDifficultyGoldCustom.setExtent(new Vector(120, 31));
pmDifficultyGoldCustom.txtCtrl.text.text = " Custom";
pmDifficultyGoldCustom.pressedAction = (e) -> {
currentList = Marbleland.goldMissions;
currentCategory = "custom";
setCategoryFunc("gold", "custom");
}
pmDifficultyCtrl.addChild(pmDifficultyGoldCustom);
var pmDifficultyGoldAdvanced = new GuiButtonText(loadButtonImages("data/ui/play/difficulty_highlight-120"), markerFelt24); var pmDifficultyGoldAdvanced = new GuiButtonText(loadButtonImages("data/ui/play/difficulty_highlight-120"), markerFelt24);
pmDifficultyGoldAdvanced.position = new Vector(37, 134); pmDifficultyGoldAdvanced.position = new Vector(37, 134);
pmDifficultyGoldAdvanced.ratio = -1 / 16; pmDifficultyGoldAdvanced.ratio = -1 / 16;
@ -741,7 +769,12 @@ class PlayMissionGui extends GuiImage {
currentList = MissionList.missionList["platinum"]["beginner"]; currentList = MissionList.missionList["platinum"]["beginner"];
setCategoryFunc = function(game:String, category:String, ?doRender:Bool = true) { setCategoryFunc = function(game:String, category:String, ?doRender:Bool = true) {
currentList = "category" == "custom" ? MissionList.customMissions : MissionList.missionList[game][category]; currentList = category == "custom" ? (switch (game) {
case 'gold': Marbleland.goldMissions;
case 'platinum': Marbleland.platinumMissions;
case 'ultra': Marbleland.ultraMissions;
default: MissionList.customMissions;
}) : MissionList.missionList[game][category];
@:privateAccess pmDifficulty.anim.frames = loadButtonImages('data/ui/play/difficulty_${category}'); @:privateAccess pmDifficulty.anim.frames = loadButtonImages('data/ui/play/difficulty_${category}');
pmDifficultyMarble.bmp.tile = ResourceLoader.getResource('data/ui/play/marble_${game}.png', ResourceLoader.getImage, this.imageResources).toTile(); pmDifficultyMarble.bmp.tile = ResourceLoader.getResource('data/ui/play/marble_${game}.png', ResourceLoader.getImage, this.imageResources).toTile();
@ -889,13 +922,13 @@ class PlayMissionGui extends GuiImage {
var scoreTextTime = '<p align="right"><font color="${scoreColor}" face="MarkerFelt18">${Util.formatTime(score.time)}</font></p>'; var scoreTextTime = '<p align="right"><font color="${scoreColor}" face="MarkerFelt18">${Util.formatTime(score.time)}</font></p>';
rightText += scoreTextTime; rightText += scoreTextTime;
descText += '<font color="#F4E4CE" face="MarkerFelt18">${i + 1}. <font color="#FFFFFF">${score.name}</font></font><br/>'; descText += '<font color="#F4E4CE" face="MarkerFelt18">${i + 1}. <font color="#FFFFFF">${StringTools.htmlEscape(score.name)}</font></font><br/>';
} }
pmDescriptionRight.text.text = rightText; pmDescriptionRight.text.text = rightText;
} else { } else {
descText += '<font color="#F4EFE3" face="MarkerFelt18"><p align="center">Author: ${currentMission.artist}</p></font>'; descText += '<font color="#F4EFE3" face="MarkerFelt18"><p align="center">Author: ${StringTools.htmlEscape(currentMission.artist)}</p></font>';
descText += '<font color="#F4E4CE" face="MarkerFelt18">${currentMission.description}</font>'; descText += '<font color="#F4E4CE" face="MarkerFelt18">${StringTools.htmlEscape(currentMission.description)}</font>';
pmDescriptionRight.text.text = ''; pmDescriptionRight.text.text = '';
} }
pmDescription.text.text = descText; pmDescription.text.text = descText;
@ -947,7 +980,10 @@ class PlayMissionGui extends GuiImage {
} }
#end #end
#if hl #if hl
var pTok = previewToken++;
var prevpath = currentMission.getPreviewImage(prevImg -> { var prevpath = currentMission.getPreviewImage(prevImg -> {
if (pTok + 1 != previewToken)
return;
pmPreview.bmp.tile = prevImg; pmPreview.bmp.tile = prevImg;
}); // Shit be sync }); // Shit be sync
if (prevpath != pmPreview.bmp.tile.getTexture().name) { if (prevpath != pmPreview.bmp.tile.getTexture().name) {

View file

@ -1,5 +1,6 @@
package gui; package gui;
import src.Marbleland;
import h2d.Tile; import h2d.Tile;
import hxd.BitmapData; import hxd.BitmapData;
import src.MarbleGame; import src.MarbleGame;
@ -9,7 +10,7 @@ import src.ResourceLoader;
import src.Settings; import src.Settings;
class SearchGui extends GuiImage { class SearchGui extends GuiImage {
public function new(game:String) { public function new(game:String, isCustom:Bool) {
var img = ResourceLoader.getImage("data/ui/search/window.png"); var img = ResourceLoader.getImage("data/ui/search/window.png");
super(img.resource.toTile()); super(img.resource.toTile());
@ -19,8 +20,29 @@ class SearchGui extends GuiImage {
this.extent = new Vector(487, 463); this.extent = new Vector(487, 463);
var missionList = []; var missionList = [];
for (diff in MissionList.missionList[game]) { if (!isCustom) {
for (mis in diff) { for (diff in MissionList.missionList[game]) {
for (mis in diff) {
missionList.push({
mis: mis,
name: mis.title,
artist: mis.artist,
path: mis.path
});
}
}
} else {
var customsList = switch (game) {
case 'gold':
Marbleland.goldMissions;
case 'platinum':
Marbleland.platinumMissions;
case 'ultra':
Marbleland.ultraMissions;
default:
MissionList.customMissions;
};
for (mis in customsList) {
missionList.push({ missionList.push({
mis: mis, mis: mis,
name: mis.title, name: mis.title,