asset changes
Some checks failed
CI / build-test-release (push) Failing after 15m11s

This commit is contained in:
Jorijn van der Graaf 2026-05-19 00:50:06 +02:00
commit f442caa888
6 changed files with 224 additions and 11 deletions

View file

@ -17,6 +17,15 @@ License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
module;
#if defined(CRAFTER_BUILD_CONFIGURATION_TARGET_x86_64_pc_windows_msvc) || defined(CRAFTER_BUILD_CONFIGURATION_TARGET_x86_64_w64_mingw32)
#include <winsock2.h>
#include <ws2tcpip.h>
#else
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#endif
export module Crafter.Build:Clang_impl;
import std;
import :Clang;
@ -304,7 +313,12 @@ BuildResult Crafter::Build(Configuration& config, std::unordered_map<fs::path, s
// a single thread to match the cfg.files pattern.
auto compressedName = [](const fs::path& src) -> std::optional<fs::path> {
std::string ext = src.extension().string();
if (ext == ".png") return fs::path(src.filename()).replace_extension(".ctex");
for (char& c : ext) c = static_cast<char>(std::tolower(static_cast<unsigned char>(c)));
// stb_image (used by CompressAsset → TextureAsset::LoadPNG) handles
// png/tga/jpg/bmp; all map to .ctex.
if (ext == ".png" || ext == ".tga" || ext == ".jpg" || ext == ".jpeg" || ext == ".bmp") {
return fs::path(src.filename()).replace_extension(".ctex");
}
if (ext == ".obj") return fs::path(src.filename()).replace_extension(".cmesh");
return std::nullopt;
};
@ -341,7 +355,7 @@ BuildResult Crafter::Build(Configuration& config, std::unordered_map<fs::path, s
std::optional<fs::path> outName = compressedName(asset);
if (!outName) {
buildCancelled.store(true);
buildError = std::format("{}: unsupported asset extension (expected .png or .obj, or a directory)", asset.string());
buildError = std::format("{}: unsupported asset extension (expected .png/.tga/.jpg/.bmp/.obj, or a directory)", asset.string());
break;
}
submitCompress(asset, *outName);
@ -752,10 +766,15 @@ BuildResult Crafter::Build(Configuration& config, std::unordered_map<fs::path, s
continue;
}
std::string ext = asset.extension().string();
for (char& c : ext) c = static_cast<char>(std::tolower(static_cast<unsigned char>(c)));
fs::path srcName = asset.filename();
if (ext == ".png") srcName.replace_extension(".ctex");
else if (ext == ".obj") srcName.replace_extension(".cmesh");
else continue;
if (ext == ".png" || ext == ".tga" || ext == ".jpg" || ext == ".jpeg" || ext == ".bmp") {
srcName.replace_extension(".ctex");
} else if (ext == ".obj") {
srcName.replace_extension(".cmesh");
} else {
continue;
}
fs::path src = depBinDir / srcName;
if (!fs::exists(src)) continue;
copyTree(src, outputDir / srcName);
@ -1080,7 +1099,22 @@ void Crafter::EnableWasiBrowserRuntime(Configuration& cfg) {
// runtime.js into an in-memory VFS so the wasm's std::ifstream et al.
// can actually read them (the wasi-runtime in this repo otherwise
// stubs every fd syscall to zero). The manifest lists basenames only;
// each file lives next to the .wasm in the bin dir.
// each file lives next to the .wasm in the bin dir. wasi-runtime
// reduces every path_open path to its basename, so subdir layouts
// collapse — that's fine for our flat-bin convention.
auto compressedBasename = [](const fs::path& src) -> std::optional<std::string> {
std::string ext = src.extension().string();
for (char& c : ext) c = static_cast<char>(std::tolower(static_cast<unsigned char>(c)));
fs::path out = src.filename();
if (ext == ".png" || ext == ".tga" || ext == ".jpg" || ext == ".jpeg" || ext == ".bmp") {
out.replace_extension(".ctex");
} else if (ext == ".obj") {
out.replace_extension(".cmesh");
} else {
return std::nullopt;
}
return out.string();
};
std::vector<std::string> assetFiles;
seen.clear();
std::function<void(Configuration*)> walkAssets = [&](Configuration* c) {
@ -1095,6 +1129,31 @@ void Crafter::EnableWasiBrowserRuntime(Configuration& cfg) {
assetFiles.push_back(std::move(name));
}
}
// cfg.assets — emit the *compressed* output basename. Directory
// entries get the same compressed-basename treatment per file;
// unrecognized extensions are treated as passthrough (kept under
// their original name, matching the build-side passthrough copy).
for (const fs::path& a : c->assets) {
if (fs::is_directory(a)) {
std::error_code ec;
for (const auto& entry : fs::recursive_directory_iterator(a, ec)) {
if (ec) break;
if (!entry.is_regular_file()) continue;
std::string name = compressedBasename(entry.path())
.value_or(entry.path().filename().string());
if (name.empty()) continue;
if (std::find(assetFiles.begin(), assetFiles.end(), name) == assetFiles.end()) {
assetFiles.push_back(std::move(name));
}
}
} else {
std::optional<std::string> name = compressedBasename(a);
if (!name) continue;
if (std::find(assetFiles.begin(), assetFiles.end(), *name) == assetFiles.end()) {
assetFiles.push_back(std::move(*name));
}
}
}
for (Configuration* dep : c->dependencies) walkAssets(dep);
};
walkAssets(&cfg);
@ -1339,10 +1398,35 @@ int Crafter::Run(int argc, char** argv) {
return std::system(probe.c_str()) == 0;
};
if (browserBuild) {
// Try installed HTTP servers in priority order: lightweight
// / dependency-free first, ad-hoc ones last. Foreground
// (Ctrl-C to stop); we exec, not fork.
const int port = 8080;
// Probe-bind to find a free port starting at 8080 — if the
// user has another dev server running we shift up rather
// than letting caddy/python exit with EADDRINUSE.
auto findFreePort = [](int basePort, int span) -> int {
#if defined(CRAFTER_BUILD_CONFIGURATION_TARGET_x86_64_pc_windows_msvc) || defined(CRAFTER_BUILD_CONFIGURATION_TARGET_x86_64_w64_mingw32)
static const bool wsaInit = []{ WSADATA d; return WSAStartup(MAKEWORD(2, 2), &d) == 0; }();
if (!wsaInit) return basePort;
using sock_t = SOCKET;
const sock_t invalid = INVALID_SOCKET;
auto closesock = [](sock_t s){ closesocket(s); };
#else
using sock_t = int;
const sock_t invalid = -1;
auto closesock = [](sock_t s){ ::close(s); };
#endif
for (int p = basePort; p < basePort + span; ++p) {
sock_t s = ::socket(AF_INET, SOCK_STREAM, 0);
if (s == invalid) return basePort;
sockaddr_in addr{};
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = htonl(INADDR_ANY);
addr.sin_port = htons(static_cast<uint16_t>(p));
bool ok = ::bind(s, reinterpret_cast<sockaddr*>(&addr), sizeof(addr)) == 0;
closesock(s);
if (ok) return p;
}
return basePort;
};
const int port = findFreePort(8080, 16);
std::string cmd;
std::string_view picked;
if (have("caddy")) {