5 Commits
1.1.0 ... 1.3.0

Author SHA1 Message Date
mikx
54ec385800 1.3.0 (Generator Energy/Biiofuel Modding) 2025-10-22 19:42:04 -04:00
mikx
5fefe8eba9 1.2.0 (Added inventory list + Recipe modding tweaks) 2025-10-13 22:54:52 -04:00
mikx
fd893057f2 1.1.1 (Removed log file logic) 2025-10-13 16:07:12 -04:00
mikx
9eeea525d3 Readme Update 2025-10-12 23:25:42 -04:00
mikx
0ba8668d09 Readme edit with How-To 2025-10-12 23:24:55 -04:00
3 changed files with 247 additions and 147 deletions

View File

@@ -62,7 +62,6 @@ namespace Jsarus
str3 = num.ToString(); str3 = num.ToString();
} }
string str4 = string.Format("{0}:{1}:{2}", (object)str3, (object)str2, (object)str1); string str4 = string.Format("{0}:{1}:{2}", (object)str3, (object)str2, (object)str1);
File.AppendAllText("mxfiltergen.logs", string.Format("[{0}] {1}", (object)str4, (object)msg) + Environment.NewLine);
ConsoleColor consoleColor = ConsoleColor.White; ConsoleColor consoleColor = ConsoleColor.White;
switch (color) switch (color)
{ {

View File

@@ -6,54 +6,95 @@ using System.ComponentModel;
using System.Diagnostics; using System.Diagnostics;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Net;
using System.Runtime; using System.Runtime;
using System.Text; using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace Jsarus namespace Jsarus
{ {
internal class Program internal class Program
{ {
public static string version = "1.1.0"; public static string version = "1.3.0";
public static string cd = Directory.GetCurrentDirectory(); public static string cd = Directory.GetCurrentDirectory();
public static Process p = new Process(); public static Process p = new Process();
private static ConsoleKeyInfo keyInfo;
static void Main(string[] args) static void Main(string[] args)
{ {
WebClient wc = new WebClient();
Message.Splash("Jsarus", "mikx"); Message.Splash("Jsarus", "mikx");
Message.CMW("Creating directories...", true, 1); Message.CMW("Creating directories...", true, 1);
if (!Directory.Exists($@"Data\Modded")) { Directory.CreateDirectory($@"Data\Modded"); } if (!Directory.Exists($@"Data\Modded")) { Directory.CreateDirectory($@"Data\Modded"); }
if (!Directory.Exists($@"Data\Modded\data")) { Directory.CreateDirectory($@"Data\Modded\data"); } if (!Directory.Exists($@"Data\Modded\data")) { Directory.CreateDirectory($@"Data\Modded\data"); }
Message.CMW("Preparing variables...",true,1); Message.CMW("Preparing variables...", true, 1);
JObject settings = JObject.Parse(File.ReadAllText("settings.json")); JObject settings = JObject.Parse(File.ReadAllText("settings.json"));
string ModName = settings["ModName"].ToObject<string>(); string ModName = settings["ModName"].ToObject<string>();
string GameContentPath = settings["GameContentPath"].ToObject<string>(); string GameContentPath = settings["GameContentPath"].ToObject<string>();
bool KeepData = settings["KeepData"].ToObject<bool>();
string[] CopyList = settings["CopyList"].ToObject<string[]>(); string[] CopyList = settings["CopyList"].ToObject<string[]>();
int ItemWeight = settings["D_Itemable"]["ItemWeight"].ToObject<int>(); if (!File.Exists("data.json")) { wc.DownloadFile("https://mxio.ovh/icarus/jsarus/data.json", "data.json"); }
int ItemStack = settings["D_Itemable"]["ItemStack"].ToObject<int>();
int ExperienceMultiplier = settings["D_ExperienceEvents"]["ExperienceMultiplier"].ToObject<int>(); JObject data = JObject.Parse(File.ReadAllText("data.json"));
int DataVersion = data["version"].ToObject<int>();
JObject dataRemote = JObject.Parse(wc.DownloadString("https://mxio.ovh/icarus/jsarus/data.json"));
int DataVersionRemote = dataRemote["version"].ToObject<int>();
string[] ActionList = settings["D_StaminaActionCosts"]["ActionList"].ToObject<string>().Split('|'); if (KeepData)
int DivideCostPer = settings["D_StaminaActionCosts"]["DivideCostPer"].ToObject<int>(); {
Message.CMW("Keeping your custom data.", true, 1);
if (DataVersion < DataVersionRemote)
{
Message.CMW("Consider setting \"KeepData\" to \"true\" in your \"settings.json\"!", true, 1);
Message.CMW("Your data is outdated. Should we update it? (y/n)", true, 3);
Message.CMW("If you are not sure, answer \"y\".", true, 1);
keyInfo = Console.ReadKey(true);
if (keyInfo.Key == ConsoleKey.Y)
{
Message.CMW("Getting the latest data...", true, 1);
if (File.Exists("data.json")) { File.Copy("data.json", "data.backup.json", true); }
Message.CMW("A backup has been made to \"data.backup.json\".", true, 1);
wc.DownloadFile("https://mxio.ovh/icarus/jsarus/data.json", "data.json");
}
}
}
else
{
Message.CMW("Getting the latest data...", true, 1);
wc.DownloadFile("https://mxio.ovh/icarus/jsarus/data.json", "data.json");
}
string[] PickList = settings["D_ToolDamage"]["PickList"].ToObject<string>().Split('|'); int ItemWeight = data["D_Itemable"]["ItemWeight"].ToObject<int>();
string[] PickEfficiencyList = settings["D_ToolDamage"]["PickEfficiencyList"].ToObject<string>().Split('|'); int ItemStack = data["D_Itemable"]["ItemStack"].ToObject<int>();
string[] AxeList = settings["D_ToolDamage"]["AxeList"].ToObject<string>().Split('|'); int ExperienceMultiplier = data["D_ExperienceEvents"]["ExperienceMultiplier"].ToObject<int>();
string[] AxeEfficiencyList = settings["D_ToolDamage"]["AxeEfficiencyList"].ToObject<string>().Split('|');
string[] RecipeListOre = settings["D_ProcessorRecipes"]["RecipeListOre"].ToObject<string>().Split('|'); string[] ActionList = data["D_StaminaActionCosts"]["ActionList"].ToObject<string>().Split('|');
string[] RecipeList = settings["D_ProcessorRecipes"]["RecipeList"].ToObject<string>().Split('|'); int DivideCostPer = data["D_StaminaActionCosts"]["DivideCostPer"].ToObject<int>();
string[] RecipeListStack = settings["D_ProcessorRecipes"]["RecipeListStack"].ToObject<string>().Split('|');
int RequiredMillijoules = settings["D_ProcessorRecipes"]["RequiredMillijoules"].ToObject<int>();
int RequiredAmount = settings["D_ProcessorRecipes"]["RequiredAmount"].ToObject<int>();
int CraftedAmount = settings["D_ProcessorRecipes"]["CraftedAmount"].ToObject<int>();
int ÞlayerInventorySize = settings["D_InventoryInfo"]["ÞlayerInventorySize"].ToObject<int>(); string[] PickList = data["D_ToolDamage"]["PickList"].ToObject<string>().Split('|');
string[] PickEfficiencyList = data["D_ToolDamage"]["PickEfficiencyList"].ToObject<string>().Split('|');
string[] supportedJson = { @"Traits\D_Itemable.json", @"Experience\D_ExperienceEvents.json", @"Tools\D_StaminaActionCosts.json", @"Tools\D_ToolDamage.json", @"Crafting\D_ProcessorRecipes.json", @"Inventory\D_InventoryInfo.json" }; string[] AxeList = data["D_ToolDamage"]["AxeList"].ToObject<string>().Split('|');
string[] AxeEfficiencyList = data["D_ToolDamage"]["AxeEfficiencyList"].ToObject<string>().Split('|');
string[] RecipeListOre = data["D_ProcessorRecipes"]["RecipeListOre"].ToObject<string>().Split('|');
string[] RecipeList = data["D_ProcessorRecipes"]["RecipeList"].ToObject<string>().Split('|');
string[] RecipeListStack = data["D_ProcessorRecipes"]["RecipeListStack"].ToObject<string>().Split('|');
int RequiredMillijoules = data["D_ProcessorRecipes"]["RequiredMillijoules"].ToObject<int>();
int RequiredAmount = data["D_ProcessorRecipes"]["RequiredAmount"].ToObject<int>();
int CraftedAmount = data["D_ProcessorRecipes"]["CraftedAmount"].ToObject<int>();
string[] InventoryList = data["D_InventoryInfo"]["InventoryList"].ToObject<string>().Split('|');
int InventorySize = data["D_InventoryInfo"]["InventorySize"].ToObject<int>();
string[] GeneratorList = data["D_Generator"]["GeneratorList"].ToObject<string>().Split('|');
int GenerationRate = data["D_Generator"]["GenerationRate"].ToObject<int>();
int GenerationRatio = data["D_Generator"]["GenerationRatio"].ToObject<int>();
string[] supportedJson = { @"Traits\D_Itemable.json", @"Experience\D_ExperienceEvents.json", @"Tools\D_StaminaActionCosts.json", @"Tools\D_ToolDamage.json", @"Crafting\D_ProcessorRecipes.json", @"Inventory\D_InventoryInfo.json", @"Traits\D_Generator.json" };
var dir = Directory.GetDirectories(@"Data\Vanilla"); var dir = Directory.GetDirectories(@"Data\Vanilla");
@@ -74,153 +115,191 @@ namespace Jsarus
Message.CMW($"Copied {sj.Split('\\')[1]}.", true, 2); Message.CMW($"Copied {sj.Split('\\')[1]}.", true, 2);
} }
Message.CMW($"We extracted the data, should we continue and mod it? (y/n)", true, 1); Message.CMW("Generating the Item Database for dynamic modding...", true, 1);
ConsoleKeyInfo keyInfo = Console.ReadKey(true); JArray itemsDB = new JArray();
if (keyInfo.Key == ConsoleKey.N) { return; } else JObject items = new JObject();
JObject item = JObject.Parse(File.ReadAllText(@"Data\Vanilla\Traits\D_Itemable.json"));
foreach (var d in dir) foreach (var i in item["Rows"])
{ {
var json = Directory.GetFiles(d); string iname = i["Name"].ToObject<string>().Substring(5);
foreach (var file in json) int iweight = 0;
if (i["Weight"] != null) { iweight = i["Weight"].ToObject<int>(); } else { iweight = 0; }
bool istack = false;
int istacksize = 1;
if (i["MaxStack"] != null) { istack = true; istacksize = i["MaxStack"].ToObject<int>(); }
items = new JObject()
{ {
string f = Path.GetFileName(file); { "name", iname },
Message.CMW($"Processing {f}...", true, 1); { "weight", iweight },
JObject job = JObject.Parse(File.ReadAllText(file)); { "dostack", istack },
switch (f) { "stack", istacksize }
{ };
case "D_Itemable.json": itemsDB.Add(items);
foreach (var r in job["Rows"]) }
var rawDB = JsonConvert.SerializeObject(itemsDB, Formatting.Indented);
File.WriteAllText($@"Data/itemDB.json", rawDB);
foreach (var d in dir)
{
var json = Directory.GetFiles(d);
foreach (var file in json)
{
string f = Path.GetFileName(file);
Message.CMW($"Processing {f}...", true, 1);
JObject job = JObject.Parse(File.ReadAllText(file));
switch (f)
{
case "D_Itemable.json":
foreach (var r in job["Rows"])
{
r["Name"] = r["Name"].ToObject<string>();
r["DisplayName"] = r["DisplayName"].ToObject<string>();
if (r["Icon"] != null)
{ {
r["Name"] = r["Name"].ToObject<string>(); r["Icon"] = r["Icon"].ToObject<string>();
r["DisplayName"] = r["DisplayName"].ToObject<string>(); }
if (r["Icon"] != null) if (r["Description"] != null)
{
r["Description"] = r["Description"].ToObject<string>();
}
if (r["FlavorText"] != null)
{
r["FlavorText"] = r["FlavorText"].ToObject<string>();
}
r["Weight"] = ItemWeight;
if (r["MaxStack"] != null)
{
r["MaxStack"] = ItemStack;
}
}
break;
case "D_ExperienceEvents.json":
foreach (var r in job["Rows"])
{
r["Name"] = r["Name"].ToObject<string>();
if (r["EventDescription"] != null)
{
r["EventDescription"] = r["EventDescription"].ToObject<string>();
}
if (r["SharedExperience"] != null)
{
r["SharedExperience"] = r["SharedExperience"].ToObject<bool>();
}
if (r["ExperienceGranted"] != null)
{
r["ExperienceGranted"] = r["ExperienceGranted"].ToObject<int>() * ExperienceMultiplier;
}
}
break;
case "D_StaminaActionCosts.json":
foreach (var r in job["Rows"])
{
if (ActionList.Contains(r["Name"].ToString()))
{
if (r["PerSecondCost"] != null)
{ {
r["Icon"] = r["Icon"].ToObject<string>(); r["PerSecondCost"] = r["PerSecondCost"].ToObject<int>() / DivideCostPer;
} }
if (r["Description"] != null) if (r["BeginActionCost"] != null)
{ {
r["Description"] = r["Description"].ToObject<string>(); r["BeginActionCost"] = r["BeginActionCost"].ToObject<int>() / DivideCostPer;
}
if (r["FlavorText"] != null)
{
r["FlavorText"] = r["FlavorText"].ToObject<string>();
}
r["Weight"] = ItemWeight;
if (r["MaxStack"] != null)
{
r["MaxStack"] = ItemStack;
} }
} }
break; }
break;
case "D_ExperienceEvents.json": case "D_ToolDamage.json":
foreach (var r in job["Rows"]) foreach (var r in job["Rows"])
{
if (PickList.Contains(r["Name"].ToString()))
{ {
r["Name"] = r["Name"].ToObject<string>(); int index = Array.IndexOf(PickList, r["Name"].ToString());
if (r["EventDescription"] != null) r["Mining_Efficiency"] = PickEfficiencyList[index];
{
r["EventDescription"] = r["EventDescription"].ToObject<string>();
}
if (r["SharedExperience"] != null)
{
r["SharedExperience"] = r["SharedExperience"].ToObject<bool>();
}
if (r["ExperienceGranted"] != null)
{
r["ExperienceGranted"] = r["ExperienceGranted"].ToObject<int>() * ExperienceMultiplier;
}
} }
break;
case "D_StaminaActionCosts.json": if (AxeList.Contains(r["Name"].ToString()))
foreach (var r in job["Rows"])
{ {
if(ActionList.Contains(r["Name"].ToString())) int index = Array.IndexOf(AxeList, r["Name"].ToString());
r["Felling_Efficiency"] = AxeEfficiencyList[index];
}
}
break;
case "D_ProcessorRecipes.json":
JArray itemDB = JArray.Parse(File.ReadAllText(@"Data\itemDB.json"));
foreach (var r in job["Rows"])
{
//JToken entry = itemDB.FirstOrDefault(t => (bool)(t["name"]?.ToString().Contains(r["Name"]?.ToString())));
if (r["Inputs"].Count() > 0)
{
if (RecipeListOre.Contains(r["Name"].ToString()))
{ {
if (r["PerSecondCost"] != null) if (r["RequiredMillijoules"] != null)
{ {
r["PerSecondCost"] = r["PerSecondCost"].ToObject<int>() / DivideCostPer; r["RequiredMillijoules"] = RequiredMillijoules;
} }
if (r["BeginActionCost"] != null) foreach (var i in r["Inputs"])
{ {
r["BeginActionCost"] = r["BeginActionCost"].ToObject<int>() / DivideCostPer; i["Count"] = RequiredAmount;
} }
r["Outputs"][0]["Count"] = CraftedAmount;
}
if (RecipeList.Contains(r["Name"].ToString()))
{
foreach (var i in r["Inputs"])
{
i["Count"] = RequiredAmount;
}
r["Outputs"][0]["Count"] = 1;
}
if (RecipeListStack.Contains(r["Name"].ToString()))
{
foreach (var i in r["Inputs"])
{
i["Count"] = RequiredAmount;
}
r["Outputs"][0]["Count"] = CraftedAmount;
} }
} }
break;
case "D_ToolDamage.json": }
foreach (var r in job["Rows"]) break;
case "D_InventoryInfo.json":
foreach (var r in job["Rows"])
{
if (InventoryList.Contains(r["Name"].ToString()))
{ {
if (PickList.Contains(r["Name"].ToString())) r["StartingSlots"] = InventorySize;
{
int index = Array.IndexOf(PickList, r["Name"].ToString());
r["Mining_Efficiency"] = PickEfficiencyList[index];
}
if (AxeList.Contains(r["Name"].ToString()))
{
int index = Array.IndexOf(AxeList, r["Name"].ToString());
r["Felling_Efficiency"] = AxeEfficiencyList[index];
}
} }
break; }
break;
case "D_ProcessorRecipes.json": case "D_Generator.json":
foreach (var r in job["Rows"]) foreach (var r in job["Rows"])
{
if (GeneratorList.Contains(r["Name"].ToString()))
{ {
if (r["Inputs"].Count() > 0) r["GenerationRate"] = GenerationRate;
if (r["GenerationRatio"] != null)
{ {
if (RecipeListOre.Contains(r["Name"].ToString())) r["GenerationRatio"] = GenerationRatio;
{
if (r["RequiredMillijoules"] != null)
{
r["RequiredMillijoules"] = RequiredMillijoules;
}
foreach (var i in r["Inputs"])
{
i["Count"] = RequiredAmount;
}
r["Outputs"][0]["Count"] = CraftedAmount;
}
if (RecipeList.Contains(r["Name"].ToString()))
{
foreach (var i in r["Inputs"])
{
i["Count"] = RequiredAmount;
}
r["Outputs"][0]["Count"] = 1;
}
if (RecipeListStack.Contains(r["Name"].ToString()))
{
foreach (var i in r["Inputs"])
{
i["Count"] = RequiredAmount;
}
r["Outputs"][0]["Count"] = CraftedAmount;
}
} }
} }
break; }
break;
case "D_InventoryInfo.json":
foreach (var r in job["Rows"])
{
if (r["Name"].ToObject<string>() == "Backpack")
{
r["StartingSlots"] = ÞlayerInventorySize;
}
}
break;
}
Message.CMW($"Saving {f}...", true, 1);
var raw = JsonConvert.SerializeObject(job, Formatting.Indented);
if (!Directory.Exists($@"{cd}\Data\Modded\data\{Path.GetFileName(d)}")) { Directory.CreateDirectory($@"{cd}\Data\Modded\data\{Path.GetFileName(d)}"); }
File.WriteAllText($@"Data/Modded/data/{Path.GetFileName(d)}/{f}", raw);
} }
Message.CMW($"Saving {f}...", true, 1);
var raw = JsonConvert.SerializeObject(job, Formatting.Indented);
if (!Directory.Exists($@"{cd}\Data\Modded\data\{Path.GetFileName(d)}")) { Directory.CreateDirectory($@"{cd}\Data\Modded\data\{Path.GetFileName(d)}"); }
File.WriteAllText($@"Data/Modded/data/{Path.GetFileName(d)}/{f}", raw);
} }
}
if (File.Exists($@"{cd}\Paks\{ModName}.txt")) { File.Delete($@"{cd}\Paks\{ModName}.txt"); } if (File.Exists($@"{cd}\Paks\{ModName}.txt")) { File.Delete($@"{cd}\Paks\{ModName}.txt"); }
File.WriteAllText($@"{cd}\Paks\{ModName}.txt", $@"""{cd}\Data\Modded\*.*"" ""..\..\..\Icarus\Content\*.*"""); File.WriteAllText($@"{cd}\Paks\{ModName}.txt", $@"""{cd}\Data\Modded\*.*"" ""..\..\..\Icarus\Content\*.*""");

View File

@@ -1,10 +1,32 @@
# ![logo](https://mxdev.ovh/wp-content/uploads/2025/09/mxdev-1.png) ![logo](https://mxdev.ovh/wp-content/uploads/2025/09/mxdev-1.png)
## Jsarus ## Jsarus
Official MxIcarus Modding Tool for Icarus. Official MxIcarus Modding Tool for Icarus.
## Features ## Features
* Extract json data from your client. 1. Extract json data from your client.
* Mod your extracted json data according to the settings.json config. 2. Mod your extracted json data according to the settings.json config.
* Create a pak file, ready to use on your client/server. 3. Create a pak file, ready to use on your client/server.
* Can copy the created pak file to a user specified list of path. 4. Can copy the created pak file to a user specified list of path.
- Set all stackable item stack size and weight. (Edited in settings.json)
- Set all non-stackable item weight. (Edited in settings.json)
- Multiply all experience gain. (Edited in settings.json)
- Divide stamina cost of listed action list. (Edited in settings.json)
- Set efficiency of listed pickaxe and axe from a list. (Edited in settings.json)
- Set ore recipe crafting speed. (Edited in settings.json)
- Reduce all required mats of a recipe to 1, using a list. (Edited in settings.json)
- Set output of all stacking recipes to a specified value. (Edited in settings.json)
- Adjust the size of all inventory specified in a list. (Edited in settings.json)
- Adjust the energy produced and the biofuel consumed by all specified generator in a list. (Edited in settings.json)
## How-To
1. Download the latest [release](https://mxgit.ovh/Icarus/Jsarus/releases).
2. Copy the archive content in an empty folder on your disk.
3. Open "settings.json" and edit the "ModName" and "GameContentPath".
4. IMPORTANT: Escape "\\" in your path with "\\\\". Ex.: "C:\\\\SteamLibrary\\\\steamapps\\\\common\\\\Icarus\\\\Icarus\\\\Content"
5. Save the "settings.json" file and run "Jsarus.exe".
6. Jsarus will extract your game data, press "y" when asked to mod it and generate a mod pak.
7. Copy the created pak file from the "Paks" folder to your game "mods" folder.
8. "mods" location exemple: "C:\SteamLibrary\steamapps\common\Icarus\Icarus\Content\Paks\mods"
9. If you don't have a "mods" folder, create one first.
10. Voila!