diff --git a/examples/kubejs/images/energizing.png b/examples/kubejs/images/energizing.png new file mode 100644 index 0000000..49975be Binary files /dev/null and b/examples/kubejs/images/energizing.png differ diff --git a/examples/kubejs/images/results_builder.png b/examples/kubejs/images/results_builder.png new file mode 100644 index 0000000..db603ef Binary files /dev/null and b/examples/kubejs/images/results_builder.png differ diff --git a/examples/kubejs/lang.js b/examples/kubejs/lang.js new file mode 100644 index 0000000..ea42186 --- /dev/null +++ b/examples/kubejs/lang.js @@ -0,0 +1,7 @@ +//Needs to be on client_scripts folder! +//Or you can have a client event to add the lang key without needing to do things with .json +//But it might be a more difficult way to translate it with external tools! + +ClientEvents.lang('en_us', event => { + event.add('replication.matter_type.matter_lambda', 'Esto es una tombola, tombola') +}) \ No newline at end of file diff --git a/examples/kubejs/matter_recipes.js b/examples/kubejs/matter_recipes.js new file mode 100644 index 0000000..d2cd419 --- /dev/null +++ b/examples/kubejs/matter_recipes.js @@ -0,0 +1,233 @@ +/* +Needs to be on the server_scripts folder! + +This is the main part about this little guide, how to add matter to items and blocks +There are 2 ways (only for smelting and crafting recipes), they are assigned automatically or manually +By default, you can get calculations up to 11 depth, that means that from log to final item, +there can only be 11 recipes + +For all the other items, you need to add them manually, which is a bit of a bummer, +but thats why we are here + +This example uses Powah's items and blocks, but you can use any other mod! +It applies the same principles! + +Links: +Replication global object -> https://github.com/Buuz135/Replication/blob/1.21/src/main/java/com/buuz135/replication/integration/kubejs/ReplicationKubeJSGateway.java +Registry -> https://github.com/Buuz135/Replication/blob/1.21/src/main/java/com/buuz135/replication/ReplicationRegistry.java + +Currently there are these types: +earth, nether, ender, organic, metallic, precious, living, quantum + +To disable automatic recipes, check configuration (ReplicationConfig.RecipeCalculation) and set MAX_RECIPE_DEPTH to 0 +*/ + +ServerEvents.recipes(event => { + + const ENERGY_TO_MATTER_FACTOR = 0.01;//Since energy is free in most packs, there is a low "efficiency" + + //Lets take dry ice as example, but you can do for another things: + /*{ + "type": "powah:energizing", //recipe type if we need want all recipes from a particular machine + "energy": 120000, //energy cost + "ingredients": [ //An array of items, which you can get the + { + "tag": "c:rods/blaze" + } + ], + "result": { + "count": 1, + "id": "powah:crystal_blazing" + } + } + */ + + //You can have a Set to store the values to store the items you previous did + //to concat them or add compact to mods! + //let matter = new WeakSet() + + //Thats for more advanced setups, if you have recipes calculation on + //Here is getting all recipes from Powah!'s Energizing, which you can add compact this way + + //Here we use the event.custom + //Below this, on another event, there is a builder, sort of nicer way to add matter if you like them! + event.forEachRecipe({ type: 'powah:energizing' }, recipe => { //forEachRecipe is a way to iterate all recipes from a type + let json = recipe.json; + + let energy = json.get('energy'); + if(!energy) + { + console.warn(`Recipe without energy: ${recipe.getId()}`); + return; + } + + //Result + let result = json.get('result'); + if(!result) + { + console.warn(`Recipe without results: ${recipe.getId()}`); + return; + } + + let idElement = result.get('id'); + if(!idElement) + { + console.warn(`No output: ${recipe.getId()}`); + return; + } + let itemId = idElement.getAsString ? idElement.getAsString() : String(idElement).replace("\"", ""); + + let count = 1; + if(result.has('count')) + { + count = result.get('count'); + } + + let matterAmount = energy * ENERGY_TO_MATTER_FACTOR; + let matterMap = { + 'metallic': matterAmount + }; + event.custom(Replication.matterValueForItem(itemId, matterMap)); + }); +}); + +ServerEvents.recipes(event => { + + const MatterBuilder = () => { + let _input = null; + let _inputType = null; // 'item', 'tag', 'ingredient' + let _matterMap = {}; + let _customId = null; + + const defaultId = () => { + if(!_input) return 'unknown'; + let inputStr = _input; + if(typeof _input === 'object') + { + inputStr = _input.item || _input.tag || JSON.stringify(_input); + } + let cleaned = inputStr.toString().replace(/[#]/g, '').replace(/[^a-z0-9_.-]/gi, '_').toLowerCase(); + let matterPart = Object.keys(_matterMap).join('_'); + return `replication:matter_value/${cleaned}_${matterPart}`; + }; + + return { + /** + * @param {string} itemId - ID of the item (e.g: 'minecraft:stone') + */ + withItem(itemId) + { + _input = itemId; + _inputType = 'item'; + return this; + }, + + /** + * @param {string} tag - Tag (e.g: '#c:iron_ingots' or 'c:iron_ingots') + */ + withTag(tag) + { + _input = tag.startsWith('#') ? tag.substring(1) : tag; + _inputType = 'tag'; + return this; + }, + + /** + * @param {Object} ingredient - e.g: { item: 'minecraft:stone' } or { tag: 'c:ingots' } + */ + withIngredient(ingredient) + { + _input = ingredient; + _inputType = 'ingredient'; + return this; + }, + + /** + * Add matter to a recipe + * @param {string} type - Matter key (ej: 'earth', 'metallic') + * @param {number} amount - Amount of matter, must be an integer, will round up for numbers with decimals + */ + addMatter(type, amount) + { + _matterMap[type] = amount; + return this; + }, + + /** + * Asign a id to the recipe and register it. + * @param {string} id - ID of the recipe 'namespace:path' (e.g mymodpack:replication/matter/...) + */ + withId(id) + { + _customId = id; + return this.register() + }, + + /** + * Generate the recipe with default ID, you can use withId to do the same but with an recipe id + * @returns void + */ + register() + { + if(!_input || !_inputType) + { + console.error('[MatterValueBuilder] No input specified. Use withItem, withTag or withIngredient. Skipping'); + return; + } + + if(typeof Replication === 'undefined') + { + console.error('[MatterValueBuilder] Replication object is not available. Is the mod loaded?'); + return; + } + + let recipeJson; + if(_inputType === 'item') + { + recipeJson = Replication.matterValueForItem(_input, _matterMap); //Given a item and a map of matters with amount, return a json object with those matters and item + } + else if(_inputType === 'tag') + { + recipeJson = Replication.matterValueForTag(_input, _matterMap); //Given a tag and a map of matters with amount, return a json object with those matters and tag + } + else + { + recipeJson = Replication.matterValue(_input, _matterMap); //Given an ingredient and a map of matters with amount, return a json object with those matters and ingredient + } + + if(_customId) + { + event.custom(recipeJson).id(_customId); + } + else + { + //KubeJS generate a random recipe id each time, so we would need + //to give an id ourselft or an generated one from inputs + event.custom(recipeJson).id(defaultId()); + } + } + }; + }; + + //This is how to use the builder + MatterBuilder() + .withItem('guideme:guide') + .addMatter('earth', 3.0) //This is fine, since it will transform to 3 + .addMatter('metallic', 1.5) //This is mostly fine, it will transform to 2 + .withId('mypack:replication/guide'); + + //But you can do more with the builder, remember the first setup? Well, we have more, you can use the builder + //to give more or less, depending on what you want! + let a_value = 0 //Lets say that we add a value depending on a variable + let builder = MatterBuilder() + .withItem('replication:matter_blueprint') + .addMatter('earth', 3.0) //This is fine, since it will transform to 3 + .addMatter('metallic', 1.5) //This is mostly fine, it will transform to 2 + + if(a_value < 5) + { + builder.addMatter('ender', 4) + } + + builder.register() +}) \ No newline at end of file diff --git a/examples/kubejs/register_matter.js b/examples/kubejs/register_matter.js new file mode 100644 index 0000000..4d8cd48 --- /dev/null +++ b/examples/kubejs/register_matter.js @@ -0,0 +1,118 @@ +/* +Needs to be on startup_scripts folder! + +Similar to registering items and blocks, we need to do the same +for our matter types + +You must have a .png with the texture on the kubejs/assets/replication/textures/gui/mattertypes/.png +or the game will crash if you open the terminal! + +Links: +ReplicationRegistry -> https://github.com/Buuz135/Replication/blob/1.21/src/main/java/com/buuz135/replication/ReplicationRegistry.java +MatterTypeBuilder -> https://github.com/Buuz135/Replication/blob/1.21/src/main/java/com/buuz135/replication/integration/kubejs/MatterTypeBuilder.java + + +Here is every way you can do it! +*/ +StartupEvents.registry('replication:matter_types', event => { + //The simplest way + event.create("ultimatium") //Id of the matter, we will need it later + .color(0.2, 0.7, 1.0, 1.0) //RGBA (from 0.0 to 1.0) + .displayName("Ultimatum") //Display name + .max(100) //can be any number, doesnt matter + + //The hard way but cool one! + //First we need the builder, we need to load some classes first + const MatterRegistry = Java.loadClass('com.buuz135.replication.ReplicationRegistry') + const MatterTypeBuilder = Java.loadClass('com.buuz135.replication.integration.kubejs.MatterTypeBuilder') + + //You can do something similar as the builder on the matter_recipes.js on server_scripts + let myBuilder = new MatterTypeBuilder('matter_to_add') + myBuilder.color(0.5, 0.1, 0.9, 1.0).max(2500) + event.add(MatterRegistry.MATTER_TYPES_KEY, myBuilder) + + //Another hard way + //This time using a lambda, for customs colors! + //This is how quantum matter type is done! + + //We need to load the classes first + const CustomMatterType = Java.loadClass('com.buuz135.replication.integration.kubejs.CustomMatterType') + const FloatArrayList = Java.loadClass('it.unimi.dsi.fastutil.floats.FloatArrayList'); + //Minecraft class is just to get the time of the day + const Minecraft = Java.loadClass('net.minecraft.client.Minecraft'); + + //In this case, we need an arrow function (a.k.a a lambda), useful if you need to have more complex setups, like this one + //or quantum matter + event.createCustom('matter_lambda', () => { + let name = "matter_lambda" //To give a name, we need a lang file with the following "replication.matter_type.matter_lambda": "Matter Lambda", + + //Dynamic color depending on some conditions + //In this case, depending on the time of the day and a period + //while doing a rainbow + + //At the end, you must have the variable list with 4 values or crash + //RGBA, then convert to float shown on the return + let color = () => { + let list = new FloatArrayList(); + try + { + let level = Minecraft.getInstance().level; + if(level) + { + let time = level.getDayTime(); //MC time, around 60k samples, more than enough for most + let period = 200; //full cycle every 10 seconds (20 ticks/sec) + let hue = (time % period) / period; // 0..1 + + //HSV to RGB (saturation=1, value=1) + let h = hue; + let s = 1.0; + let v = 1.0; + + let r, g, b; + let i = Math.floor(h * 6); + let f = h * 6 - i; + let p = v * (1 - s); + let q = v * (1 - f * s); + let t = v * (1 - (1 - f) * s); + + switch(i % 6) + { + case 0: r = v; g = t; b = p; break; + case 1: r = q; g = v; b = p; break; + case 2: r = p; g = v; b = t; break; + case 3: r = p; g = q; b = v; break; + case 4: r = t; g = p; b = v; break; + case 5: r = v; g = p; b = q; break; + } + + list.add(r); + list.add(g); + list.add(b); + list.add(1.0); //alpha + } + else + { + //A default color just in case level is null + list.add(0.5); + list.add(0.5); + list.add(0.5); + list.add(1.0); + } + } + catch(e) + { + //If any error (e.g., on server or you pass an string to a number), + //return a default color + list.add(1.0); + list.add(1.0); + list.add(1.0); + list.add(1.0); + //console.log(e) //This spam the logs a lot but tells you a lot too + } + return list.toFloatArray(); + }; + + let max = 5000 + return new CustomMatterType(name, color, max) + }) +}) \ No newline at end of file