From 1ae4d1686bc13c47898d3353cb8999cb22e02c10 Mon Sep 17 00:00:00 2001 From: Merith Date: Sun, 22 Jun 2025 12:44:17 -0700 Subject: [PATCH 1/5] Magefile initial conversion --- go.mod | 5 +++++ go.sum | 2 ++ magefile.go | 54 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 61 insertions(+) create mode 100644 go.mod create mode 100644 go.sum create mode 100644 magefile.go diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..fe9a557 --- /dev/null +++ b/go.mod @@ -0,0 +1,5 @@ +module DigitalStorageTweaks + +go 1.24.3 + +require github.com/magefile/mage v1.15.0 diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..4ee1b87 --- /dev/null +++ b/go.sum @@ -0,0 +1,2 @@ +github.com/magefile/mage v1.15.0 h1:BvGheCMAsG3bWUDbZ8AyXXpCNwU9u5CB6sM+HNb9HYg= +github.com/magefile/mage v1.15.0/go.mod h1:z5UZb/iS3GoOSn0JgWuiw7dxlurVYTu+/jHXqQg881A= diff --git a/magefile.go b/magefile.go new file mode 100644 index 0000000..5e7e11a --- /dev/null +++ b/magefile.go @@ -0,0 +1,54 @@ +//go:build mage +// +build mage + +package main + +import ( + "fmt" + "os" + + "github.com/magefile/mage/mg" + "github.com/magefile/mage/sh" +) + +const ( + zipName = "DigitalStorageTweaks.zip" + filesToCopy = "./ContentLib ./DigitalStorageTweaks.uplugin" + targetDirs = "Windows WindowsServer LinuxServer" +) + +// Default target to run when none is specified +var Default = Package + +// Package creates the distribution zip file +func Package() error { + mg.Deps(Clean) + + fmt.Println("Creating target directories...") + for _, dir := range []string{"Windows", "WindowsServer", "LinuxServer"} { + if err := os.MkdirAll(dir, 0755); err != nil { + return fmt.Errorf("failed to create directory %s: %v", dir, err) + } + + fmt.Printf("Copying files to %s...\n", dir) + if err := sh.Run("cp", "-r", "./ContentLib", "./DigitalStorageTweaks.uplugin", dir+"/"); err != nil { + return fmt.Errorf("failed to copy files to %s: %v", dir, err) + } + } + + fmt.Println("Creating zip archive...") + return sh.Run("7z", "a", "-r", zipName, "Windows/", "LinuxServer/", "WindowsServer/") +} + +// Clean removes generated directories and zip file +func Clean() error { + fmt.Println("Cleaning up...") + toRemove := []string{"Windows", "WindowsServer", "LinuxServer", zipName} + + for _, path := range toRemove { + if err := os.RemoveAll(path); err != nil { + return fmt.Errorf("failed to remove %s: %v", path, err) + } + } + return nil +} From 90503f86b125b028d9eb5c2ab9bdcc0d42fd73f5 Mon Sep 17 00:00:00 2001 From: Merith Date: Sun, 22 Jun 2025 12:52:24 -0700 Subject: [PATCH 2/5] sanitizer --- magefile.go | 102 ++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 88 insertions(+), 14 deletions(-) diff --git a/magefile.go b/magefile.go index 5e7e11a..441c227 100644 --- a/magefile.go +++ b/magefile.go @@ -4,25 +4,30 @@ package main import ( + "bytes" "fmt" + "io/ioutil" "os" + "path/filepath" + "unicode" "github.com/magefile/mage/mg" "github.com/magefile/mage/sh" ) const ( - zipName = "DigitalStorageTweaks.zip" - filesToCopy = "./ContentLib ./DigitalStorageTweaks.uplugin" - targetDirs = "Windows WindowsServer LinuxServer" + zipName = "DigitalStorageTweaks.zip" + contentDir = "./ContentLib" + pluginFile = "./DigitalStorageTweaks.uplugin" + targetDirs = "Windows WindowsServer LinuxServer" ) -// Default target to run when none is specified var Default = Package // Package creates the distribution zip file func Package() error { - mg.Deps(Clean) + mg.Deps(SanitizeContent) + defer Clean(false) // Clean temp dirs but keep zip fmt.Println("Creating target directories...") for _, dir := range []string{"Windows", "WindowsServer", "LinuxServer"} { @@ -31,7 +36,7 @@ func Package() error { } fmt.Printf("Copying files to %s...\n", dir) - if err := sh.Run("cp", "-r", "./ContentLib", "./DigitalStorageTweaks.uplugin", dir+"/"); err != nil { + if err := sh.Run("cp", "-r", contentDir, pluginFile, dir+"/"); err != nil { return fmt.Errorf("failed to copy files to %s: %v", dir, err) } } @@ -40,15 +45,84 @@ func Package() error { return sh.Run("7z", "a", "-r", zipName, "Windows/", "LinuxServer/", "WindowsServer/") } -// Clean removes generated directories and zip file -func Clean() error { - fmt.Println("Cleaning up...") - toRemove := []string{"Windows", "WindowsServer", "LinuxServer", zipName} - - for _, path := range toRemove { - if err := os.RemoveAll(path); err != nil { - return fmt.Errorf("failed to remove %s: %v", path, err) +// Clean removes generated artifacts +func Clean(includeZip bool) error { + fmt.Println("Cleaning artifacts...") + paths := []string{"Windows", "WindowsServer", "LinuxServer"} + if includeZip { + paths = append(paths, zipName) + } + for _, path := range paths { + if err := sh.Rm(path); err != nil { + return err } } return nil } + +// SanitizeContent cleans all text files of non-ASCII and ensures CRLF line endings +func SanitizeContent() error { + fmt.Println("Sanitizing content files...") + + // Process plugin file + if err := sanitizeFile(pluginFile); err != nil { + return fmt.Errorf("plugin file sanitization failed: %v", err) + } + + // Process content directory + return filepath.Walk(contentDir, func(path string, info os.FileInfo, err error) error { + if err != nil || info.IsDir() { + return err + } + + // Skip binary files + switch filepath.Ext(path) { + case ".png", ".jpg", ".jpeg", ".bmp", ".gif", ".dds", ".tga", ".psd", ".fbx", ".uasset", ".umap": + return nil + default: + return sanitizeFile(path) + } + }) +} + +func sanitizeFile(path string) error { + content, err := ioutil.ReadFile(path) + if err != nil { + return fmt.Errorf("failed to read %s: %v", path, err) + } + + // First fix any encoding issues by converting to valid UTF-8 + content = bytes.ToValidUTF8(content, []byte{}) + + // Remove non-ASCII characters but preserve standard whitespace + cleanContent := bytes.Map(func(r rune) rune { + switch { + case r > unicode.MaxASCII: + return -1 // Remove non-ASCII + case r == '\t', r == '\n', r == '\r': + return r // Keep standard whitespace + case r < 32 || r == 127: + return -1 // Remove control characters + default: + return r // Keep regular ASCII + } + }, content) + + // Normalize line endings to CRLF + cleanContent = bytes.ReplaceAll(cleanContent, []byte("\r\n"), []byte("\n")) + cleanContent = bytes.ReplaceAll(cleanContent, []byte("\n"), []byte("\r\n")) + + // Only write back if changes were made + if !bytes.Equal(content, cleanContent) { + fmt.Printf("Sanitizing %s\n", path) + fileInfo, err := os.Stat(path) + if err != nil { + return fmt.Errorf("failed to get file info for %s: %v", path, err) + } + if err := ioutil.WriteFile(path, cleanContent, fileInfo.Mode()); err != nil { + return fmt.Errorf("failed to write %s: %v", path, err) + } + } + + return nil +} From 42fc32511e5a54f2da1538f633dbdafbdd523839 Mon Sep 17 00:00:00 2001 From: Merith Date: Sun, 22 Jun 2025 13:16:39 -0700 Subject: [PATCH 3/5] redo magefile --- go.mod | 12 +++- go.sum | 13 +++++ magefile.go | 154 ++++++++++++++++++++++++++-------------------------- 3 files changed, 99 insertions(+), 80 deletions(-) diff --git a/go.mod b/go.mod index fe9a557..c6c8524 100644 --- a/go.mod +++ b/go.mod @@ -1,5 +1,13 @@ -module DigitalStorageTweaks +module local go 1.24.3 -require github.com/magefile/mage v1.15.0 +require ( + github.com/magefile/mage v1.15.0 + github.com/xeipuuv/gojsonschema v1.2.0 +) + +require ( + github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f // indirect + github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect +) diff --git a/go.sum b/go.sum index 4ee1b87..5d71808 100644 --- a/go.sum +++ b/go.sum @@ -1,2 +1,15 @@ +github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/magefile/mage v1.15.0 h1:BvGheCMAsG3bWUDbZ8AyXXpCNwU9u5CB6sM+HNb9HYg= github.com/magefile/mage v1.15.0/go.mod h1:z5UZb/iS3GoOSn0JgWuiw7dxlurVYTu+/jHXqQg881A= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f h1:J9EGpcZtP0E/raorCMxlFGSTBrsSlaDGf3jU/qvAE2c= +github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= +github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0= +github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= +github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= +github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= diff --git a/magefile.go b/magefile.go index 441c227..e8e7721 100644 --- a/magefile.go +++ b/magefile.go @@ -4,125 +4,123 @@ package main import ( - "bytes" "fmt" "io/ioutil" "os" "path/filepath" "unicode" + "unicode/utf8" "github.com/magefile/mage/mg" "github.com/magefile/mage/sh" + "github.com/xeipuuv/gojsonschema" ) const ( zipName = "DigitalStorageTweaks.zip" contentDir = "./ContentLib" pluginFile = "./DigitalStorageTweaks.uplugin" - targetDirs = "Windows WindowsServer LinuxServer" ) -var Default = Package +// Default target +var Default = Build -// Package creates the distribution zip file +// Build runs the full pipeline +func Build() { + mg.SerialDeps(Validate, Package) +} + +// Package creates the distribution zip func Package() error { - mg.Deps(SanitizeContent) - defer Clean(false) // Clean temp dirs but keep zip + fmt.Println("Packaging files...") - fmt.Println("Creating target directories...") + // Create target directories for _, dir := range []string{"Windows", "WindowsServer", "LinuxServer"} { if err := os.MkdirAll(dir, 0755); err != nil { - return fmt.Errorf("failed to create directory %s: %v", dir, err) + return fmt.Errorf("creating %s: %w", dir, err) } - - fmt.Printf("Copying files to %s...\n", dir) if err := sh.Run("cp", "-r", contentDir, pluginFile, dir+"/"); err != nil { - return fmt.Errorf("failed to copy files to %s: %v", dir, err) + return fmt.Errorf("copying to %s: %w", dir, err) } } - fmt.Println("Creating zip archive...") - return sh.Run("7z", "a", "-r", zipName, "Windows/", "LinuxServer/", "WindowsServer/") + // Create zip + if err := sh.Run("7z", "a", "-r", zipName, "Windows/", "LinuxServer/", "WindowsServer/"); err != nil { + return fmt.Errorf("creating zip: %w", err) + } + + // Clean temp dirs + return Clean("Windows", "WindowsServer", "LinuxServer") } -// Clean removes generated artifacts -func Clean(includeZip bool) error { - fmt.Println("Cleaning artifacts...") - paths := []string{"Windows", "WindowsServer", "LinuxServer"} - if includeZip { - paths = append(paths, zipName) - } - for _, path := range paths { - if err := sh.Rm(path); err != nil { - return err - } - } - return nil -} +// Validate checks all content files +func Validate() error { + fmt.Println("Validating files...") -// SanitizeContent cleans all text files of non-ASCII and ensures CRLF line endings -func SanitizeContent() error { - fmt.Println("Sanitizing content files...") - - // Process plugin file - if err := sanitizeFile(pluginFile); err != nil { - return fmt.Errorf("plugin file sanitization failed: %v", err) + // Check plugin file + if err := checkFile(pluginFile); err != nil { + return fmt.Errorf("plugin file: %w", err) } - // Process content directory + // Check content directory return filepath.Walk(contentDir, func(path string, info os.FileInfo, err error) error { if err != nil || info.IsDir() { return err } - - // Skip binary files - switch filepath.Ext(path) { - case ".png", ".jpg", ".jpeg", ".bmp", ".gif", ".dds", ".tga", ".psd", ".fbx", ".uasset", ".umap": - return nil - default: - return sanitizeFile(path) - } + return checkFile(path) }) } -func sanitizeFile(path string) error { - content, err := ioutil.ReadFile(path) +func checkFile(path string) error { + // Skip binary files + switch filepath.Ext(path) { + case ".png", ".jpg", ".jpeg", ".bmp", ".gif", ".dds", ".tga", ".psd", ".fbx", ".uasset", ".umap": + return nil + case ".json": + return validateJSON(path) + default: + return validateEncoding(path) + } +} + +func validateJSON(path string) error { + schemaLoader := gojsonschema.NewReferenceLoader("https://raw.githubusercontent.com/budak7273/ContentLib_Documentation/main/JsonSchemas/CL_Recipe.json") + documentLoader := gojsonschema.NewReferenceLoader("file:///" + filepath.ToSlash(path)) + + result, err := gojsonschema.Validate(schemaLoader, documentLoader) if err != nil { - return fmt.Errorf("failed to read %s: %v", path, err) + return fmt.Errorf("schema validation failed: %w", err) } - // First fix any encoding issues by converting to valid UTF-8 - content = bytes.ToValidUTF8(content, []byte{}) - - // Remove non-ASCII characters but preserve standard whitespace - cleanContent := bytes.Map(func(r rune) rune { - switch { - case r > unicode.MaxASCII: - return -1 // Remove non-ASCII - case r == '\t', r == '\n', r == '\r': - return r // Keep standard whitespace - case r < 32 || r == 127: - return -1 // Remove control characters - default: - return r // Keep regular ASCII - } - }, content) - - // Normalize line endings to CRLF - cleanContent = bytes.ReplaceAll(cleanContent, []byte("\r\n"), []byte("\n")) - cleanContent = bytes.ReplaceAll(cleanContent, []byte("\n"), []byte("\r\n")) - - // Only write back if changes were made - if !bytes.Equal(content, cleanContent) { - fmt.Printf("Sanitizing %s\n", path) - fileInfo, err := os.Stat(path) - if err != nil { - return fmt.Errorf("failed to get file info for %s: %v", path, err) - } - if err := ioutil.WriteFile(path, cleanContent, fileInfo.Mode()); err != nil { - return fmt.Errorf("failed to write %s: %v", path, err) - } + if !result.Valid() { + return fmt.Errorf("invalid JSON schema: %v", result.Errors()) + } + return nil +} + +func validateEncoding(path string) error { + content, err := ioutil.ReadFile(path) + if err != nil { + return err + } + + // Check for non-ASCII + for i := 0; i < len(content); i++ { + if content[i] > unicode.MaxASCII { + r, _ := utf8.DecodeRune(content[i:]) + return fmt.Errorf("non-ASCII character %U at position %d", r, i) + } + } + return nil +} + +// Clean removes all build artifacts +func Clean(list ...string) error { + fmt.Println("Cleaning up...") + for _, f := range list { + if err := os.RemoveAll(f); err != nil { + return fmt.Errorf("failed to remove %s: %w", f, err) + } } - return nil } From 0eb645d26444833d1e5a0432776ddec12a6b5a35 Mon Sep 17 00:00:00 2001 From: Merith Date: Sun, 22 Jun 2025 14:10:06 -0700 Subject: [PATCH 4/5] trim comment at beginning of files --- .../Buildables/Recipe_DS_AtomicCrafter.json | 1 - .../Recipe_DS_CentralStorageAdapter.json | 1 - .../Buildables/Recipe_DS_CraftingAdapter.json | 1 - .../Buildables/Recipe_DS_CraftingServer.json | 1 - .../Recipe_DS_CraftingTerminal.json | 1 - .../Recipe_DS_DoubleNetworkPlug.json | 1 - .../Buildables/Recipe_DS_DriveTerminal.json | 1 - .../Recipe_DS_FactoryConnectionAdapter.json | 1 - .../Recipe_DS_FluidConnectionAdapter.json | 1 - .../Buildables/Recipe_DS_NetworkCable.json | 1 - .../Recipe_DS_NetworkDistributor.json | 1 - .../Buildables/Recipe_DS_NetworkPlug.json | 1 - .../Buildables/Recipe_DS_NetworkPole.json | 1 - .../Recipe_DS_NetworkPowerAdapater.json | 1 - .../Buildables/Recipe_DS_ResourceAdapter.json | 1 - .../Buildables/Recipe_DS_ServerRack.json | 1 - .../Buildables/Recipe_DS_Server_1U.json | 1 - .../Buildables/Recipe_DS_Server_1UF.json | 1 - .../Buildables/Recipe_DS_Server_2U.json | 1 - .../Buildables/Recipe_DS_Server_2UF.json | 1 - .../Buildables/Recipe_DS_Server_2UG.json | 1 - .../Recipe_DS_StorageConnectionAdapter.json | 1 - .../Buildables/Recipe_DS_StorageTerminal.json | 1 - .../Recipe_DS_TrainCargoAdapter.json | 1 - .../Recipe_DS_UniversalAdapter.json | 1 - .../Buildables/Recipe_DS_UplinkSatellite.json | 1 - .../Recipe_DS_WirelessAccessPoint.json | 1 - .../Buildables/Recipe_DS_WirelessTower.json | 1 - .../Recipe_DS_Drive_10K_Fluid.json | Bin 2328 -> 2130 bytes .../Recipe_DS_Drive_120K_Fluid.json | Bin 2826 -> 2622 bytes .../Recipe_DS_Drive_120K_Gas.json | Bin 2802 -> 2610 bytes .../RecipePatches/Recipe_DS_Drive_16K.json | 1 - .../RecipePatches/Recipe_DS_Drive_1K.json | 1 - .../Recipe_DS_Drive_20K_Fluid.json | Bin 2370 -> 2172 bytes .../Recipe_DS_Drive_240K_Fluid.json | Bin 3052 -> 2848 bytes .../Recipe_DS_Drive_240K_Gas.json | Bin 3028 -> 2836 bytes .../RecipePatches/Recipe_DS_Drive_256.json | 1 - .../RecipePatches/Recipe_DS_Drive_2K.json | 1 - .../RecipePatches/Recipe_DS_Drive_32K.json | 1 - .../Recipe_DS_Drive_40K_Fluid.json | Bin 2368 -> 2170 bytes .../Recipe_DS_Drive_40K_Gas.json | Bin 2348 -> 2162 bytes .../RecipePatches/Recipe_DS_Drive_4K.json | 1 - .../RecipePatches/Recipe_DS_Drive_512.json | 1 - .../Recipe_DS_Drive_60K_Fluid.json | Bin 2368 -> 2170 bytes .../Recipe_DS_Drive_60K_Gas.json | Bin 2344 -> 2158 bytes .../RecipePatches/Recipe_DS_Drive_64K.json | 1 - .../RecipePatches/Recipe_DS_Drive_8K.json | 1 - .../RecipePatches/Recipe_DS_Multitool.json | 1 - .../Recipe_DS_NetworkCable_Item.json | 1 - .../Recipe_DS_WirelessExtender.json | 1 - .../Recipe_DS_WirelessTablet.json | 1 - 51 files changed, 41 deletions(-) diff --git a/ContentLib/RecipePatches/Buildables/Recipe_DS_AtomicCrafter.json b/ContentLib/RecipePatches/Buildables/Recipe_DS_AtomicCrafter.json index d7a9a6b..3623131 100644 --- a/ContentLib/RecipePatches/Buildables/Recipe_DS_AtomicCrafter.json +++ b/ContentLib/RecipePatches/Buildables/Recipe_DS_AtomicCrafter.json @@ -1,4 +1,3 @@ -//DigitalStorage/Buildables/AtomicCrafter/Recipe_DS_AtomicCrafter.Recipe_DS_AtomicCrafter_C { "$schema": "https://raw.githubusercontent.com/budak7273/ContentLib_Documentation/refs/heads/main/JsonSchemas/CL_Recipe.json", "Name": "Atomic Crafter", diff --git a/ContentLib/RecipePatches/Buildables/Recipe_DS_CentralStorageAdapter.json b/ContentLib/RecipePatches/Buildables/Recipe_DS_CentralStorageAdapter.json index 56efdcc..6b678c5 100644 --- a/ContentLib/RecipePatches/Buildables/Recipe_DS_CentralStorageAdapter.json +++ b/ContentLib/RecipePatches/Buildables/Recipe_DS_CentralStorageAdapter.json @@ -1,4 +1,3 @@ -//DigitalStorage/Buildables/CentralStorageAdapter/Recipe_DS_CentralStorageAdapter.Recipe_DS_CentralStorageAdapter_C { "$schema": "https://raw.githubusercontent.com/budak7273/ContentLib_Documentation/refs/heads/main/JsonSchemas/CL_Recipe.json", "Name": "Depot Uploader Adapter", diff --git a/ContentLib/RecipePatches/Buildables/Recipe_DS_CraftingAdapter.json b/ContentLib/RecipePatches/Buildables/Recipe_DS_CraftingAdapter.json index 01bddd7..6f980c4 100644 --- a/ContentLib/RecipePatches/Buildables/Recipe_DS_CraftingAdapter.json +++ b/ContentLib/RecipePatches/Buildables/Recipe_DS_CraftingAdapter.json @@ -1,4 +1,3 @@ -//DigitalStorage/Buildables/CraftingAdapter/Recipe_DS_CraftingAdapter.Recipe_DS_CraftingAdapter_C { "$schema": "https://raw.githubusercontent.com/budak7273/ContentLib_Documentation/refs/heads/main/JsonSchemas/CL_Recipe.json", "Name": "Crafting Connection Adapter", diff --git a/ContentLib/RecipePatches/Buildables/Recipe_DS_CraftingServer.json b/ContentLib/RecipePatches/Buildables/Recipe_DS_CraftingServer.json index 4c4fb7f..f4ea898 100644 --- a/ContentLib/RecipePatches/Buildables/Recipe_DS_CraftingServer.json +++ b/ContentLib/RecipePatches/Buildables/Recipe_DS_CraftingServer.json @@ -1,4 +1,3 @@ -//DigitalStorage/Buildables/CraftingServer/Recipe_DS_CraftingServer.Recipe_DS_CraftingServer_C { "$schema": "https://raw.githubusercontent.com/budak7273/ContentLib_Documentation/refs/heads/main/JsonSchemas/CL_Recipe.json", "Name": "Crafting Server", diff --git a/ContentLib/RecipePatches/Buildables/Recipe_DS_CraftingTerminal.json b/ContentLib/RecipePatches/Buildables/Recipe_DS_CraftingTerminal.json index c4b952a..83da95c 100644 --- a/ContentLib/RecipePatches/Buildables/Recipe_DS_CraftingTerminal.json +++ b/ContentLib/RecipePatches/Buildables/Recipe_DS_CraftingTerminal.json @@ -1,4 +1,3 @@ -//DigitalStorage/Buildables/Terminals/Crafting/Recipe_DS_CraftingTerminal.Recipe_DS_CraftingTerminal_C { "$schema": "https://raw.githubusercontent.com/budak7273/ContentLib_Documentation/refs/heads/main/JsonSchemas/CL_Recipe.json", "Name": "Crafting Terminal", diff --git a/ContentLib/RecipePatches/Buildables/Recipe_DS_DoubleNetworkPlug.json b/ContentLib/RecipePatches/Buildables/Recipe_DS_DoubleNetworkPlug.json index 4c3db94..5712dc3 100644 --- a/ContentLib/RecipePatches/Buildables/Recipe_DS_DoubleNetworkPlug.json +++ b/ContentLib/RecipePatches/Buildables/Recipe_DS_DoubleNetworkPlug.json @@ -1,4 +1,3 @@ -//DigitalStorage/Buildables/NetworkPlug/Recipe_DS_DoubleNetworkPlug.Recipe_DS_DoubleNetworkPlug_C { "$schema": "https://raw.githubusercontent.com/budak7273/ContentLib_Documentation/refs/heads/main/JsonSchemas/CL_Recipe.json", "Name": "Double Network Wall Outlet", diff --git a/ContentLib/RecipePatches/Buildables/Recipe_DS_DriveTerminal.json b/ContentLib/RecipePatches/Buildables/Recipe_DS_DriveTerminal.json index f4b9f4b..fca31a5 100644 --- a/ContentLib/RecipePatches/Buildables/Recipe_DS_DriveTerminal.json +++ b/ContentLib/RecipePatches/Buildables/Recipe_DS_DriveTerminal.json @@ -1,4 +1,3 @@ -//DigitalStorage/Buildables/Terminals/Drive/Recipe_DS_DriveTerminal.Recipe_DS_DriveTerminal_C { "$schema": "https://raw.githubusercontent.com/budak7273/ContentLib_Documentation/refs/heads/main/JsonSchemas/CL_Recipe.json", "Name": "Drive Terminal", diff --git a/ContentLib/RecipePatches/Buildables/Recipe_DS_FactoryConnectionAdapter.json b/ContentLib/RecipePatches/Buildables/Recipe_DS_FactoryConnectionAdapter.json index 53379cf..9d767ed 100644 --- a/ContentLib/RecipePatches/Buildables/Recipe_DS_FactoryConnectionAdapter.json +++ b/ContentLib/RecipePatches/Buildables/Recipe_DS_FactoryConnectionAdapter.json @@ -1,4 +1,3 @@ -//DigitalStorage/Buildables/FactoryModule/Recipe_DS_FactoryConnectionAdapter.Recipe_DS_FactoryConnectionAdapter_C { "$schema": "https://raw.githubusercontent.com/budak7273/ContentLib_Documentation/refs/heads/main/JsonSchemas/CL_Recipe.json", "Name": "Factory Connection Adapter", diff --git a/ContentLib/RecipePatches/Buildables/Recipe_DS_FluidConnectionAdapter.json b/ContentLib/RecipePatches/Buildables/Recipe_DS_FluidConnectionAdapter.json index 9851111..fc448df 100644 --- a/ContentLib/RecipePatches/Buildables/Recipe_DS_FluidConnectionAdapter.json +++ b/ContentLib/RecipePatches/Buildables/Recipe_DS_FluidConnectionAdapter.json @@ -1,4 +1,3 @@ -//DigitalStorage/Buildables/ContainerModules/Normal/Recipe_DS_FluidConnectionAdapter.Recipe_DS_FluidConnectionAdapter_C { "$schema": "https://raw.githubusercontent.com/budak7273/ContentLib_Documentation/refs/heads/main/JsonSchemas/CL_Recipe.json", "Name": "Pipe Connection Adapter", diff --git a/ContentLib/RecipePatches/Buildables/Recipe_DS_NetworkCable.json b/ContentLib/RecipePatches/Buildables/Recipe_DS_NetworkCable.json index abb1734..d790edd 100644 --- a/ContentLib/RecipePatches/Buildables/Recipe_DS_NetworkCable.json +++ b/ContentLib/RecipePatches/Buildables/Recipe_DS_NetworkCable.json @@ -1,4 +1,3 @@ -//DigitalStorage/Buildables/NetworkCable/Recipe_DS_NetworkCable.Recipe_DS_NetworkCable_C { "$schema": "https://raw.githubusercontent.com/budak7273/ContentLib_Documentation/refs/heads/main/JsonSchemas/CL_Recipe.json", "Name": "Network Cable", diff --git a/ContentLib/RecipePatches/Buildables/Recipe_DS_NetworkDistributor.json b/ContentLib/RecipePatches/Buildables/Recipe_DS_NetworkDistributor.json index e786d09..5ae9c53 100644 --- a/ContentLib/RecipePatches/Buildables/Recipe_DS_NetworkDistributor.json +++ b/ContentLib/RecipePatches/Buildables/Recipe_DS_NetworkDistributor.json @@ -1,4 +1,3 @@ -//DigitalStorage/Buildables/NetworkDistributor/Recipe_DS_NetworkDistributor.Recipe_DS_NetworkDistributor_C { "$schema": "https://raw.githubusercontent.com/budak7273/ContentLib_Documentation/refs/heads/main/JsonSchemas/CL_Recipe.json", "Name": "Network Distributor", diff --git a/ContentLib/RecipePatches/Buildables/Recipe_DS_NetworkPlug.json b/ContentLib/RecipePatches/Buildables/Recipe_DS_NetworkPlug.json index 0d52adf..3898934 100644 --- a/ContentLib/RecipePatches/Buildables/Recipe_DS_NetworkPlug.json +++ b/ContentLib/RecipePatches/Buildables/Recipe_DS_NetworkPlug.json @@ -1,4 +1,3 @@ -//DigitalStorage/Buildables/NetworkPlug/Recipe_DS_NetworkPlug.Recipe_DS_NetworkPlug_C { "$schema": "https://raw.githubusercontent.com/budak7273/ContentLib_Documentation/refs/heads/main/JsonSchemas/CL_Recipe.json", "Name": "Network Wall Outlet", diff --git a/ContentLib/RecipePatches/Buildables/Recipe_DS_NetworkPole.json b/ContentLib/RecipePatches/Buildables/Recipe_DS_NetworkPole.json index 8571870..2db330b 100644 --- a/ContentLib/RecipePatches/Buildables/Recipe_DS_NetworkPole.json +++ b/ContentLib/RecipePatches/Buildables/Recipe_DS_NetworkPole.json @@ -1,4 +1,3 @@ -//DigitalStorage/Buildables/NetworkPole/Recipe_DS_NetworkPole.Recipe_DS_NetworkPole_C { "$schema": "https://raw.githubusercontent.com/budak7273/ContentLib_Documentation/refs/heads/main/JsonSchemas/CL_Recipe.json", "Name": "Network Pole", diff --git a/ContentLib/RecipePatches/Buildables/Recipe_DS_NetworkPowerAdapater.json b/ContentLib/RecipePatches/Buildables/Recipe_DS_NetworkPowerAdapater.json index 999e0bc..a5bd514 100644 --- a/ContentLib/RecipePatches/Buildables/Recipe_DS_NetworkPowerAdapater.json +++ b/ContentLib/RecipePatches/Buildables/Recipe_DS_NetworkPowerAdapater.json @@ -1,4 +1,3 @@ -//DigitalStorage/Buildables/NetworkPowerAdapter/Recipe_DS_NetworkPowerAdapater.Recipe_DS_NetworkPowerAdapater_C { "$schema": "https://raw.githubusercontent.com/budak7273/ContentLib_Documentation/refs/heads/main/JsonSchemas/CL_Recipe.json", "Name": "Network Power Adapter", diff --git a/ContentLib/RecipePatches/Buildables/Recipe_DS_ResourceAdapter.json b/ContentLib/RecipePatches/Buildables/Recipe_DS_ResourceAdapter.json index a0fbcf0..a3b610b 100644 --- a/ContentLib/RecipePatches/Buildables/Recipe_DS_ResourceAdapter.json +++ b/ContentLib/RecipePatches/Buildables/Recipe_DS_ResourceAdapter.json @@ -1,4 +1,3 @@ -//DigitalStorage/Buildables/ResourceAdapter/Recipe_DS_ResourceAdapter.Recipe_DS_ResourceAdapter_C { "$schema": "https://raw.githubusercontent.com/budak7273/ContentLib_Documentation/refs/heads/main/JsonSchemas/CL_Recipe.json", "Name": "Resource Adapter", diff --git a/ContentLib/RecipePatches/Buildables/Recipe_DS_ServerRack.json b/ContentLib/RecipePatches/Buildables/Recipe_DS_ServerRack.json index 08e51bb..de4a475 100644 --- a/ContentLib/RecipePatches/Buildables/Recipe_DS_ServerRack.json +++ b/ContentLib/RecipePatches/Buildables/Recipe_DS_ServerRack.json @@ -1,4 +1,3 @@ -//DigitalStorage/Buildables/ServerRack/Recipe_DS_ServerRack.Recipe_DS_ServerRack_C { "$schema": "https://raw.githubusercontent.com/budak7273/ContentLib_Documentation/refs/heads/main/JsonSchemas/CL_Recipe.json", "Name": "Server Rack", diff --git a/ContentLib/RecipePatches/Buildables/Recipe_DS_Server_1U.json b/ContentLib/RecipePatches/Buildables/Recipe_DS_Server_1U.json index 73963a0..1b1e7ac 100644 --- a/ContentLib/RecipePatches/Buildables/Recipe_DS_Server_1U.json +++ b/ContentLib/RecipePatches/Buildables/Recipe_DS_Server_1U.json @@ -1,4 +1,3 @@ -//DigitalStorage/Buildables/Server/1U/Recipe_DS_Server_1U.Recipe_DS_Server_1U_C { "$schema": "https://raw.githubusercontent.com/budak7273/ContentLib_Documentation/refs/heads/main/JsonSchemas/CL_Recipe.json", "Name": "Server 1U (Item)", diff --git a/ContentLib/RecipePatches/Buildables/Recipe_DS_Server_1UF.json b/ContentLib/RecipePatches/Buildables/Recipe_DS_Server_1UF.json index 4b195c9..916cd40 100644 --- a/ContentLib/RecipePatches/Buildables/Recipe_DS_Server_1UF.json +++ b/ContentLib/RecipePatches/Buildables/Recipe_DS_Server_1UF.json @@ -1,4 +1,3 @@ -//DigitalStorage/Buildables/Server/1UF/Recipe_DS_Server_1UF.Recipe_DS_Server_1UF_C { "$schema": "https://raw.githubusercontent.com/budak7273/ContentLib_Documentation/refs/heads/main/JsonSchemas/CL_Recipe.json", "Name": "Server 1U (Fluid)", diff --git a/ContentLib/RecipePatches/Buildables/Recipe_DS_Server_2U.json b/ContentLib/RecipePatches/Buildables/Recipe_DS_Server_2U.json index 250dff0..5d27490 100644 --- a/ContentLib/RecipePatches/Buildables/Recipe_DS_Server_2U.json +++ b/ContentLib/RecipePatches/Buildables/Recipe_DS_Server_2U.json @@ -1,4 +1,3 @@ -//DigitalStorage/Buildables/Server/2U/Recipe_DS_Server_2U.Recipe_DS_Server_2U_C { "$schema": "https://raw.githubusercontent.com/budak7273/ContentLib_Documentation/refs/heads/main/JsonSchemas/CL_Recipe.json", "Name": "Server 2U (Item)", diff --git a/ContentLib/RecipePatches/Buildables/Recipe_DS_Server_2UF.json b/ContentLib/RecipePatches/Buildables/Recipe_DS_Server_2UF.json index 3c5bd69..d6e07c4 100644 --- a/ContentLib/RecipePatches/Buildables/Recipe_DS_Server_2UF.json +++ b/ContentLib/RecipePatches/Buildables/Recipe_DS_Server_2UF.json @@ -1,4 +1,3 @@ -//DigitalStorage/Buildables/Server/2UF/Recipe_DS_Server_2UF.Recipe_DS_Server_2UF_C { "$schema": "https://raw.githubusercontent.com/budak7273/ContentLib_Documentation/refs/heads/main/JsonSchemas/CL_Recipe.json", "Name": "Server 2U (Fluid)", diff --git a/ContentLib/RecipePatches/Buildables/Recipe_DS_Server_2UG.json b/ContentLib/RecipePatches/Buildables/Recipe_DS_Server_2UG.json index 4faf894..c89630c 100644 --- a/ContentLib/RecipePatches/Buildables/Recipe_DS_Server_2UG.json +++ b/ContentLib/RecipePatches/Buildables/Recipe_DS_Server_2UG.json @@ -1,4 +1,3 @@ -//DigitalStorage/Buildables/Server/2UG/Recipe_DS_Server_2UG.Recipe_DS_Server_2UG_C { "$schema": "https://raw.githubusercontent.com/budak7273/ContentLib_Documentation/refs/heads/main/JsonSchemas/CL_Recipe.json", "Name": "Server 2U (Gas)", diff --git a/ContentLib/RecipePatches/Buildables/Recipe_DS_StorageConnectionAdapter.json b/ContentLib/RecipePatches/Buildables/Recipe_DS_StorageConnectionAdapter.json index c16da9e..f4c993a 100644 --- a/ContentLib/RecipePatches/Buildables/Recipe_DS_StorageConnectionAdapter.json +++ b/ContentLib/RecipePatches/Buildables/Recipe_DS_StorageConnectionAdapter.json @@ -1,4 +1,3 @@ -//DigitalStorage/Buildables/ContainerModules/Normal/Recipe_DS_StorageConnectionAdapter.Recipe_DS_StorageConnectionAdapter_C { "$schema": "https://raw.githubusercontent.com/budak7273/ContentLib_Documentation/refs/heads/main/JsonSchemas/CL_Recipe.json", "Name": "Storage Connection Adapter", diff --git a/ContentLib/RecipePatches/Buildables/Recipe_DS_StorageTerminal.json b/ContentLib/RecipePatches/Buildables/Recipe_DS_StorageTerminal.json index 3ac70c4..083ec81 100644 --- a/ContentLib/RecipePatches/Buildables/Recipe_DS_StorageTerminal.json +++ b/ContentLib/RecipePatches/Buildables/Recipe_DS_StorageTerminal.json @@ -1,4 +1,3 @@ -//DigitalStorage/Buildables/Terminals/Storage/Recipe_DS_StorageTerminal.Recipe_DS_StorageTerminal_C { "$schema": "https://raw.githubusercontent.com/budak7273/ContentLib_Documentation/refs/heads/main/JsonSchemas/CL_Recipe.json", "Name": "Storage Terminal", diff --git a/ContentLib/RecipePatches/Buildables/Recipe_DS_TrainCargoAdapter.json b/ContentLib/RecipePatches/Buildables/Recipe_DS_TrainCargoAdapter.json index e17e86e..59e9331 100644 --- a/ContentLib/RecipePatches/Buildables/Recipe_DS_TrainCargoAdapter.json +++ b/ContentLib/RecipePatches/Buildables/Recipe_DS_TrainCargoAdapter.json @@ -1,4 +1,3 @@ -//DigitalStorage/Buildables/TrainCargoAdapter/Recipe_DS_TrainCargoAdapter.Recipe_DS_TrainCargoAdapter_C { "$schema": "https://raw.githubusercontent.com/budak7273/ContentLib_Documentation/refs/heads/main/JsonSchemas/CL_Recipe.json", "Name": "Train Cargo Adapter", diff --git a/ContentLib/RecipePatches/Buildables/Recipe_DS_UniversalAdapter.json b/ContentLib/RecipePatches/Buildables/Recipe_DS_UniversalAdapter.json index 311d1f9..40d7fb5 100644 --- a/ContentLib/RecipePatches/Buildables/Recipe_DS_UniversalAdapter.json +++ b/ContentLib/RecipePatches/Buildables/Recipe_DS_UniversalAdapter.json @@ -1,4 +1,3 @@ -//DigitalStorage/Buildables/Adapters/UniversalAdapter/Recipe_DS_UniversalAdapter.Recipe_DS_UniversalAdapter_C { "$schema": "https://raw.githubusercontent.com/budak7273/ContentLib_Documentation/refs/heads/main/JsonSchemas/CL_Recipe.json", "Name": "Universal Adapter", diff --git a/ContentLib/RecipePatches/Buildables/Recipe_DS_UplinkSatellite.json b/ContentLib/RecipePatches/Buildables/Recipe_DS_UplinkSatellite.json index bdef7e4..36d834d 100644 --- a/ContentLib/RecipePatches/Buildables/Recipe_DS_UplinkSatellite.json +++ b/ContentLib/RecipePatches/Buildables/Recipe_DS_UplinkSatellite.json @@ -1,4 +1,3 @@ -//DigitalStorage/Buildables/UplinkSatellite/Recipe_DS_UplinkSatellite.Recipe_DS_UplinkSatellite_C { "$schema": "https://raw.githubusercontent.com/budak7273/ContentLib_Documentation/refs/heads/main/JsonSchemas/CL_Recipe.json", "Name": "Wireless Ground Antenna", diff --git a/ContentLib/RecipePatches/Buildables/Recipe_DS_WirelessAccessPoint.json b/ContentLib/RecipePatches/Buildables/Recipe_DS_WirelessAccessPoint.json index 45ee68e..047eac7 100644 --- a/ContentLib/RecipePatches/Buildables/Recipe_DS_WirelessAccessPoint.json +++ b/ContentLib/RecipePatches/Buildables/Recipe_DS_WirelessAccessPoint.json @@ -1,4 +1,3 @@ -//DigitalStorage/Buildables/WirelessAccessPoint/Recipe_DS_WirelessAccessPoint.Recipe_DS_WirelessAccessPoint_C { "$schema": "https://raw.githubusercontent.com/budak7273/ContentLib_Documentation/refs/heads/main/JsonSchemas/CL_Recipe.json", "Name": "Wireless Access Point", diff --git a/ContentLib/RecipePatches/Buildables/Recipe_DS_WirelessTower.json b/ContentLib/RecipePatches/Buildables/Recipe_DS_WirelessTower.json index 0b2a014..0e9146a 100644 --- a/ContentLib/RecipePatches/Buildables/Recipe_DS_WirelessTower.json +++ b/ContentLib/RecipePatches/Buildables/Recipe_DS_WirelessTower.json @@ -1,4 +1,3 @@ -//DigitalStorage/Buildables/WirelessTower/Recipe_DS_WirelessTower.Recipe_DS_WirelessTower_C { "$schema": "https://raw.githubusercontent.com/budak7273/ContentLib_Documentation/refs/heads/main/JsonSchemas/CL_Recipe.json", "Name": "Wireless Tower", diff --git a/ContentLib/RecipePatches/Recipe_DS_Drive_10K_Fluid.json b/ContentLib/RecipePatches/Recipe_DS_Drive_10K_Fluid.json index 68f1b6829880a9402dd70b487baad21fae13d1f4..db884dab1f4b70db638a91dc900a208e46463548 100644 GIT binary patch delta 16 YcmbOsbV-2u|G(@l;;N2RSM*%FvK$$G8iy;LvG|KG-QHe3K6(FHdE delta 154 zcmdld(j}Ju|DQgCK7$KGCPO+9moOwU3oJFAUmBQ6(}17B#VI}r9iP{FdL+! z2&ldc%5wwiDh2XW7~&ZW8H^YV7`&nSl7XTH45^dfGm1_=#VW$92R02&ls%ronSqyq NYjPp0@J10WE&yzBA-Mnm diff --git a/ContentLib/RecipePatches/Recipe_DS_Drive_120K_Gas.json b/ContentLib/RecipePatches/Recipe_DS_Drive_120K_Gas.json index 482a8d897b8a6f45172f1ecf8bdde438d381d9ad..edeb3177dfb288ade0b9c092050ed2948e8217f9 100644 GIT binary patch delta 16 Ycmew)x=Doj|G(@l;;jqTg(v8V8~#^V8GxF)sqZVQNWNoc`d6duO8SGBoX#_24@Cd2Cm74%)%Q* Gk^hbdC|G(@l;;N2RSM*%FvK$$F&Hp-Lv@l;;N2RSM*%FvK$$F_#l5 diff --git a/ContentLib/RecipePatches/Recipe_DS_Drive_240K_Gas.json b/ContentLib/RecipePatches/Recipe_DS_Drive_240K_Gas.json index ea92491524cded2fef363b0ed902ba05ad8ba86e..0a61a9f9c946a9c3bc96a826a39bec3e31125740 100644 GIT binary patch delta 16 Ycmca2K1GcA|G(@l;;jqTg(v8V8md;V8GxF)sqZVQ2b`^+W=KPc{8gj XXFP*511|#?L-pi^9KsvL{&4{Sb+IG& diff --git a/ContentLib/RecipePatches/Recipe_DS_Drive_256.json b/ContentLib/RecipePatches/Recipe_DS_Drive_256.json index 43f40e9..5dfa428 100644 --- a/ContentLib/RecipePatches/Recipe_DS_Drive_256.json +++ b/ContentLib/RecipePatches/Recipe_DS_Drive_256.json @@ -1,4 +1,3 @@ -//DigitalStorage/Resources/Drives/256/Recipe_DS_Drive_256.Recipe_DS_Drive_256_C { "$schema": "https://raw.githubusercontent.com/budak7273/ContentLib_Documentation/refs/heads/main/JsonSchemas/CL_Recipe.json", "Name": "DS Drive (256)", diff --git a/ContentLib/RecipePatches/Recipe_DS_Drive_2K.json b/ContentLib/RecipePatches/Recipe_DS_Drive_2K.json index a12cd4d..b7c7166 100644 --- a/ContentLib/RecipePatches/Recipe_DS_Drive_2K.json +++ b/ContentLib/RecipePatches/Recipe_DS_Drive_2K.json @@ -1,4 +1,3 @@ -//DigitalStorage/Resources/Drives/2K/Recipe_DS_Drive_2K.Recipe_DS_Drive_2K_C { "$schema": "https://raw.githubusercontent.com/budak7273/ContentLib_Documentation/refs/heads/main/JsonSchemas/CL_Recipe.json", "Name": "DS Drive (2K)", diff --git a/ContentLib/RecipePatches/Recipe_DS_Drive_32K.json b/ContentLib/RecipePatches/Recipe_DS_Drive_32K.json index 68d56f6..d7a235b 100644 --- a/ContentLib/RecipePatches/Recipe_DS_Drive_32K.json +++ b/ContentLib/RecipePatches/Recipe_DS_Drive_32K.json @@ -1,4 +1,3 @@ -//DigitalStorage/Resources/Drives/32K/Recipe_DS_Drive_32K.Recipe_DS_Drive_32K_C { "$schema": "https://raw.githubusercontent.com/budak7273/ContentLib_Documentation/refs/heads/main/JsonSchemas/CL_Recipe.json", "Name": "DS Drive (32K)", diff --git a/ContentLib/RecipePatches/Recipe_DS_Drive_40K_Fluid.json b/ContentLib/RecipePatches/Recipe_DS_Drive_40K_Fluid.json index bbd383493e6da2b4d091ab2c4218e5a871402a81..c3ade70d7da9cd9c6b91fe301ee9f008fdefe2f6 100644 GIT binary patch delta 16 YcmX>g^h<#G|G(@l;;N2RSM*%FvK&MFc>g+Lv@l;;jqTg(v8V8UR);0@K043sZmNS*wWQC1ituLm{>Nt_?1&zXUjfs3JfG9#Pt IMzI(U0CM9XlK=n! diff --git a/ContentLib/RecipePatches/Recipe_DS_Drive_4K.json b/ContentLib/RecipePatches/Recipe_DS_Drive_4K.json index 102f6ca..677d031 100644 --- a/ContentLib/RecipePatches/Recipe_DS_Drive_4K.json +++ b/ContentLib/RecipePatches/Recipe_DS_Drive_4K.json @@ -1,4 +1,3 @@ -//DigitalStorage/Resources/Drives/4K/Recipe_DS_Drive_4K.Recipe_DS_Drive_4K_C { "$schema": "https://raw.githubusercontent.com/budak7273/ContentLib_Documentation/refs/heads/main/JsonSchemas/CL_Recipe.json", "Name": "DS Drive (4K)", diff --git a/ContentLib/RecipePatches/Recipe_DS_Drive_512.json b/ContentLib/RecipePatches/Recipe_DS_Drive_512.json index 9781709..43476d5 100644 --- a/ContentLib/RecipePatches/Recipe_DS_Drive_512.json +++ b/ContentLib/RecipePatches/Recipe_DS_Drive_512.json @@ -1,4 +1,3 @@ -//DigitalStorage/Resources/Drives/512/Recipe_DS_Drive_512.Recipe_DS_Drive_512_C { "$schema": "https://raw.githubusercontent.com/budak7273/ContentLib_Documentation/refs/heads/main/JsonSchemas/CL_Recipe.json", "Name": "DS Drive (512)", diff --git a/ContentLib/RecipePatches/Recipe_DS_Drive_60K_Fluid.json b/ContentLib/RecipePatches/Recipe_DS_Drive_60K_Fluid.json index 8507a920ae8cca0731cffc975f2d7ce26bb85c47..689e0bde4edd5c52dae8d64fa2c8758328b8bd81 100644 GIT binary patch delta 16 YcmX>g^h<#G|G(@l;;N2RSM*%FvK&MF&Hp-Lv^iF{3|G$lUayS4Xs|A?= delta 142 zcmaDSutF&D|37^OeFhhXOontIE@4Py$YBTu()kQUKz2GqDo{2ENEQP{N`Yd@U^Ylc z5m0>@l;;jqTg(v8V8&p;;0@K043sZmNS*wdS(#T4YzC4DXFP*511|#?L-pj3?7|zx GA~*m6P#;_X diff --git a/ContentLib/RecipePatches/Recipe_DS_Drive_64K.json b/ContentLib/RecipePatches/Recipe_DS_Drive_64K.json index fa2af03..54b8521 100644 --- a/ContentLib/RecipePatches/Recipe_DS_Drive_64K.json +++ b/ContentLib/RecipePatches/Recipe_DS_Drive_64K.json @@ -1,4 +1,3 @@ -//DigitalStorage/Resources/Drives/64K/Recipe_DS_Drive_64K.Recipe_DS_Drive_64K_C { "$schema": "https://raw.githubusercontent.com/budak7273/ContentLib_Documentation/refs/heads/main/JsonSchemas/CL_Recipe.json", "Name": "DS Drive (64K)", diff --git a/ContentLib/RecipePatches/Recipe_DS_Drive_8K.json b/ContentLib/RecipePatches/Recipe_DS_Drive_8K.json index 1f675ba..ce324d8 100644 --- a/ContentLib/RecipePatches/Recipe_DS_Drive_8K.json +++ b/ContentLib/RecipePatches/Recipe_DS_Drive_8K.json @@ -1,4 +1,3 @@ -//DigitalStorage/Resources/Drives/8K/Recipe_DS_Drive_8K.Recipe_DS_Drive_8K_C { "$schema": "https://raw.githubusercontent.com/budak7273/ContentLib_Documentation/refs/heads/main/JsonSchemas/CL_Recipe.json", "Name": "DS Drive (8K)", diff --git a/ContentLib/RecipePatches/Recipe_DS_Multitool.json b/ContentLib/RecipePatches/Recipe_DS_Multitool.json index f51a020..4ebb4bf 100644 --- a/ContentLib/RecipePatches/Recipe_DS_Multitool.json +++ b/ContentLib/RecipePatches/Recipe_DS_Multitool.json @@ -1,4 +1,3 @@ -//DigitalStorage/Equipment/Multitool/Recipe_DS_Multitool.Recipe_DS_Multitool_C { "$schema": "https://raw.githubusercontent.com/budak7273/ContentLib_Documentation/refs/heads/main/JsonSchemas/CL_Recipe.json", "Name": "Multitool", diff --git a/ContentLib/RecipePatches/Recipe_DS_NetworkCable_Item.json b/ContentLib/RecipePatches/Recipe_DS_NetworkCable_Item.json index 0480686..d61f1aa 100644 --- a/ContentLib/RecipePatches/Recipe_DS_NetworkCable_Item.json +++ b/ContentLib/RecipePatches/Recipe_DS_NetworkCable_Item.json @@ -1,4 +1,3 @@ -//DigitalStorage/Resources/NetworkCable/Recipe_DS_NetworkCable_Item.Recipe_DS_NetworkCable_Item_C { "$schema": "https://raw.githubusercontent.com/budak7273/ContentLib_Documentation/refs/heads/main/JsonSchemas/CL_Recipe.json", "Name": "Network Cable", diff --git a/ContentLib/RecipePatches/Recipe_DS_WirelessExtender.json b/ContentLib/RecipePatches/Recipe_DS_WirelessExtender.json index f030a65..bf4e896 100644 --- a/ContentLib/RecipePatches/Recipe_DS_WirelessExtender.json +++ b/ContentLib/RecipePatches/Recipe_DS_WirelessExtender.json @@ -1,4 +1,3 @@ -//DigitalStorage/Resources/WifiExtender/Recipe_DS_WirelessExtender.Recipe_DS_WirelessExtender_C { "$schema": "https://raw.githubusercontent.com/budak7273/ContentLib_Documentation/refs/heads/main/JsonSchemas/CL_Recipe.json", "Name": "Wireless Range Extender", diff --git a/ContentLib/RecipePatches/Recipe_DS_WirelessTablet.json b/ContentLib/RecipePatches/Recipe_DS_WirelessTablet.json index 0a64030..694f4c3 100644 --- a/ContentLib/RecipePatches/Recipe_DS_WirelessTablet.json +++ b/ContentLib/RecipePatches/Recipe_DS_WirelessTablet.json @@ -1,4 +1,3 @@ -//DigitalStorage/Equipment/WirelessTablet/Recipe_DS_WirelessTablet.Recipe_DS_WirelessTablet_C { "$schema": "https://raw.githubusercontent.com/budak7273/ContentLib_Documentation/refs/heads/main/JsonSchemas/CL_Recipe.json", "Name": "Wireless Tablet", From 8884c53f572b64ee817ab6cbf47415b18c63cfb6 Mon Sep 17 00:00:00 2001 From: Merith Date: Sun, 22 Jun 2025 14:39:53 -0700 Subject: [PATCH 5/5] schema validation --- go.mod | 1 + go.sum | 2 + magefile.go | 239 +++++++++++++++++--- schema/CL_NameResolvedAsset.json | 9 + schema/CL_Recipe.json | 189 ++++++++++++++++ schema/Components/CL_ItemAmount.json | 23 ++ schema/Components/CL_NameResolvedAsset.json | 9 + 7 files changed, 445 insertions(+), 27 deletions(-) create mode 100644 schema/CL_NameResolvedAsset.json create mode 100644 schema/CL_Recipe.json create mode 100644 schema/Components/CL_ItemAmount.json create mode 100644 schema/Components/CL_NameResolvedAsset.json diff --git a/go.mod b/go.mod index c6c8524..e771035 100644 --- a/go.mod +++ b/go.mod @@ -4,6 +4,7 @@ go 1.24.3 require ( github.com/magefile/mage v1.15.0 + github.com/santhosh-tekuri/jsonschema/v5 v5.3.1 github.com/xeipuuv/gojsonschema v1.2.0 ) diff --git a/go.sum b/go.sum index 5d71808..6fc5d5e 100644 --- a/go.sum +++ b/go.sum @@ -4,6 +4,8 @@ github.com/magefile/mage v1.15.0 h1:BvGheCMAsG3bWUDbZ8AyXXpCNwU9u5CB6sM+HNb9HYg= github.com/magefile/mage v1.15.0/go.mod h1:z5UZb/iS3GoOSn0JgWuiw7dxlurVYTu+/jHXqQg881A= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/santhosh-tekuri/jsonschema/v5 v5.3.1 h1:lZUw3E0/J3roVtGQ+SCrUrg3ON6NgVqpn3+iol9aGu4= +github.com/santhosh-tekuri/jsonschema/v5 v5.3.1/go.mod h1:uToXkOrWAZ6/Oc07xWQrPOhJotwFIyu2bBVN41fcDUY= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= diff --git a/magefile.go b/magefile.go index e8e7721..888981c 100644 --- a/magefile.go +++ b/magefile.go @@ -4,22 +4,36 @@ package main import ( + "archive/zip" + "bytes" + "encoding/json" "fmt" + "io" "io/ioutil" "os" "path/filepath" - "unicode" + "strings" "unicode/utf8" "github.com/magefile/mage/mg" "github.com/magefile/mage/sh" - "github.com/xeipuuv/gojsonschema" + "github.com/santhosh-tekuri/jsonschema/v5" ) const ( zipName = "DigitalStorageTweaks.zip" contentDir = "./ContentLib" pluginFile = "./DigitalStorageTweaks.uplugin" + schemaPath = "./schema/CL_Recipe.json" // Local schema path +) + +var ( + // Binary file extensions to skip line ending conversion + binaryExtensions = map[string]bool{ + ".png": true, ".jpg": true, ".jpeg": true, ".bmp": true, ".gif": true, + ".dds": true, ".tga": true, ".psd": true, ".fbx": true, ".uasset": true, + ".umap": true, + } ) // Default target @@ -44,57 +58,125 @@ func Package() error { } } - // Create zip - if err := sh.Run("7z", "a", "-r", zipName, "Windows/", "LinuxServer/", "WindowsServer/"); err != nil { + // Create zip file + if err := createZip(zipName, "Windows", "WindowsServer", "LinuxServer"); err != nil { return fmt.Errorf("creating zip: %w", err) } // Clean temp dirs return Clean("Windows", "WindowsServer", "LinuxServer") } - -// Validate checks all content files func Validate() error { fmt.Println("Validating files...") - // Check plugin file - if err := checkFile(pluginFile); err != nil { + const ( + baseSchemaURL = "https://raw.githubusercontent.com/budak7273/ContentLib_Documentation/main/JsonSchemas/" + localSchemaDir = "./schema" + ) + + compiler := jsonschema.NewCompiler() + + // Disable remote fetching + compiler.LoadURL = func(url string) (io.ReadCloser, error) { + return nil, fmt.Errorf("remote schema loading disabled: %s", url) + } + + // Walk through the schema directory and add all .json files + err := filepath.Walk(localSchemaDir, func(path string, info os.FileInfo, err error) error { + if err != nil || info.IsDir() { + return err + } + + if filepath.Ext(path) != ".json" { + return nil + } + + relPath, err := filepath.Rel(localSchemaDir, path) + if err != nil { + return fmt.Errorf("resolving relative path: %w", err) + } + + // Build the full schema ID + schemaID := baseSchemaURL + filepath.ToSlash(relPath) + + data, err := ioutil.ReadFile(path) + if err != nil { + return fmt.Errorf("reading %s: %w", path, err) + } + + err = compiler.AddResource(schemaID, bytes.NewReader(data)) + if err != nil { + return fmt.Errorf("adding schema %s: %w", schemaID, err) + } + + return nil + }) + if err != nil { + return fmt.Errorf("failed to load schemas: %w", err) + } + + // Main schema (must match its $id) + mainSchemaID := baseSchemaURL + "CL_Recipe.json" + + // Compile the main schema + schema, err := compiler.Compile(mainSchemaID) + if err != nil { + return fmt.Errorf("invalid main schema: %w", err) + } + + // Validate plugin file + if err := validateFile(pluginFile, schema); err != nil { return fmt.Errorf("plugin file: %w", err) } - // Check content directory + // Validate all JSON files in the content directory return filepath.Walk(contentDir, func(path string, info os.FileInfo, err error) error { if err != nil || info.IsDir() { return err } - return checkFile(path) + return validateFile(path, schema) }) } -func checkFile(path string) error { +func validateFile(path string, schema *jsonschema.Schema) error { // Skip binary files - switch filepath.Ext(path) { - case ".png", ".jpg", ".jpeg", ".bmp", ".gif", ".dds", ".tga", ".psd", ".fbx", ".uasset", ".umap": + ext := filepath.Ext(path) + if binaryExtensions[ext] { return nil - case ".json": - return validateJSON(path) - default: - return validateEncoding(path) } + + if ext == ".json" { + return validateJSON(path, schema) + } + return validateEncoding(path) } -func validateJSON(path string) error { - schemaLoader := gojsonschema.NewReferenceLoader("https://raw.githubusercontent.com/budak7273/ContentLib_Documentation/main/JsonSchemas/CL_Recipe.json") - documentLoader := gojsonschema.NewReferenceLoader("file:///" + filepath.ToSlash(path)) - - result, err := gojsonschema.Validate(schemaLoader, documentLoader) +func validateJSON(path string, schema *jsonschema.Schema) error { + content, err := ioutil.ReadFile(path) if err != nil { - return fmt.Errorf("schema validation failed: %w", err) + return fmt.Errorf("failed to read JSON file: %w", err) } - if !result.Valid() { - return fmt.Errorf("invalid JSON schema: %v", result.Errors()) + // Remove comment lines (starting with //) + var filteredContent []byte + for _, line := range bytes.Split(content, []byte("\n")) { + trimmed := bytes.TrimSpace(line) + if !bytes.HasPrefix(trimmed, []byte("//")) && len(trimmed) > 0 { + filteredContent = append(filteredContent, line...) + filteredContent = append(filteredContent, '\n') + } } + + // Validate JSON + var v interface{} + if err := json.Unmarshal(filteredContent, &v); err != nil { + return fmt.Errorf("invalid JSON in %s: %w", path, err) + } + + if err := schema.Validate(v); err != nil { + return fmt.Errorf("schema validation failed for %s: %w", path, err) + } + return nil } @@ -105,11 +187,16 @@ func validateEncoding(path string) error { } // Check for non-ASCII - for i := 0; i < len(content); i++ { - if content[i] > unicode.MaxASCII { + for i := 0; i < len(content); { + b := content[i] + if b > 127 { // Non-ASCII r, _ := utf8.DecodeRune(content[i:]) + if r == utf8.RuneError { + return fmt.Errorf("invalid UTF-8 sequence at position %d", i) + } return fmt.Errorf("non-ASCII character %U at position %d", r, i) } + i++ } return nil } @@ -124,3 +211,101 @@ func Clean(list ...string) error { } return nil } + +// createZip creates a zip file from the specified directories +func createZip(zipPath string, dirs ...string) error { + // Create zip file + zipFile, err := os.Create(zipPath) + if err != nil { + return fmt.Errorf("creating zip file: %w", err) + } + defer zipFile.Close() + + // Create zip writer + zipWriter := zip.NewWriter(zipFile) + defer zipWriter.Close() + + // Add each directory to the zip + for _, dir := range dirs { + if err := addDirToZip(zipWriter, dir); err != nil { + return fmt.Errorf("adding %s to zip: %w", dir, err) + } + } + + return nil +} + +// addDirToZip adds a directory to the zip, converting text files to DOS line endings +func addDirToZip(zipWriter *zip.Writer, dirPath string) error { + return filepath.Walk(dirPath, func(filePath string, info os.FileInfo, err error) error { + if err != nil { + return err + } + + // Create relative path for the zip file + relPath, err := filepath.Rel(dirPath, filePath) + if err != nil { + return err + } + zipPath := filepath.Join(filepath.Base(dirPath), relPath) + + // Create zip file header + header, err := zip.FileInfoHeader(info) + if err != nil { + return err + } + header.Name = filepath.ToSlash(zipPath) // Use forward slashes for zip compatibility + + // Use compression for all files + header.Method = zip.Deflate + + // Handle directories + if info.IsDir() { + header.Name += "/" + _, err := zipWriter.CreateHeader(header) + return err + } + + // Open source file + file, err := os.Open(filePath) + if err != nil { + return err + } + defer file.Close() + + // Create writer in zip + writer, err := zipWriter.CreateHeader(header) + if err != nil { + return err + } + + // Process based on file type + ext := strings.ToLower(filepath.Ext(filePath)) + if binaryExtensions[ext] { + // Binary file - copy directly + _, err = io.Copy(writer, file) + return err + } else { + // Text file - read content and convert line endings + content, err := ioutil.ReadAll(file) + if err != nil { + return err + } + + // Convert LF to CRLF + content = convertToDOSLineEndings(content) + + // Write to zip + _, err = writer.Write(content) + return err + } + }) +} + +// convertToDOSLineEndings converts LF to CRLF while preserving existing CRLF +func convertToDOSLineEndings(content []byte) []byte { + // First normalize to LF + normalized := bytes.ReplaceAll(content, []byte("\r\n"), []byte("\n")) + // Then convert to CRLF + return bytes.ReplaceAll(normalized, []byte("\n"), []byte("\r\n")) +} diff --git a/schema/CL_NameResolvedAsset.json b/schema/CL_NameResolvedAsset.json new file mode 100644 index 0000000..06fbe42 --- /dev/null +++ b/schema/CL_NameResolvedAsset.json @@ -0,0 +1,9 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "https://raw.githubusercontent.com/budak7273/ContentLib_Documentation/main/JsonSchemas/CL_NameResolvedAsset.json", + "title": "ContentLib Name Resolved Asset", + "description": "An asset that can be specified either with a full path, or a shortened name for ContentLib to resolve. See more info here: https://docs-dev.ficsit.app/contentlib/latest/BackgroundInfo/AutomaticNameResolving.html", + "$comment": "This file does not represent ContentLib asset type! It's a resource used by other JSON Schemas. Please read https://docs-dev.ficsit.app/contentlib/latest/BackgroundInfo/AutomaticNameResolving.html", + "type": "string", + "minLength": 1 +} diff --git a/schema/CL_Recipe.json b/schema/CL_Recipe.json new file mode 100644 index 0000000..2c9656d --- /dev/null +++ b/schema/CL_Recipe.json @@ -0,0 +1,189 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "https://raw.githubusercontent.com/budak7273/ContentLib_Documentation/main/JsonSchemas/CL_Recipe.json", + "title": "ContentLib Recipe", + "description": "ContentLib Recipe struct definitions can be made from this JSON, and when converted to JSON, will follow this form.", + "$comment": "This is NOT a copy-paste template! Check the docs to see how to use this! https://docs.ficsit.app/contentlib/latest/index.html", + "type": "object", + "additionalProperties": false, + "properties": { + "Name": { + "type": "string", + "description": "Override for the recipe's name, which is displayed inside the manual crafting bench, build gun, or any machines you set it to be used in. By default, recipes take the name of their first product item." + }, + "Ingredients": { + "type": "array", + "description": "ItemAmounts which form the ingredients. Be sure to not exceed an item's stack size, and remember that 1000 fluid units displays as 1 Liter ingame. See 'ClearIngredients' to append instead of replace.", + "items": { + "$ref": "./Components/CL_ItemAmount.json" + }, + "examples": [ + [ + { + "Item": "Desc_CopperIngot", + "Amount": 1 + }, + { + "Item": "Desc_IronIngot", + "Amount": 1 + } + ] + ] + }, + "Products": { + "type": "array", + "description": "ItemAmounts which form the recipe outputs. Be sure to not exceed an item's stack size, and remember that 1000 fluid units displays as 1 Liter ingame. Manual recipes should only have 1 product. See 'ClearProducts' to append instead of replace.", + "items": { + "$ref": "./Components/CL_ItemAmount.json" + }, + "examples": [ + [ + { + "Item": "Desc_Biofuel", + "Amount": 10 + } + ] + ] + }, + "ProducedIn": { + "type": "array", + "description": "Automatic name resolved asset. Machines/builders which this recipe can be used in. The examples are not an exhaustive list. Use 'manual' for all manual workbenches; this is a workaround and will be fixed in the future. See 'ClearBuilders' to append instead of replace.", + "uniqueItems": true, + "items": { + "$ref": "./Components/CL_NameResolvedAsset.json", + "examples": [ + "manual", + "Build_SmelterMk1", + "Build_ConstructorMk1", + "Build_AssemblerMk1", + "Build_FoundryMk1", + "Build_ManufacturerMk1", + "Build_OilRefinery", + "Build_Packager", + "Build_Blender", + "Build_HadronCollider", + "Build_Converter", + "Build_QuantumEncoder", + "BP_BuildGun" + ], + "allOf": [ + { + "$comment": "The `manual` workaround should be used instead of these (see the docs https://docs.ficsit.app/contentlib/latest/Tutorials/CreateRecipe.html).", + "if": { + "anyOf": [ + { + "const": "FGWorkBench" + }, + { + "const": "Build_Workshop" + }, + { + "const": "Build_WorkBench" + }, + { + "const": "Build_WorkBenchIntegrated" + } + ] + }, + "then": { + "const": "manual" + } + } + ] + } + }, + "OverrideCategory": { + "type": "string", + "description": "By default, recipes take on the category of their first product item. Specifying something here causes it to be used as the category instead. Either a base-game category, or a string which ContentLib will automatically turn into a category for you.", + "examples": [ + "Cat_Other", + "MyCustomAutoCreatedCategory" + ] + }, + "ManufacturingDuration": { + "type": "number", + "description": "The time it takes for a machine to process this recipe in seconds. Recipe energy consumption is usually this times the machine's power usage." + }, + "ManualManufacturingMultiplier": { + "type": "number", + "description": "If you want to use the same recipe for machines and the craft bench, this defines how much longer the crafting of this recipe should take in the craft bench. With the multiplier set to the default of 0, the number of clicks to craft is the number of seconds it takes to craft divided by two.", + "examples": [ + 0.0 + ] + }, + "UnlockedBy": { + "type": "array", + "description": "Automatic name resolved asset. Schematics to add this recipe to. Alternative way of tying recipes to schematics; the standard way is to use the schematic's 'Recipes' field. This is useful if you don't want to also make a patch to add your recipe to a base-game schematic. Something must unlock the recipe, else it will never be accessible in-game. If you want it to be unlocked by default, use Schematic_StartingRecipes.", + "items": { + "$ref": "./Components/CL_NameResolvedAsset.json" + }, + "examples": [ + [ + "Schematic_StartingRecipes" + ], + [ + "Schematic_1-1" + ] + ] + }, + "VariablePowerConsumptionFactor": { + "type": "number", + "description": "Only works in variable consumption machines (the Particle Accelerator in base game). Added to the VariablePowerConsumptionFactor to get the 'maximum' power consumption the recipe can scale up to over its cycle." + }, + "VariablePowerConsumptionConstant": { + "type": "number", + "description": "Only works in variable consumption machines (the Particle Accelerator in base game). The 'minimum' power consumption the recipe can scale down to over its cycle." + }, + "ManufacturingMenuPriority": { + "type": "number", + "description": "Controls the order that recipes appear within their category. Lower values means earlier in the menu. Negatives and decimals allowed." + }, + "OverrideName": { + "type": "boolean", + "description": "For patches, should the Recipe this is used on have its 'use override name' flag enabled? Default is true when 'Name' exists, false when not. This can be used to ex. revert a recipe's displayed name to that of its first product, instead of the custom name that was specified for it." + }, + "ClearIngredients": { + "type": "boolean", + "description": "For patches, should the Recipe this is used on have its existing Ingredients array cleared before adding to it? Default is true when 'Ingredients' exists, false when not." + }, + "ClearProducts": { + "type": "boolean", + "description": "For patches, should the Recipe this is used on have its existing Products array cleared before adding to it? Default is true when 'Products' exists, false when not." + }, + "ClearBuilders": { + "type": "boolean", + "description": "For patches, should the Recipe this is used on have its existing ProducedIn array cleared before adding to it? Default is true when 'ProducedIn' exists, false when not." + } + }, + "allOf": [ + { + "$comment": "Manual recipes should only have one product", + "if": { + "properties": { + "ProducedIn": { + "contains": { + "const": "manual" + } + } + } + }, + "then": { + "properties": { + "Products": { + "maxItems": 1 + } + } + } + } + ], + "patternProperties": { + "schema": { + "$comment": "Allow the $schema line in files", + "type": "string" + }, + "comment": { + "$comment": "Allow the $comment line in files", + "type": "string" + } + } +} \ No newline at end of file diff --git a/schema/Components/CL_ItemAmount.json b/schema/Components/CL_ItemAmount.json new file mode 100644 index 0000000..ab69cb5 --- /dev/null +++ b/schema/Components/CL_ItemAmount.json @@ -0,0 +1,23 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "https://raw.githubusercontent.com/budak7273/ContentLib_Documentation/main/JsonSchemas/CL_ItemAmount.json", + "title": "Item Amount Structure", + "description": "Respresents a quantity of an item", + "$comment": "This file does not represent ContentLib asset type! It's a resource used by other JSON Schemas.", + "type": "object", + "additionalProperties": false, + "required": [ + "Item", + "Amount" + ], + "properties": { + "Item": { + "$ref": "./CL_NameResolvedAsset.json" + }, + "Amount": { + "type": "integer", + "minimum": 0, + "description": "Integer specifying the quantity of item(s). Remember that remember that 1000 fluid units displays as 1 Liter ingame." + } + } +} \ No newline at end of file diff --git a/schema/Components/CL_NameResolvedAsset.json b/schema/Components/CL_NameResolvedAsset.json new file mode 100644 index 0000000..06fbe42 --- /dev/null +++ b/schema/Components/CL_NameResolvedAsset.json @@ -0,0 +1,9 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "https://raw.githubusercontent.com/budak7273/ContentLib_Documentation/main/JsonSchemas/CL_NameResolvedAsset.json", + "title": "ContentLib Name Resolved Asset", + "description": "An asset that can be specified either with a full path, or a shortened name for ContentLib to resolve. See more info here: https://docs-dev.ficsit.app/contentlib/latest/BackgroundInfo/AutomaticNameResolving.html", + "$comment": "This file does not represent ContentLib asset type! It's a resource used by other JSON Schemas. Please read https://docs-dev.ficsit.app/contentlib/latest/BackgroundInfo/AutomaticNameResolving.html", + "type": "string", + "minLength": 1 +}