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

View file

@ -471,7 +471,7 @@ class DtsObject extends GameObject {
}
function parseIfl(path:String) {
var text = ResourceLoader.fileSystem.get(path).getText();
var text = ResourceLoader.getFileEntry(path).entry.getText();
var lines = text.split('\n');
var keyframes = [];
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;
import src.Marbleland;
import src.Console;
import hxd.Key;
import src.Util;
@ -18,6 +19,7 @@ import hxd.res.DefaultFont;
import h2d.Text;
import h3d.Vector;
import src.ProfilerUI;
import src.Http;
class Main extends hxd.App {
var marbleGame:MarbleGame;
@ -66,10 +68,13 @@ class Main extends hxd.App {
#end
try {
Http.init();
haxe.MainLoop.add(() -> Http.loop());
Settings.init();
ResourceLoader.init(s2d, () -> {
AudioManager.init();
AudioManager.playShell();
Marbleland.init();
marbleGame = new MarbleGame(s2d, s3d);
MarbleGame.canvas.setContent(new MainMenuGui());

View file

@ -181,6 +181,8 @@ class MarbleWorld extends Scheduler {
public var _ready:Bool = false;
var _loadBegin:Bool = false;
var _loadingLength:Int = 0;
var _resourcesLoaded:Int = 0;
@ -207,7 +209,15 @@ class MarbleWorld extends Scheduler {
Console.log("*** LOADING MISSION: " + mission.path);
this.loadingGui = new LoadingGui(this.mission.title, this.mission.game);
MarbleGame.canvas.setContent(this.loadingGui);
if (this.mission.isClaMission) {
this.mission.download(() -> loadBegin());
} else {
loadBegin();
}
}
function loadBegin() {
_loadBegin = true;
function scanMission(simGroup:MissionElementSimGroup) {
for (element in simGroup.elements) {
if ([
@ -249,8 +259,12 @@ class MarbleWorld extends Scheduler {
}
public function loadMusic(onFinish:Void->Void) {
var musicFileName = 'sound/music/' + this.mission.missionInfo.music;
ResourceLoader.load(musicFileName).entry.load(onFinish);
if (this.mission.missionInfo.music != null) {
var musicFileName = 'sound/music/' + this.mission.missionInfo.music;
ResourceLoader.load(musicFileName).entry.load(onFinish);
} else {
onFinish();
}
}
public function postInit() {
@ -1031,7 +1045,7 @@ class MarbleWorld extends Scheduler {
public function addDtsObject(obj:DtsObject, onFinish:Void->Void) {
function parseIfl(path:String, onFinish:Array<String>->Void) {
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 keyframes = [];
for (line in lines) {
@ -1294,7 +1308,7 @@ class MarbleWorld extends Scheduler {
});
#end
} else {
if (this._resourcesLoaded < _loadingLength)
if (this._resourcesLoaded < _loadingLength || !this._loadBegin)
return;
if (!_ready && !postInited) {
postInited = true;
@ -2002,22 +2016,12 @@ class MarbleWorld extends Scheduler {
this.replay.name = MarbleGame.instance.recordingName;
#if hl
sys.FileSystem.createDirectory(haxe.io.Path.join([Settings.settingsDir, "data", "replays"]));
var replayPath = haxe.io.Path.join([
Settings.settingsDir,
"data",
"replays",
'${this.replay.name}.mbr'
]);
var replayPath = haxe.io.Path.join([Settings.settingsDir, "data", "replays", '${this.replay.name}.mbr']);
if (sys.FileSystem.exists(replayPath)) {
var count = 1;
var found = false;
while (!found) {
replayPath = haxe.io.Path.join([
Settings.settingsDir,
"data",
"replays",
'${this.replay.name} (${count}).mbr'
]);
replayPath = haxe.io.Path.join([Settings.settingsDir, "data", "replays", '${this.replay.name} (${count}).mbr']);
if (!sys.FileSystem.exists(replayPath)) {
this.replay.name += ' (${count})';
found = true;
@ -2066,7 +2070,8 @@ class MarbleWorld extends Scheduler {
}
}
this.playGui.dispose();
if (this.playGui != null)
this.playGui.dispose();
scene.removeChildren();
for (interior in this.interiors) {
@ -2091,7 +2096,8 @@ class MarbleWorld extends Scheduler {
textureResource.release();
}
sky.dispose();
if (sky != null)
sky.dispose();
this._disposed = true;
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;
import gui.Canvas;
import gui.MessageBoxOkDlg;
import haxe.Json;
import mis.MissionElement.MissionElementItem;
import haxe.io.BytesBuffer;
@ -15,6 +17,8 @@ import hxd.res.Image;
import src.Resource;
import src.Util;
import src.Console;
import src.Marbleland;
import src.MarbleGame;
class Mission {
public var root:MissionElementSimGroup;
@ -45,7 +49,7 @@ class Mission {
public function new() {}
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();
root = contents.root;
@ -60,6 +64,8 @@ class Mission {
} else if (element._type == MissionElementType.SimGroup && !this.hasEgg) {
scanMission(cast element);
}
if (element._name == 'MissionInfo')
missionInfo = cast element;
}
};
@ -153,10 +159,17 @@ class Mission {
onLoaded(Tile.fromBitmap(img));
return null;
} 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));
Marbleland.getMissionImage(this.id, (im) -> {
if (im != null) {
onLoaded(im.toTile());
} 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;
}
}
@ -175,15 +188,20 @@ class Mission {
#if (js || android)
path = StringTools.replace(path, "data/", "");
#end
if (ResourceLoader.fileSystem.exists(path))
if (ResourceLoader.exists(path))
return path;
if (StringTools.contains(path, 'interiors_mbg/'))
path = StringTools.replace(path, 'interiors_mbg/', 'interiors/');
var dirpath = path.substring(0, path.lastIndexOf('/') + 1);
if (ResourceLoader.fileSystem.exists(path))
if (ResourceLoader.exists(path))
return path;
if (ResourceLoader.fileSystem.exists(dirpath + fname))
if (ResourceLoader.exists(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);
return "";
}
@ -200,4 +218,17 @@ class Mission {
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;
}
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;
import hxd.res.Any;
import hxd.fs.BytesFileSystem.BytesFileEntry;
#if (js || android)
import fs.ManifestLoader;
import fs.ManifestBuilder;
@ -43,6 +45,7 @@ class ResourceLoader {
static var textureCache:Map<String, Resource<Texture>> = new Map();
static var imageCache:Map<String, Resource<Image>> = 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);
@ -256,9 +259,9 @@ class ResourceLoader {
#if (js || android)
path = StringTools.replace(path, "data/", "");
#end
if (ResourceLoader.fileSystem.exists(path))
if (ResourceLoader.exists(path))
return path;
if (ResourceLoader.fileSystem.exists(dirpath + fname))
if (ResourceLoader.exists(dirpath + fname))
return dirpath + fname;
return "";
}
@ -271,6 +274,9 @@ class ResourceLoader {
#if (js || android)
path = StringTools.replace(path, "data/", "");
#end
if (zipFilesystem.exists(path.toLowerCase())) {
return new hxd.res.Any(loader, zipFilesystem.get(path.toLowerCase()));
}
return ResourceLoader.loader.load(path);
}
@ -284,7 +290,10 @@ class ResourceLoader {
var itr:Dif;
// var lock = new Lock();
// 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 -> {});
interiorResources.set(path, itrresource);
// lock.release();
@ -296,6 +305,7 @@ class ResourceLoader {
public static function loadDts(path:String) {
path = getProperFilepath(path);
if (dtsResources.exists(path))
return dtsResources.get(path);
else {
@ -314,6 +324,18 @@ class ResourceLoader {
public static function getTexture(path:String) {
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))
return textureCache.get(path);
if (fileSystem.exists(path)) {
@ -336,6 +358,12 @@ class ResourceLoader {
#if (js || android)
path = StringTools.replace(path, "data/", "");
#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))
return imageCache.get(path);
if (fileSystem.exists(path)) {
@ -379,10 +407,20 @@ class ResourceLoader {
#if (js || android)
path = StringTools.replace(path, "data/", "");
#end
if (zipFilesystem.exists(path.toLowerCase())) {
var fentry = zipFilesystem.get(path.toLowerCase());
return new hxd.res.Any(loader, fentry);
}
var file = loader.load(path);
return file;
}
public static function exists(path:String) {
if (zipFilesystem.exists(path.toLowerCase()))
return true;
return fileSystem.exists(path);
}
public static function clearInteriorResources() {
interiorResources = new Map();
}
@ -405,4 +443,17 @@ class ResourceLoader {
}
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)
dmlPath = StringTools.replace(dmlPath, "data/", "");
#end
if (ResourceLoader.fileSystem.exists(dmlPath)) {
var dmlFileEntry = ResourceLoader.fileSystem.get(dmlPath);
if (ResourceLoader.exists(dmlPath)) {
var dmlFileEntry = ResourceLoader.getFileEntry(dmlPath).entry;
dmlFileEntry.load(() -> {
var dmlFile = dmlFileEntry.getText();
var dmlDirectory = Path.directory(dmlPath);

View file

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

View file

@ -1,5 +1,6 @@
package gui;
import src.Marbleland;
import h2d.filter.DropShadow;
import src.Replay;
import haxe.ds.Option;
@ -50,6 +51,9 @@ class PlayMissionGui extends GuiImage {
#if js
var previewTimeoutHandle:Option<Int> = None;
#end
#if hl
var previewToken:Int = 0;
#end
public function new() {
MissionList.buildMissionList();
@ -195,7 +199,7 @@ class PlayMissionGui extends GuiImage {
pmSearch.position = new Vector(315, 325);
pmSearch.extent = new Vector(43, 43);
pmSearch.pressedAction = (e) -> {
MarbleGame.canvas.pushDialog(new SearchGui(currentGame));
MarbleGame.canvas.pushDialog(new SearchGui(currentGame, currentCategory == "custom"));
}
pmBox.addChild(pmSearch);
@ -420,6 +424,18 @@ class PlayMissionGui extends GuiImage {
pmDifficultyTopCTab2.vertSizing = Bottom;
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);
pmDifficultyUltraAdvanced.position = new Vector(277, 134);
pmDifficultyUltraAdvanced.ratio = -1 / 16;
@ -456,6 +472,18 @@ class PlayMissionGui extends GuiImage {
}
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);
pmDifficultyGoldAdvanced.position = new Vector(37, 134);
pmDifficultyGoldAdvanced.ratio = -1 / 16;
@ -741,7 +769,12 @@ class PlayMissionGui extends GuiImage {
currentList = MissionList.missionList["platinum"]["beginner"];
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}');
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>';
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;
} else {
descText += '<font color="#F4EFE3" face="MarkerFelt18"><p align="center">Author: ${currentMission.artist}</p></font>';
descText += '<font color="#F4E4CE" face="MarkerFelt18">${currentMission.description}</font>';
descText += '<font color="#F4EFE3" face="MarkerFelt18"><p align="center">Author: ${StringTools.htmlEscape(currentMission.artist)}</p></font>';
descText += '<font color="#F4E4CE" face="MarkerFelt18">${StringTools.htmlEscape(currentMission.description)}</font>';
pmDescriptionRight.text.text = '';
}
pmDescription.text.text = descText;
@ -947,7 +980,10 @@ class PlayMissionGui extends GuiImage {
}
#end
#if hl
var pTok = previewToken++;
var prevpath = currentMission.getPreviewImage(prevImg -> {
if (pTok + 1 != previewToken)
return;
pmPreview.bmp.tile = prevImg;
}); // Shit be sync
if (prevpath != pmPreview.bmp.tile.getTexture().name) {

View file

@ -1,5 +1,6 @@
package gui;
import src.Marbleland;
import h2d.Tile;
import hxd.BitmapData;
import src.MarbleGame;
@ -9,7 +10,7 @@ import src.ResourceLoader;
import src.Settings;
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");
super(img.resource.toTile());
@ -19,8 +20,29 @@ class SearchGui extends GuiImage {
this.extent = new Vector(487, 463);
var missionList = [];
for (diff in MissionList.missionList[game]) {
for (mis in diff) {
if (!isCustom) {
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({
mis: mis,
name: mis.title,