diff --git a/modules/nixos/minecraft-bedrock.nix b/modules/nixos/minecraft-bedrock.nix index a3f90489..630c3c35 100644 --- a/modules/nixos/minecraft-bedrock.nix +++ b/modules/nixos/minecraft-bedrock.nix @@ -27,14 +27,68 @@ let }; }; }; + packModule = {config, lib, ...}: let + inherit (lib.options) mkOption mkEnableOption; + inherit (lib.modules) mkIf mkOptionDefault; + inherit (lib.strings) splitString; + inherit (builtins) typeOf; + in { + options = with lib.types; { + enable = mkEnableOption "pack" // { + default = true; + }; + package = mkOption { + type = nullOr package; + default = null; + }; + packDir = mkOption { + type = str; + }; + packType = mkOption { + type = enum [ "resource_packs" "behavior_packs" ]; + }; + packId = mkOption { + type = str; + }; + version = mkOption { + type = oneOf [ str (listOf str) ]; + }; + settings = mkOption { + type = attrsOf (oneOf [ str (listOf str) ]); + }; + }; + config = { + packId = mkIf (config.package != null && config.package ? minecraft-bedrock.pack.pack_id) (mkOptionDefault + config.package.minecraft-bedrock.pack.pack_id + ); + packType = mkIf (config.package != null && config.package ? minecraft-bedrock.pack.type) (mkOptionDefault + config.package.minecraft-bedrock.pack.type + ); + version = mkIf (config.package != null && config.package ? minecraft-bedrock.pack.version) (mkOptionDefault + config.package.minecraft-bedrock.pack.version + ); + packDir = mkIf (config.package != null && config.package ? minecraft-bedrock.pack.dir) (mkOptionDefault + config.package.minecraft-bedrock.pack.dir + ); + settings = { + pack_id = mkOptionDefault config.packId; + version = mkOptionDefault { + string = splitString "." config.version; + list = config.version; + }.${typeOf config.version}; + }; + }; + }; in { config, gensokyo-zone, lib, pkgs, ... }: let # see https://gist.github.com/datakurre/cfdf627fb23ed8ff62bb7b3520b92674 inherit (gensokyo-zone.lib) mapOptionDefaults; inherit (lib.options) mkOption mkPackageOption; inherit (lib.modules) mkIf mkMerge mkOptionDefault; - inherit (lib.attrsets) mapAttrsToList; + inherit (lib.attrsets) filterAttrs mapAttrsToList; inherit (lib.strings) concatStringsSep; inherit (lib.trivial) boolToString; + inherit (lib.meta) getExe; + inherit (builtins) toJSON; cfg = config.services.minecraft-bedrock-server; cfgToString = v: if builtins.isBool v then boolToString v else toString v; @@ -130,6 +184,17 @@ in { allowList = mkOption { type = nullOr path; }; + + packs = mkOption { + type = attrsOf (submoduleWith { + modules = [ packModule ]; + specialArgs = { + inherit gensokyo-zone; + nixosConfig = config; + }; + }); + default = { }; + }; }; config = let @@ -163,7 +228,7 @@ in { allowList = let allowPlayers = mapAttrsToList (_: allow: allow.settings) cfg.allowPlayers; allowListJson = pkgs.writeText "minecraft-bedrock-server-allowlist.json" ( - builtins.toJSON allowPlayers + toJSON allowPlayers ); in mkOptionDefault ( if cfg.allowPlayers != null then allowListJson @@ -186,7 +251,7 @@ in { serviceConfig = { BindReadOnlyPaths = let - packageResources = map (subpath: "${cfg.package}/var/lib/${subpath}:${cfg.dataDir}/${subpath}") [ + packageResources = map (subpath: "${cfg.package}/var/lib/minecraft-bedrock/${subpath}:${cfg.dataDir}/${subpath}") [ "definitions/attachables" "definitions/biomes" "definitions/feature_rules" @@ -201,12 +266,32 @@ in { "env-vars" "permissions.json" ]; + mkWorldPacks = type: let + enabledPacks = filterAttrs (_: pack: pack.enable && pack.packType == "${type}_packs") cfg.packs; + jsonName = "world_${type}_packs.json"; + packsJson = mapAttrsToList (_: pack: pack.settings) enabledPacks; + packsJsonPath = pkgs.writeText jsonName (toJSON packsJson); + in mkIf (enabledPacks != { }) [ + "${packsJsonPath}:${cfg.dataDir}/worlds/${cfg.serverProperties.level-name}/${jsonName}" + ]; + mapWorldPacks = packs: let + enabledPacks = filterAttrs (_: pack: pack.enable && pack.package != null) packs; + mapPackPath = _: pack: let + subDir = "${pack.packType}/${pack.packDir}"; + in "${pack.package}/${cfg.package.dataDir}/${subDir}:${cfg.dataDir}/${subDir}"; + in mapAttrsToList mapPackPath enabledPacks; + packsPaths = mkMerge [ + (mkWorldPacks "behavior") + (mkWorldPacks "resource") + (mapWorldPacks cfg.packs) + ]; in mkMerge [ packageResources - (mkIf (cfg.allowList != null) "${cfg.allowList}:${cfg.dataDir}/allowlist.json") + (mkIf (cfg.allowList != null) [ "${cfg.allowList}:${cfg.dataDir}/allowlist.json" ]) + (mkIf (cfg.packs != { }) packsPaths) ]; ExecStart = [ - "${cfg.package}/bin/bedrock_server" + "${getExe cfg.package}" ]; Restart = "always"; User = cfg.user; @@ -219,7 +304,7 @@ in { preStart = '' mkdir -p behavior_packs - ln -sf ${cfg.package}/var/lib/behavior_packs/* behavior_packs/ + ln -sf ${cfg.package}/var/lib/minecraft-bedrock/behavior_packs/* behavior_packs/ cp -f ${serverPropertiesFile} server.properties chmod +w server.properties ''; diff --git a/nixos/minecraft/bedrock.nix b/nixos/minecraft/bedrock.nix index 12adc1c2..8f9c4f58 100644 --- a/nixos/minecraft/bedrock.nix +++ b/nixos/minecraft/bedrock.nix @@ -1,4 +1,4 @@ -{config, lib, ...}: let +{config, lib, pkgs, ...}: let inherit (lib.modules) mkIf mkDefault; cfg = config.services.minecraft-bedrock-server; in { @@ -9,6 +9,14 @@ in { online-mode = true; level-name = "KatBedrock"; }; + packs = let + addons = pkgs.minecraft-bedrock-addons; + in { + #tree-capitator-bp.package = addons.true-tree-capitator-bp; + #tree-capitator-rp.package = addons.true-tree-capitator-rp; + #tree-capitator-bh.package = addons.definitive-tree-capitator-bh; + #tree-capitator-rs.package = addons.definitive-tree-capitator-rs; + }; allowPlayers = let base = 2535460000000000; in { @@ -17,6 +25,7 @@ in { }; }; systemd.services.minecraft-bedrock-server = mkIf cfg.enable { + confinement.enable = true; gensokyo-zone.sharedMounts."minecraft/bedrock" = {config, ...}: { root = config.rootDir + "/${config.subpath}"; path = mkDefault cfg.dataDir; diff --git a/overlays/minecraft.nix b/overlays/minecraft.nix index 30596673..6e86082c 100644 --- a/overlays/minecraft.nix +++ b/overlays/minecraft.nix @@ -54,4 +54,115 @@ in { }); minecraft-bedrock-server = final.callPackage ../packages/minecraft-bedrock.nix { }; + + unzipMcpack = let + f = { stdenvNoCC, unzip, writeText }: stdenvNoCC.mkDerivation { + name = "unzip-mcpack"; + propagatedBuildInputs = [ unzip ]; + dontUnpack = true; + setupHook = writeText "mcpack-setup-hook.sh" '' + unpackCmdHooks+=(_tryUnzipMcpack) + _tryUnzipMcpack() { + if ! [[ "$curSrc" =~ \.mcpack$ ]]; then return 1; fi + + LANG=en_US.UTF-8 unzip -qq "$curSrc" + } + ''; + }; + in final.callPackage f { }; + mkMinecraftBedrockServerAddon = let + argNames = [ "mcpackModules" "mcpackVersion" "mcpackId" ]; + f = { stdenvNoCC, unzipMcpack, minecraft-bedrock-server, lib }: { + src, + pname, + version, + mcpackVersion ? version, + mcVersion ? null, + mcpackId, + mcpackModules ? [ ], + mcpackDir ? pname, + mcpackType ? "behavior_packs", + ... + }@args: let + inherit (lib.strings) optionalString splitString; + inherit (minecraft-bedrock-server) dataDir; + in stdenvNoCC.mkDerivation (removeAttrs args argNames // { + inherit dataDir mcpackType mcpackDir; + version = version + optionalString (mcVersion != null) "-${mcVersion}"; + nativeBuildInputs = args.nativeBuildInputs or [ ] ++ [ + unzipMcpack + ]; + installPhase = args.installPhase or '' + install -d "$out$dataDir/$mcpackType/$mcpackDir" + cp -a ./* "$out$dataDir/$mcpackType/$mcpackDir/" + + install ./manifest.json $manifest + ''; + outputs = [ "out" "manifest" ]; + passthru = args.passthru or { } // { + minecraft-bedrock = args.passthru.minecraft-bedrock or { } // { + pack = args.passthru.minecraft-bedrock.pack or { } // { + pack_id = mcpackId; + modules = mcpackModules; + version = splitString "." mcpackVersion; + type = mcpackType; + dir = mcpackDir; + subPath = "${dataDir}/${mcpackType}/${mcpackDir}"; + }; + }; + }; + }); + in final.callPackage f { }; + + minecraft-bedrock-addons = { + definitive-tree-capitator-bh = final.mkMinecraftBedrockServerAddon { + pname = "definitive-tree-capitator-bh"; + version = "1.0.0"; + mcpackId = "b3538a6c-3e42-400a-9ed0-5ec1670b796c"; + mcpackVersion = "1.0.0"; + mcVersion = "1.20.20"; + src = final.fetchurl { + url = "https://mediafilez.forgecdn.net/files/5214/136/Definitive%20Tree%20Capitator%20BH.mcpack"; + sha256 = "941564d65386fd2701dfe017408d8c1d5b6d6a90a017e60b7ef9f6ff6de7b51a"; + }; + }; + definitive-tree-capitator-rs = final.mkMinecraftBedrockServerAddon { + pname = "definitive-tree-capitator-rs"; + version = "1.0.0"; + mcpackId = "e01dd561-a1d9-45d0-b6ad-cd3858b93fe7"; + mcpackVersion = "1.0.0"; + mcVersion = "1.13.0"; + src = final.fetchurl { + url = "https://mediafilez.forgecdn.net/files/5214/134/Definitive%20Tree%20Capitator%20RS.mcpack"; + sha256 = "22c8ff1c85720052d9f2a0af1c205b5457a9bb806d65125cff3751fdbe22b864"; + }; + }; + true-tree-capitator-bp = final.mkMinecraftBedrockServerAddon { + pname = "true-tree-capitator-bp"; + version = "1.2"; + mcpackVersion = "1.0.0"; + mcpackId = "4d0f6078-f2f9-415f-9848-b36b008127b4"; + mcVersion = "1.20.71"; + src = final.fetchurl { + name = "Tree-capitator-BP-v1.2.mcpack"; + url = "https://mediafilez.forgecdn.net/files/5237/589/Tree%20capitator%20%5BBP%5D%20v1.2.mcpack"; + sha256 = "c4b702be4dd45707b66ef3cfda578695347caa6a43ead30c06dc17cd14a00040"; + }; + sourceRoot = "."; + }; + true-tree-capitator-rp = final.mkMinecraftBedrockServerAddon { + pname = "true-tree-capitator-rp"; + version = "1.2"; + mcpackVersion = "1.0.0"; + mcpackId = "811af5f4-929b-4d77-aed4-119486b6c0a0"; + mcVersion = "1.20.71"; + mcpackType = "resource_packs"; + src = final.fetchurl { + name = "Tree-capitator-RP-v1.2.mcpack"; + url = "https://mediafilez.forgecdn.net/files/5237/590/Tree%20capitator%20%5BRP%5D%20v1.2.mcpack"; + sha256 = "66c850106c7fa1764b32f20c555c1bb5e7e6905f3cbea4b429ca076e7a4cc31f"; + }; + sourceRoot = "."; + }; + }; } diff --git a/packages/minecraft-bedrock.nix b/packages/minecraft-bedrock.nix index 6315d58b..52c07b74 100644 --- a/packages/minecraft-bedrock.nix +++ b/packages/minecraft-bedrock.nix @@ -5,7 +5,10 @@ #, minecraft-bedrock-server-libCrypto , autoPatchelfHook , curl, gcc-unwrapped, openssl, unzip -}: stdenv.mkDerivation rec { +, lib +}: let + inherit (lib) licenses; +in stdenv.mkDerivation rec { pname = "minecraft-bedrock-server"; version = "1.20.80.05"; src = fetchurl { @@ -26,15 +29,20 @@ buildPhase = '' minecraft-bedrock-server-patchdebug bedrock_server_symbols.debug bedrock_server_symbols_patched.debug ''; + dataDir = "/var/lib/minecraft-bedrock"; installPhase = '' install -m755 -D bedrock_server $out/bin/bedrock_server - rm bedrock_server - rm server.properties - mkdir -p $out/var - cp -a . $out/var/lib + install -d $out$dataDir + cp -a definitions behavior_packs resource_packs config env-vars *.json *.debug *.properties $out$dataDir/ ''; fixupPhase = '' autoPatchelf $out/bin/bedrock_server ''; dontStrip = true; + + meta = { + platforms = [ "x86_64-linux" ]; + license = licenses.unfree; + mainProgram = "bedrock_server"; + }; }