From 664fb3bfb525233d6e39fc4f7fdf0112de8a934a Mon Sep 17 00:00:00 2001 From: LordMZTE Date: Sun, 26 Jun 2022 00:15:29 +0200 Subject: [PATCH] feat: ported build script to zig also some housekeeping --- build.sh | 22 ---- build.zig | 279 ++++++++++++++++++++++++++++++++++++++++++ mods.txt | 7 +- overrides/options.txt | 154 +++++++++++++++++++++++ settings.zig | 6 + 5 files changed, 444 insertions(+), 24 deletions(-) delete mode 100755 build.sh create mode 100755 build.zig create mode 100644 overrides/options.txt create mode 100644 settings.zig diff --git a/build.sh b/build.sh deleted file mode 100755 index d3bfed9..0000000 --- a/build.sh +++ /dev/null @@ -1,22 +0,0 @@ -#!/bin/bash -set -e - -VERSION="0.1.0" -BUILDPATH="build/zip" - -rm -rf $BUILDPATH || true -mkdir -p $BUILDPATH -cp -r overrides $BUILDPATH/minecraft -mkdir -p $BUILDPATH/minecraft/mods -cp mmc-pack.json $BUILDPATH -echo "InstanceType=OneSix" > $BUILDPATH/instance.cfg - -cd $BUILDPATH/minecraft/mods -while read -r mod; do - echo "Downloading $mod" - curl -LO "$mod" -done <../../../../mods.txt -cd ../.. - -rm ../*.zip || true -zip -r "../ac4-$VERSION.zip" ./* diff --git a/build.zig b/build.zig new file mode 100755 index 0000000..8c82505 --- /dev/null +++ b/build.zig @@ -0,0 +1,279 @@ +//usr/bin/env zig run $0 -lc `pkgconf --libs libarchive libcurl`; exit +// This script requires a zig compiler, libarchive and libcurl to run. +// If you're on windows, screw you lol + +const std = @import("std"); +const c = @cImport({ + @cInclude("curl/curl.h"); + @cInclude("archive.h"); + @cInclude("archive_entry.h"); +}); +const settings = @import("settings.zig"); + +pub fn main() !void { + // used to buffer whatever + var buf: [512]u8 = undefined; + try std.fs.cwd().deleteTree(settings.build_dir); + try std.fs.cwd().makeDir(settings.build_dir); + + var zip = c.archive_write_new(); + if (zip == null) + return error.ArchiveNewError; + defer _ = c.archive_write_free(zip); + try handleArchiveErr(c.archive_write_set_format_zip(zip), zip); + try handleArchiveErr(c.archive_write_set_format_option( + zip, + "zip", + "compression-level", + settings.compression_level, + ), zip); + try handleArchiveErr(c.archive_write_open_filename( + zip, + settings.build_dir ++ "/ac4-" ++ settings.version ++ ".zip", + ), zip); + + var entry = c.archive_entry_new(); + defer c.archive_entry_free(entry); + entrySetDir(entry.?); + c.archive_entry_set_size(entry, 0); + c.archive_entry_set_pathname(entry, "minecraft/"); + try handleArchiveErr(c.archive_write_header(zip, entry), zip); + c.archive_entry_set_pathname(entry, "minecraft/mods/"); + try handleArchiveErr(c.archive_write_header(zip, entry), zip); + + var overrides = try std.fs.cwd().openDir("overrides", .{ .iterate = true }); + defer overrides.close(); + var walker = try overrides.walk(std.heap.c_allocator); + defer walker.deinit(); + + while (try walker.next()) |e| { + switch (e.kind) { + .Directory => { + const path = try std.mem.concat( + std.heap.c_allocator, + u8, + &[_][]const u8{ "minecraft/", e.path, "/\x00" }, + ); + defer std.heap.c_allocator.free(path); + entrySetDir(entry.?); + c.archive_entry_set_pathname(entry, path.ptr); + try handleArchiveErr(c.archive_write_header(zip, entry), zip); + }, + .File => { + var file = try overrides.openFile(e.path, .{}); + const stat = try file.stat(); + entrySetFile(entry.?); + c.archive_entry_set_size(entry, @intCast(i64, stat.size)); + const path = try std.mem.concatWithSentinel( + std.heap.c_allocator, + u8, + &[_][]const u8{ "minecraft/", e.path }, + 0, + ); + defer std.heap.c_allocator.free(path); + c.archive_entry_set_pathname(entry, path); + try handleArchiveErr(c.archive_write_header(zip, entry), zip); + + var read = try file.read(&buf); + while (read != 0) { + _ = c.archive_write_data(zip, &buf, read); + read = try file.read(&buf); + } + }, + else => {}, + } + } + + entrySetFile(entry.?); + var file = try std.fs.cwd().openFile("mmc-pack.json", .{}); + c.archive_entry_set_pathname(entry, "mmc-pack.json"); + c.archive_entry_set_size(entry, @intCast(i64, (try file.stat()).size)); + try handleArchiveErr(c.archive_write_header(zip, entry), zip); + + var read = try file.read(&buf); + while (read != 0) { + _ = c.archive_write_data(zip, &buf, read); + read = try file.read(&buf); + } + + const instance_cfg_data = "InstanceType=OneSix"; + c.archive_entry_set_pathname(entry, "instance.cfg"); + c.archive_entry_set_size(entry, instance_cfg_data.len); + try handleArchiveErr(c.archive_write_header(zip, entry), zip); + _ = c.archive_write_data( + zip, + instance_cfg_data, + instance_cfg_data.len, + ); + + var mods_arena = std.heap.ArenaAllocator.init(std.heap.c_allocator); + defer mods_arena.deinit(); + var mods = std.ArrayList([]u8).init(std.heap.c_allocator); + defer mods.deinit(); + + readMods(&mods, mods_arena.allocator()) catch |err| { + std.log.err("Error reading mods.txt", .{}); + return err; + }; + + downloadMods(mods.items, zip.?, entry.?) catch |err| { + std.log.err("Error downloading mods", .{}); + return err; + }; + + try handleArchiveErr(c.archive_write_close(zip), zip); +} + +fn readMods(list: *std.ArrayList([]u8), alloc: std.mem.Allocator) !void { + var file = try std.fs.cwd().openFile("mods.txt", .{}); + defer file.close(); + var line_buf: [1024]u8 = undefined; + + while (try file.reader().readUntilDelimiterOrEof(&line_buf, '\n')) |line| { + // mods.txt has comments with "#" + const line_without_comment = std.mem.sliceTo(line, '#'); + const trimmed_line = std.mem.trim(u8, line_without_comment, "\n\r\t "); + if (trimmed_line.len != 0) { + try list.append(try alloc.dupe(u8, trimmed_line)); + } + } +} + +fn curlWriteCallback( + data: [*]const u8, + size: usize, + nmemb: usize, + out: *std.ArrayList(u8), +) callconv(.C) usize { + const realsize = size * nmemb; + out.writer().writeAll(data[0..realsize]) catch return 0; + return realsize; +} + +fn curlInfoCallback( + filename: *[]const u8, + dltotal: c.curl_off_t, + dlnow: c.curl_off_t, + ultotal: c.curl_off_t, + ulnow: c.curl_off_t, +) callconv(.C) usize { + _ = ultotal; + _ = ulnow; + std.io.getStdOut().writer().print( + "\x1b[2K\r\x1b[34m{s} \x1b[32m{}%", + .{ + filename.*, + if (dltotal != 0) @divTrunc(dlnow * 100, dltotal) else 0, + }, + ) catch {}; + return 0; +} + +fn downloadMods( + mods: []const []const u8, + zip: *c.archive, + entry: *c.archive_entry, +) !void { + var curl = c.curl_easy_init(); + if (curl == null) + return error.CurlInitError; + defer c.curl_easy_cleanup(curl); + + try handleCurlErr(c.curl_easy_setopt( + curl, + c.CURLOPT_WRITEFUNCTION, + curlWriteCallback, + )); + try handleCurlErr(c.curl_easy_setopt( + curl, + c.CURLOPT_XFERINFOFUNCTION, + curlInfoCallback, + )); + try handleCurlErr(c.curl_easy_setopt(curl, c.CURLOPT_NOPROGRESS, @as(c_long, 0))); + try handleCurlErr(c.curl_easy_setopt(curl, c.CURLOPT_FOLLOWLOCATION, @as(c_long, 1))); + + var mod_buf = std.ArrayList(u8).init(std.heap.c_allocator); + defer mod_buf.deinit(); + defer std.io.getStdOut().writeAll("\x1b[0\n") catch {}; + for (mods) |mod| { + mod_buf.clearRetainingCapacity(); + var splits = std.mem.split(u8, mod, "/"); + var filename: ?[]const u8 = null; + while (splits.next()) |split| + filename = split; + + if (filename == null or filename.?.len == 0) { + std.log.err("Failed to get filename of URL {s}", .{mod}); + return error.BorkedUrl; + } + + try handleCurlErr(c.curl_easy_setopt(curl, c.CURLOPT_WRITEDATA, &mod_buf)); + try handleCurlErr(c.curl_easy_setopt(curl, c.CURLOPT_XFERINFODATA, &filename)); + try handleCurlErr(c.curl_easy_setopt(curl, c.CURLOPT_XFERINFODATA, &filename)); + + const mod_cstr = try std.cstr.addNullByte(std.heap.c_allocator, mod); + defer std.heap.c_allocator.free(mod_cstr); + + try handleCurlErr(c.curl_easy_setopt( + curl, + c.CURLOPT_URL, + @ptrCast([*c]const u8, mod_cstr), + )); + try handleCurlErr(c.curl_easy_perform(curl)); + + std.io.getStdOut().writer().print( + "\x1b[2K\r\x1b[34m{s} \x1b[31mZipping...", + .{filename.?}, + ) catch {}; + + const file_cstr = try std.cstr.addNullByte(std.heap.c_allocator, filename.?); + defer std.heap.c_allocator.free(file_cstr); + + var archive_path = try std.mem.concatWithSentinel( + std.heap.c_allocator, + u8, + &[_][]const u8{ "minecraft/mods/", file_cstr }, + 0, + ); + defer std.heap.c_allocator.free(archive_path); + + c.archive_entry_set_pathname(entry, archive_path.ptr); + c.archive_entry_set_size(entry, @intCast(i64, mod_buf.items.len)); + try handleArchiveErr(c.archive_write_header(zip, entry), zip); + _ = c.archive_write_data( + zip, + mod_buf.items.ptr, + mod_buf.items.len, + ); + std.io.getStdOut().writer().print( + "\x1b[2K\r\x1b[34m{s}\n", + .{filename.?}, + ) catch {}; + } +} + +fn entrySetDir(entry: *c.archive_entry) void { + c.archive_entry_set_mode(entry, c.S_IFDIR | 0777); + c.archive_entry_set_size(entry, 0); +} + +fn entrySetFile(entry: *c.archive_entry) void { + c.archive_entry_set_mode(entry, c.S_IFREG | 0777); +} + +fn handleCurlErr(code: c.CURLcode) !void { + if (code != c.CURLE_OK) { + std.log.err("Curl error: {s}", .{c.curl_easy_strerror(code)}); + return error.CurlError; + } +} + +fn handleArchiveErr(err: anytype, archive: ?*c.archive) !void { + if (err != c.ARCHIVE_OK) { + if (archive) |ar| { + if (c.archive_error_string(ar)) |err_s| + std.log.err("Archive error: {s}", .{err_s}); + } + return error.ArchiveError; + } +} diff --git a/mods.txt b/mods.txt index 55f6028..98392ca 100644 --- a/mods.txt +++ b/mods.txt @@ -18,7 +18,8 @@ https://cdn.modrinth.com/data/ls90k6B8/versions/0.7.2/simplepipes-all-0.7.2.jar https://cdn.modrinth.com/data/kXygSBVI/versions/5.0.0-alpha.2/traverse-5.0.0-alpha.2.jar https://cdn.modrinth.com/data/hvFnDODi/versions/0.1.2/lazydfu-0.1.2.jar https://cdn.modrinth.com/data/LMEONxlN/versions/1.4.1-BETA+1.18/lifts-1.4.1-BETA%2B1.18.jar -https://cdn.modrinth.com/data/q8MC5tW2/versions/2.6.12/bitsandchisels-2.6.12.jar +# deactivated until crash is resolved +#https://cdn.modrinth.com/data/q8MC5tW2/versions/2.6.12/bitsandchisels-2.6.12.jar https://cdn.modrinth.com/data/eldBwa5V/versions/1.100.6/cc-restitched-1.100.6.jar https://cdn.modrinth.com/data/yoEkK5RL/versions/2.3.2+fabric-1.18.2/purpeille-2.3.2%2Bfabric-1.18.2.jar https://cdn.modrinth.com/data/GUwDZ4ZU/versions/2.2.4+quilt/portal_cubed-2.2.4.jar @@ -31,7 +32,8 @@ https://cdn.modrinth.com/data/WuFYdGVB/versions/2.0.10+fabric/flyingfluxery-3.0. https://cdn.modrinth.com/data/OrJTMhHF/versions/mc1.18-4.1/sync-mc1.18.2-4.1.jar https://cdn.modrinth.com/data/34431T56/versions/1.0.6+1.18.2/wthit-plugins-1.0.6%2B1.18.2.jar https://cdn.modrinth.com/data/yn9u3ypm/versions/2.0.3+1.18.2/graves-2.0.3%2B1.18.2.jar -https://cdn.modrinth.com/data/IKpsG0nF/versions/1.6.8/paradise-lost-1.6.8%2B1.18.2.jar +# disabled because crash with create +#https://cdn.modrinth.com/data/IKpsG0nF/versions/1.6.8/paradise-lost-1.6.8%2B1.18.2.jar https://cdn.modrinth.com/data/zgaWtmrV/versions/1.29/arcanus-1.29.jar https://cdn.modrinth.com/data/F6KTit9k/versions/1.0.12/magitekmechs-fabric-MC1.18-1.0.12.jar https://cdn.modrinth.com/data/4KWv7wbN/versions/1.4.5/chisel-1.4.5%2B1.18.2.jar @@ -54,3 +56,4 @@ https://edge.forgecdn.net/files/3798/506/RebornCore-5.2.0.jar https://edge.forgecdn.net/files/3827/255/geckolib-fabric-1.18-3.0.47.jar https://cdn.modrinth.com/data/9s6osm5g/versions/6.2.62/cloth-config-fabric-6.2.62.jar https://edge.forgecdn.net/files/3668/220/autoconfig1u-3.4.0.jar +https://cdn.modrinth.com/data/5aaWibi9/versions/3.3.1/trinkets-3.3.1.jar diff --git a/overrides/options.txt b/overrides/options.txt new file mode 100644 index 0000000..179c82e --- /dev/null +++ b/overrides/options.txt @@ -0,0 +1,154 @@ +version:2975 +autoJump:false +autoSuggestions:true +chatColors:true +chatLinks:true +chatLinksPrompt:true +enableVsync:true +entityShadows:true +forceUnicodeFont:false +discrete_mouse_scroll:false +invertYMouse:false +realmsNotifications:true +reducedDebugInfo:false +showSubtitles:false +touchscreen:false +fullscreen:false +bobView:true +toggleCrouch:false +toggleSprint:false +darkMojangStudiosBackground:false +hideLightningFlashes:false +mouseSensitivity:0.5 +fov:0.0 +screenEffectScale:1.0 +fovEffectScale:1.0 +gamma:1.0 +renderDistance:12 +simulationDistance:12 +entityDistanceScaling:1.0 +guiScale:2 +particles:0 +maxFps:120 +difficulty:2 +graphicsMode:2 +ao:2 +prioritizeChunkUpdates:0 +biomeBlendRadius:2 +renderClouds:true +resourcePacks:["Fabric Mods","Theinar Language"] +incompatibleResourcePacks:[] +lastServer: +lang:en_us +soundDevice: +chatVisibility:0 +chatOpacity:1.0 +chatLineSpacing:0.0 +textBackgroundOpacity:0.5 +backgroundForChatOnly:true +hideServerAddress:false +advancedItemTooltips:false +pauseOnLostFocus:true +overrideWidth:0 +overrideHeight:0 +heldItemTooltips:true +chatHeightFocused:1.0 +chatDelay:0.0 +chatHeightUnfocused:0.44366195797920227 +chatScale:1.0 +chatWidth:1.0 +mipmapLevels:4 +useNativeTransport:true +mainHand:right +attackIndicator:1 +narrator:0 +tutorialStep:movement +mouseWheelSensitivity:1.0 +rawMouseInput:true +glDebugVerbosity:1 +skipMultiplayerWarning:false +skipRealms32bitWarning:false +hideMatchedNames:true +joinedFirstServer:false +hideBundleTutorial:false +syncChunkWrites:false +showAutosaveIndicator:true +allowServerListing:true +key_key.attack:key.mouse.left +key_key.use:key.mouse.right +key_key.forward:key.keyboard.w +key_key.left:key.keyboard.a +key_key.back:key.keyboard.s +key_key.right:key.keyboard.d +key_key.jump:key.keyboard.space +key_key.sneak:key.keyboard.left.shift +key_key.sprint:key.keyboard.left.control +key_key.drop:key.keyboard.q +key_key.inventory:key.keyboard.e +key_key.chat:key.keyboard.t +key_key.playerlist:key.keyboard.tab +key_key.pickItem:key.mouse.middle +key_key.command:key.keyboard.slash +key_key.socialInteractions:key.keyboard.p +key_key.screenshot:key.keyboard.f2 +key_key.togglePerspective:key.keyboard.f5 +key_key.smoothCamera:key.keyboard.unknown +key_key.fullscreen:key.keyboard.f11 +key_key.spectatorOutlines:key.keyboard.unknown +key_key.swapOffhand:key.keyboard.f +key_key.saveToolbarActivator:key.keyboard.c +key_key.loadToolbarActivator:key.keyboard.x +key_key.advancements:key.keyboard.l +key_key.hotbar.1:key.keyboard.1 +key_key.hotbar.2:key.keyboard.2 +key_key.hotbar.3:key.keyboard.3 +key_key.hotbar.4:key.keyboard.4 +key_key.hotbar.5:key.keyboard.5 +key_key.hotbar.6:key.keyboard.6 +key_key.hotbar.7:key.keyboard.7 +key_key.hotbar.8:key.keyboard.8 +key_key.hotbar.9:key.keyboard.9 +key_key.iron-jetpacks.engine:key.keyboard.v +key_key.iron-jetpacks.hover:key.keyboard.g +key_key.iron-jetpacks.descend:key.keyboard.unknown +key_key.ae2.wireless_terminal:key.keyboard.unknown +key_key.ae2.portable_item_cell:key.keyboard.unknown +key_key.ae2.portable_fluid_cell:key.keyboard.unknown +key_key.ae2.wireless_pattern_encoding_terminal:key.keyboard.unknown +key_key.ae2.wireless_pattern_access_terminal:key.keyboard.unknown +key_key.ae2.ae2wtlib_restock:key.keyboard.unknown +key_key.ae2.ae2wtlib_magnet:key.keyboard.unknown +key_key.botania_corporea_request:key.keyboard.c +key_create.keyinfo.toolmenu:key.keyboard.left.alt +key_create.keyinfo.toolbelt:key.keyboard.left.alt +key_key.dml-refabricated.teleport:key.keyboard.v +key_key.dml-refabricated.soul_vision:key.keyboard.b +key_key.indrev.modular:key.keyboard.k +key_key.indrev.gamer_axe_toggle:key.keyboard.g +key_mininggadgets.text.open_gui:key.keyboard.unknown +key_key.modern_industrialization.activate:key.keyboard.v +key_key.mtmechs.primary:key.keyboard.v +key_key.mtr.lift_menu:key.keyboard.z +key_key.waila.config:key.keyboard.keypad.0 +key_key.waila.show_overlay:key.keyboard.keypad.1 +key_key.waila.toggle_liquid:key.keyboard.keypad.2 +key_key.waila.show_recipe_input:key.keyboard.keypad.3 +key_key.waila.show_recipe_output:key.keyboard.keypad.4 +key_key.wthit-plugins.show_author:key.keyboard.left.shift +soundCategory_master:1.0 +soundCategory_music:0.0 +soundCategory_record:1.0 +soundCategory_weather:1.0 +soundCategory_block:1.0 +soundCategory_hostile:1.0 +soundCategory_neutral:1.0 +soundCategory_player:1.0 +soundCategory_ambient:1.0 +soundCategory_voice:1.0 +modelPart_cape:true +modelPart_jacket:true +modelPart_left_sleeve:true +modelPart_right_sleeve:true +modelPart_left_pants_leg:true +modelPart_right_pants_leg:true +modelPart_hat:true diff --git a/settings.zig b/settings.zig new file mode 100644 index 0000000..d4044f8 --- /dev/null +++ b/settings.zig @@ -0,0 +1,6 @@ +// Version number used for the archive name +pub const version = "0.1.0"; +pub const build_dir = "build"; +// zip compression level. 9 is max. ask libarchive why this is a string. +pub const compression_level = "9"; +