[5] Initial implementation of some attribute stuff. Nothing in this commit actually works but the game still launches! Will need to move item and armor stuff to a more generic file as well to make it less unique so it can be used broadly. Directory structure extended to add items and resources

[5] **WORKING** add custom item and item group to game. primarily metaljacket items not added yet - but example item works.

[5] initial add of custom blocks

[5] Made adding blocks more dynamic - tested to work

[5] Fixed metal jacket armor & created correct texture files to not break game. TEXTURES ARE RANDOM ON WEARING AS I DONT HAVE AN ACTUAL TEXTURE YET

[5] Started attribute tree stuff

[5] end of day commit. **NOT WORKING**

[5] First successful attribute write using test commandsgit br

[5] one directory for you, and one for you, and one for...

[5] Loot tables, dropping blocks, experience block, example ore block

changes

[5] Documentation. Small command patch to make command treegit br
This commit is contained in:
Jkibbels 2024-08-24 22:21:57 -04:00
parent 6fce9f9bdc
commit b84ebee289
47 changed files with 1242 additions and 47 deletions

View File

@ -0,0 +1,81 @@
package jesse.keeblarcraft.Armor;
import jesse.keeblarcraft.Keeblarcraft;
import net.minecraft.item.ArmorItem;
import net.minecraft.item.ArmorMaterial;
import net.minecraft.item.Items;
import net.minecraft.recipe.Ingredient;
import net.minecraft.sound.SoundEvent;
import net.minecraft.sound.SoundEvents;
public class MetalJacketArmor implements ArmorMaterial {
// All references to this class must refer to this
public static final MetalJacketArmor INSTANCE = new MetalJacketArmor();
int defaultArmorModifier = 3;
/// FUNCTIONS BELOW
public MetalJacketArmor() {
System.out.println("Constructor for armor called");
}
@Override
public int getDurability(ArmorItem.Type type) {
System.out.println("durability for armor called");
// Replace this multiplier by a constant value for the durability of the armor.
// For reference, diamond uses 33 for all armor pieces, whilst leather uses 5.
return switch (type) {
case ArmorItem.Type.BOOTS -> Integer.MAX_VALUE;
case ArmorItem.Type.LEGGINGS -> Integer.MAX_VALUE;
case ArmorItem.Type.CHESTPLATE -> Integer.MAX_VALUE;
case ArmorItem.Type.HELMET -> Integer.MAX_VALUE;
};
}
@Override
public int getProtection(ArmorItem.Type type) {
System.out.println("Protection called");
// Protection values for all the slots.
// For reference, diamond uses 3 for boots, 6 for leggings, 8 for chestplate, and 3 for helmet,
// whilst leather uses 1, 2, 3 and 1 respectively.
return switch (type) {
case ArmorItem.Type.BOOTS -> defaultArmorModifier;
case ArmorItem.Type.HELMET -> defaultArmorModifier;
case ArmorItem.Type.LEGGINGS -> defaultArmorModifier;
case ArmorItem.Type.CHESTPLATE -> defaultArmorModifier;
};
}
@Override
public int getEnchantability() {
return Integer.MAX_VALUE;
}
@Override
public SoundEvent getEquipSound() {
// Example for Iron Armor
return SoundEvents.ITEM_ARMOR_EQUIP_IRON;
}
@Override
public Ingredient getRepairIngredient() {
return Ingredient.ofItems(Items.BEDROCK); // prayfully impossible repair or just not worth it
}
@Override
public String getName() {
return Keeblarcraft.MOD_ID + ":" + "metaljacket";
}
@Override
public float getToughness() {
// Toughness is the actual "resistance" the armor provides to HIGH damage attacks
return (float) defaultArmorModifier;
}
@Override
public float getKnockbackResistance() {
return 0;
}
}

View File

@ -0,0 +1,115 @@
/*
*
* AttributeMgr
*
* Central point for the attribute skill system in the mod
*
*
*/
package jesse.keeblarcraft.AttributeMgr;
import java.util.HashMap;
import jesse.keeblarcraft.Keeblarcraft;
import jesse.keeblarcraft.AttributeMgr.AttributeNodes.AbstractNode;
import jesse.keeblarcraft.AttributeMgr.AttributeNodes.AttributeFlight;
import jesse.keeblarcraft.AttributeMgr.AttributeNodes.AttributeMetalJacket;
import jesse.keeblarcraft.ConfigMgr.ConfigManager;
import jesse.keeblarcraft.Utils.ChatUtil;
public class AttributeMgr {
ConfigManager config;
// Global list of attributes
public static final HashMap<String, Class<? extends AbstractNode>> attributes = new HashMap<String, Class<? extends AbstractNode>>();
// This is a list of all logged in player tree's. These are kept in memory until either the mod is torn down or
// players log out for optimization reasons
public static final HashMap<String, AttributeTree> activeTrees = new HashMap<String, AttributeTree>();
/////////////////////////////////////////////////////////////////////////////
/// @fn RegisterAttributeClass
///
/// @brief All generic class objects for attributes should be
/// registered via this function
/////////////////////////////////////////////////////////////////////////////
@SuppressWarnings("deprecation")
public static void RegisterAttributeClass(Class<? extends AbstractNode> classObj) {
AbstractNode verifyNode = null;
try {
// We spin up an instance of this node; but it will be dead after this function. We need this for name
verifyNode = classObj.newInstance();
} catch (Exception e) {
Keeblarcraft.LOGGER.error("Attempted to assign AbstractNode class type when registering object but could not call .newInstance()! Constructs must be empty");
e.printStackTrace();
}
ChatUtil.LoggerColored("Registring attribute called", ChatUtil.CONSOLE_COLOR.CYAN, Keeblarcraft.LOGGER);
try {
if (attributes.containsKey(verifyNode.GetNodeTitle())) {
Keeblarcraft.LOGGER.warn("Could not register attribute with duplicate name '" + verifyNode.GetNodeTitle() + "'");
} else {
ChatUtil.LoggerColored("REGISTERING ATTRIBUTE " + verifyNode.GetNodeTitle(), ChatUtil.CONSOLE_COLOR.YELLOW, Keeblarcraft.LOGGER);
attributes.put(verifyNode.GetNodeTitle(), classObj);
}
} catch (Exception e) {} // Left empty since previous try-catch will throw error-message
}
/////////////////////////////////////////////////////////////////////////////
/// @fn ApplyAttribute
///
/// @arg[in] uuid is the players uuid
///
/// @arg[in] attributeName is the node title of the attribute class object
///
/// @brief Used to apply an attribute to a player's attribute tree
/////////////////////////////////////////////////////////////////////////////
@SuppressWarnings("deprecation")
public static String ApplyAttribute(String uuid, String attributeName) {
String msg = "";
if (attributes.containsKey(attributeName)) {
AttributeTree playerTree = activeTrees.get(uuid);
AbstractNode node = null;
try {
node = attributes.get(attributeName).newInstance();
} catch (Exception e) {
Keeblarcraft.LOGGER.error("Could not successfully apply attribute. String of attribute name could not be successfully cast to actual java object");
}
if (playerTree != null && node != null) {
///////////
// debug testing
String isNull = (node == null ? "NULL" : "NOT NULL");
System.out.println("Node is " + isNull);
if (isNull.equals("NOT NULL")) { System.out.println("Node name: " + node.GetNodeTitle()); }
// end debug testing
///////////
playerTree.AddNewNode(node, 1, null, null);
msg = "Applied attribute '" + attributeName + "' successfully";
} else {
msg = "Player tree not found!";
}
} else {
msg = "Could not apply attribute, attribute name does not exist!";
}
return msg;
}
/////////////////////////////////////////////////////////////////////////////
/// @fn RegisterAttributes
///
/// @brief This registers all attribute classes to the global attribute
/// class. Individual classes can be added here that call the
/// more braod "RegisterAttributeClass"
/// @see RegisterAttributeClass
/////////////////////////////////////////////////////////////////////////////
public static void RegisterAttributes() {
// Manually register all attribute node classes here
/// TODO: Find a better way to do this more dynamically in the future
RegisterAttributeClass(AttributeFlight.class);
RegisterAttributeClass(AttributeMetalJacket.class);
}
}

View File

@ -0,0 +1,52 @@
/*
*
* AbstractNode
*
* This is the general definition of everything that is allowed inside a node and is called by our system
*
*
*/
package jesse.keeblarcraft.AttributeMgr.AttributeNodes;
import java.util.HashMap;
import java.util.List;
abstract public class AbstractNode {
/////////////////////////////////////////////////////////////////////////////
/// @fn GetNodeTitle
///
/// @brief The title of your node/skill!
/////////////////////////////////////////////////////////////////////////////
public abstract String GetNodeTitle();
/////////////////////////////////////////////////////////////////////////////
/// @fn GetNodeDescription
///
/// @brief This will become the hover-over text display of a skill in
/// the skill tree
/////////////////////////////////////////////////////////////////////////////
public abstract String GetNodeDescription();
/////////////////////////////////////////////////////////////////////////////
/// @fn GetDetails
///
/// @brief This is the general details that may be displayed inside the
/// GUI when the skill tree becomes available to a player. The
/// object is suggested to be treated as such:
///
/// KEY (String) -> The title of an effect/attribute
/// VAL (List<String>) -> Treated as a list of description
/// attributes. 1 string per description
/////////////////////////////////////////////////////////////////////////////
public abstract HashMap<String, List<String>> GetDetails();
/////////////////////////////////////////////////////////////////////////////
/// @fn RegisterCallbacks
///
/// @brief If your node has responsive callbacks; then this is the area
/// you will register your callbacks for everything
/////////////////////////////////////////////////////////////////////////////
public abstract void RegisterCallbacks();
}

View File

@ -0,0 +1,68 @@
/*
*
* AttributeFlight
*
* The flight attribute
*
*
*/
package jesse.keeblarcraft.AttributeMgr.AttributeNodes;
import java.util.HashMap;
import java.util.List;
import net.fabricmc.fabric.api.event.player.AttackBlockCallback;
import net.minecraft.block.BlockState;
import net.minecraft.util.ActionResult;
public class AttributeFlight extends AbstractNode {
Boolean registeredHitCallback = false;
public AttributeFlight() {
}
@Override
public String GetNodeTitle() {
return "attribute_low_health_flight";
}
@Override
public String GetNodeDescription() {
return "Gives player flight with low health";
}
@Override
public HashMap<String, List<String>> GetDetails() {
HashMap<String, List<String>> ret = new HashMap<String, List<String>>();
// Filling out description item stuff here
ret.put("Flight", List.of (
"Gives a player natural flight if they have less than or equal to two hearts remaining"
));
return ret;
}
@Override
public void RegisterCallbacks() {
// Register events here
if (registeredHitCallback == false) {
AttackBlockCallback.EVENT.register((player, world, hand, pos, direction) -> {
BlockState state = world.getBlockState(pos);
// Manual spectator check is necessary because AttackBlockCallbacks fire before the spectator check
if (!player.isSpectator() && player.getMainHandStack().isEmpty() && state.isToolRequired()) {
player.damage(world.getDamageSources().generic(), 1.0F);
}
return ActionResult.PASS;
});
}
registeredHitCallback = true;
}
}

View File

@ -0,0 +1,56 @@
package jesse.keeblarcraft.AttributeMgr.AttributeNodes;
import java.util.HashMap;
import java.util.List;
import jesse.keeblarcraft.Keeblarcraft;
import jesse.keeblarcraft.Armor.MetalJacketArmor;
import jesse.keeblarcraft.CustomItems.ItemManager;
import net.minecraft.item.ArmorItem;
import net.minecraft.item.Item;
public final class AttributeMetalJacket extends AbstractNode {
// This is the custom armor set that players will receive if no armor is on & attribute is equipped
public final Item jacketHelm = new ArmorItem(MetalJacketArmor.INSTANCE, ArmorItem.Type.HELMET, new Item.Settings());
public final Item jacketChest = new ArmorItem(MetalJacketArmor.INSTANCE, ArmorItem.Type.CHESTPLATE, new Item.Settings());
public final Item jacketLegs = new ArmorItem(MetalJacketArmor.INSTANCE, ArmorItem.Type.LEGGINGS, new Item.Settings());
public final Item jacketBoots = new ArmorItem(MetalJacketArmor.INSTANCE, ArmorItem.Type.BOOTS, new Item.Settings());
public AttributeMetalJacket() {
// Finally register items with game
Keeblarcraft.LOGGER.debug("Registering metaljackets");
ItemManager.RegisterItem("metaljacket_helmet", jacketHelm);
ItemManager.RegisterItem("metaljacket_chestplate", jacketChest);
ItemManager.RegisterItem("metaljacket_leggings", jacketLegs);
ItemManager.RegisterItem("metaljacket_boots", jacketBoots);
}
@Override
public String GetNodeTitle() {
return "MetalJacket";
}
// Short description of node on hover-event in GUI
@Override
public String GetNodeDescription() {
return "MetalJacket affects armor value modifiers or gives player base armor when none is worn";
}
// Detailed description of node on click-event in GUI
@Override
public HashMap<String, List<String>> GetDetails() {
HashMap<String, List<String>> ret = new HashMap<String, List<String>>();
// Filling out description item stuff here
ret.put("durability", List.of (
"Gives player a base armor set with 3 protection and resistance",
"If armor is being worn, this attribute multiplies each pieces armor value by 120% (rounding up to nearest integer)"
));
return ret;
}
@Override
public void RegisterCallbacks() {
}
}

View File

@ -0,0 +1,322 @@
/*
*
* AttributeTree
*
* Handles a players individual attribute tree
*
*
*/
package jesse.keeblarcraft.AttributeMgr;
import java.util.ArrayList;
import java.util.List;
import java.util.Map.Entry;
import java.util.HashMap;
import jesse.keeblarcraft.Keeblarcraft;
import jesse.keeblarcraft.AttributeMgr.AttributeNodes.AbstractNode;
import jesse.keeblarcraft.ConfigMgr.ConfigManager;
import jesse.keeblarcraft.Utils.ChatUtil;
import jesse.keeblarcraft.Utils.ChatUtil.CONSOLE_COLOR;
import jesse.keeblarcraft.Utils.CustomExceptions.FILE_WRITE_EXCEPTION;
public class AttributeTree {
PlayerTree playerAttributeTree = new PlayerTree();
ConfigManager config = new ConfigManager();
private AbstractNode root = new RootNode();
/////////////////////////////////////////////////////////////////////////////
/// @class TreeNode
///
/// @brief This is an individual node that goes within the larger
/// PlayerTree class object
/////////////////////////////////////////////////////////////////////////////
private class TreeNode {
public TreeNode(AbstractNode node, Integer maxLevel, List<String> parents, List<String> children) {
thisNode = node;
parentNodes = parents;
childrenNodes = children;
maxNodeLevel = maxLevel;
currentNodeLevel = 1;
}
AbstractNode thisNode;
Integer currentNodeLevel;
Integer maxNodeLevel;
// Store the names of the parent and children nodes; this lets a node have any number of parents and children
// NOTE TO DEVELOPERS: Be aware! The more nodes the harrier the tree will look in the GUI!!! Always test your
// code before just adding stuff willy-nilly!
List<String> parentNodes;
List<String> childrenNodes;
}
/////////////////////////////////////////////////////////////////////////////
/// @class PlayerTree
///
/// @brief This is the tree object of a given player. It contains all
/// valid attribute information for a player that is statically
/// stored inside the AttributeMgr class
/////////////////////////////////////////////////////////////////////////////
private class PlayerTree {
String uuid;
// Key = name of AbstractNode
// Val = The attribute itself
HashMap<String, TreeNode> tree = new HashMap<String, TreeNode>();
}
/////////////////////////////////////////////////////////////////////////////
/// @class RootNode
///
/// @brief This is the default root node of a tree. It is mostly left
/// blank and used to code around as an "anchor" object
/////////////////////////////////////////////////////////////////////////////
private class RootNode extends AbstractNode {
@Override
public String GetNodeTitle() {
return "root";
}
@Override
public String GetNodeDescription() {
return "This is the players tree root! All attributes extend from here";
}
@Override
public HashMap<String, List<String>> GetDetails() {
HashMap<String, List<String>> ret = new HashMap<String, List<String>>();
ret.put("First Attribute", List.of("This is your skill tree", "All attributes grow from this root! Unlocking nodes requires all nodes connected to that previously to be unlocked first"));
return ret;
}
@Override
public void RegisterCallbacks() {
}
}
/////////////////////////////////////////////////////////////////////////////
/// @fn RegisterActiveCallbacks
///
/// @brief This will register all the active callbacks on all nodes that
/// are unlocked within a players tree instance
/////////////////////////////////////////////////////////////////////////////
public void RegisterActiveCallbacks() {
for(Entry<String, TreeNode> tree : playerAttributeTree.tree.entrySet()) {
if (tree.getValue().currentNodeLevel != 0) {
// We need to construct the node object if it's null. If it's not null; we assume
// the callback registration process has already happened
if (tree.getValue().thisNode == null) {
System.out.println("REGISTERACTIVECALLBACKS - NULL NODE");
tree.getValue().thisNode.RegisterCallbacks();
} else {
System.out.println("REGISTERACTIVECALLBACKS - NOT NULL NODE");
}
}
}
}
/////////////////////////////////////////////////////////////////////////////
/// @fn AddNewNode
///
/// @arg[in] newNode is the attribute node to be added to the player tree
///
/// @arg[in] maxNodeLevel is the max level of the node
///
/// @arg[in] parents is the list of parent attributes. If empty,
/// root is default
///
/// @arg[in] children is the list of children attributes.
/// Root cannot be child
///
/// @brief Add a new node to the tree arbitrarily. Root can never be a
/// child node parents can never be empty or null (null or empty
/// would imply you are adding root)
///
/// @note developer warning: you must personally verify your nodes are
/// in the tree. anywhere is fine, and the tree is very dynamic
/// (which is why self verification is required). When the tree
/// is drawn in the GUI, it starts from the root node. As long as
/// your node is attached to this node anywhere in the indirected
/// graph; then your attribute will be drawn in the gui
/////////////////////////////////////////////////////////////////////////////
public Boolean AddNewNode(AbstractNode newNode, Integer maxNodeLevel, List<String> parents, List<String> children) {
Boolean ret = false;
TreeNode nodeReference = playerAttributeTree.tree.get(newNode.GetNodeTitle());
System.out.println("Is node reference null? -> " + (nodeReference == null ? "YES":"NO"));
System.out.println("Is root reference null? -> " + (root == null ? "YES":"NO"));
System.out.println("Is parents null? -> " + (parents == null ? "YES":"NO"));
// Some special handling is required on checking child list in case it is null
Boolean validChildren = true;
if (children != null) {
validChildren = !children.contains(root.GetNodeTitle());
}
if (nodeReference == null && validChildren) {
// Since these values can be left as null, we want to guarentee they are at least initialized here
maxNodeLevel = (maxNodeLevel == null ? 1 : maxNodeLevel);
parents = (parents == null ? new ArrayList<String>() : parents);
children = (children == null ? new ArrayList<String>() : children);
if (parents.size() == 0) {
parents.add(root.GetNodeTitle()); // No disconnected nodes allowed! All parentless nodes are adopted by root by default
}
// Node implementation here
playerAttributeTree.tree.put(newNode.GetNodeTitle(), new TreeNode(newNode, maxNodeLevel, parents, children));
// if the new nodes level is not 0 we need to manually register the callbacks
if (playerAttributeTree.tree.get(newNode.GetNodeTitle()).currentNodeLevel != 0) {
System.out.println("Registering new callback for new node");
playerAttributeTree.tree.get(newNode.GetNodeTitle()).thisNode.RegisterCallbacks();
}
} else {
// Some fancy error handling for console log
if (nodeReference != null) {
Keeblarcraft.LOGGER.error("Attribute with name " + newNode.GetNodeTitle() + " was already found within the tree! Rename your node to add it");
} else {
Keeblarcraft.LOGGER.error("The attribute you attempted to add (name: " + newNode.GetNodeTitle() + "), has root in the children");
}
ret = false;
}
FlashConfig();
return ret;
}
/////////////////////////////////////////////////////////////////////////////
/// @fn ChangeNodeLevel
///
/// @arg[in] nodeName is the attribute node title
///
/// @arg[in] newLevel is the new level you wish to grant the node
///
/// @brief If you wish to change the level of an attribute, you can use
/// this function to do so
/////////////////////////////////////////////////////////////////////////////
public void ChangeNodeLevel(String nodeName, Integer newLevel) {
TreeNode nodeReference = playerAttributeTree.tree.get(nodeName);
if (nodeReference != null) {
if (newLevel <= nodeReference.maxNodeLevel) {
nodeReference.currentNodeLevel = newLevel;
}
}
FlashConfig();
}
/////////////////////////////////////////////////////////////////////////////
/// @fn DeleteNode
///
/// @arg[in] nodeName is the attribute node title
///
/// @brief Delete a node via the name
/////////////////////////////////////////////////////////////////////////////
public void DeleteNode(String nodeName) {
// Do not delete root!
if (nodeName != root.GetNodeTitle()) {
playerAttributeTree.tree.remove(nodeName);
}
FlashConfig();
}
/////////////////////////////////////////////////////////////////////////////
/// @fn GetNodeDetails
///
/// @arg[in] nodeName is the attribute node title
///
/// @brief Returns the detail map from the attribute if it has any
/////////////////////////////////////////////////////////////////////////////
public HashMap<String, List<String>> GetNodeDetails(String nodeName) {
HashMap<String, List<String>> ret = null;
TreeNode nodeReference = playerAttributeTree.tree.get(nodeName);
if (nodeReference != null) {
ret = nodeReference.thisNode.GetDetails();
}
return ret;
}
/////////////////////////////////////////////////////////////////////////////
/// @fn GetPlayerTree
///
/// @brief Returns the player tree. Will be deprecated in use of the
/// static active user map list instead for performance reasons
/////////////////////////////////////////////////////////////////////////////
@Deprecated
public PlayerTree GetPlayerTree() {
return playerAttributeTree;
}
/////////////////////////////////////////////////////////////////////////////
/// @fn AttributeTree
///
/// @arg[in] uuid is the player uuid
///
/// @brief Constructor for class
/////////////////////////////////////////////////////////////////////////////
public AttributeTree(String uuid) {
// DEVELOPER NOTE:
// If you are testing this part of the code, please be reminded that anonymous testing starts a new
// player instance everytime you launch. This means the UUID CAN CHANGE when you launch the
// game! This is not an issue with proper registered accounts in production
Boolean existingFile = false;
try {
playerAttributeTree = config.GetJsonObjectFromFile("attributes/" + uuid + ".json", PlayerTree.class);
existingFile = true;
} catch (Exception e) {
// Do nothing. This means the file does not exist
}
// In the event the above code failed out, this means a new file has to be created for the player's uuid
if (!existingFile)
{
System.out.println(ChatUtil.ColoredString("Trying to create new file", CONSOLE_COLOR.BLUE));
try {
playerAttributeTree.uuid = uuid;
FlashConfig();
} catch (Exception e) {
System.out.println(ChatUtil.ColoredString("Could not write to file", CONSOLE_COLOR.RED));
}
} else {
System.out.println(ChatUtil.ColoredString("Moving on", CONSOLE_COLOR.BLUE));
}
// It's possible the above code will return a blank class if a file doesn't exist. This will make
// a new file with this players uuid
if ("".equals(playerAttributeTree.uuid)) {
System.out.println(ChatUtil.ColoredString("Assigning new config file for this uuid. No previous existing", CONSOLE_COLOR.BLUE));
playerAttributeTree.uuid = uuid;
}
// If the tree is empty or missing root, add it!
if (playerAttributeTree.tree.size() == 0 || playerAttributeTree.tree.containsKey(root.GetNodeTitle()) == false) {
playerAttributeTree.tree.put(root.GetNodeTitle(), new TreeNode(root, 1, null, null));
}
RegisterActiveCallbacks();
}
/////////////////////////////////////////////////////////////////////////////
/// @fn FlashConfig
///
/// @brief Flashes the config to the disk
/////////////////////////////////////////////////////////////////////////////
public void FlashConfig() {
try {
config.WriteToJsonFile("attributes/" + playerAttributeTree.uuid + ".json", playerAttributeTree);
} catch (FILE_WRITE_EXCEPTION e) {
System.out.println(ChatUtil.ColoredString("Could not flash notes configuration file", CONSOLE_COLOR.RED));
}
}
}

View File

@ -0,0 +1,115 @@
/*
*
* AttributeCommands
*
* This class handles all the possible in-game commands for the attribute system
*
*
*/
package jesse.keeblarcraft.Commands;
import java.util.Map.Entry;
import com.mojang.brigadier.arguments.StringArgumentType;
import com.mojang.brigadier.context.CommandContext;
import jesse.keeblarcraft.Keeblarcraft;
import jesse.keeblarcraft.AttributeMgr.AttributeMgr;
import jesse.keeblarcraft.AttributeMgr.AttributeNodes.AbstractNode;
import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback;
import net.minecraft.command.argument.EntityArgumentType;
import net.minecraft.server.command.CommandManager;
import net.minecraft.server.command.ServerCommandSource;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.text.Text;
public class AttributeCommands {
public void RegisterCommands() {
// Command Root: "/attributes"
// Subcommands: "apply <name> <attributename>", "remove <name> <attributename>"
CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) -> {
var attributeNode = CommandManager.literal("attributes").build();
var applyNode = CommandManager.literal("apply").build();
var removeNode = CommandManager.literal("delete").build();
var listNode = CommandManager.literal("list").executes(context -> ListAttributes(context)).build();
var playerArgAdd = CommandManager.argument("targetPlayer", EntityArgumentType.player()).build();
var playerArgRemove = CommandManager.argument("targetPlayer", EntityArgumentType.player()).build();
var attributeNameAdd = CommandManager.argument("attributeName", StringArgumentType.greedyString())
.executes(context -> ApplyAttribute
(
EntityArgumentType.getPlayer(context, "targetPlayer"),
StringArgumentType.getString(context, "attributeName"),
context)
)
.build();
var attributeNameDelete = CommandManager.argument("attributeName", StringArgumentType.greedyString())
.executes(context -> DeleteAttribute
(
EntityArgumentType.getPlayer(context, "targetPlayer"),
StringArgumentType.getString(context, "attributeName"),
context)
)
.build();
// Build out the argument tree here
dispatcher.getRoot().addChild(attributeNode);
attributeNode.addChild(applyNode);
attributeNode.addChild(listNode);
attributeNode.addChild(removeNode);
// Subcommands "/apply playerArg", "/remove playerArg"
applyNode.addChild(playerArgAdd);
removeNode.addChild(playerArgRemove);
// name argument
playerArgAdd.addChild(attributeNameAdd);
playerArgRemove.addChild(attributeNameDelete);
});
}
public int ApplyAttribute(ServerPlayerEntity targetPlayer, String attributeName, CommandContext<ServerCommandSource> context) {
int ret = -1;
System.out.println("Applying attribute");
if (context.getSource().isExecutedByPlayer()) {
System.out.println("Executed by player");
// String result = AttributeMgr.ApplyAttribute(targetPlayer.getUuidAsString(), attributeName);
String result = AttributeMgr.ApplyAttribute(context.getSource().getPlayer().getUuidAsString(), attributeName);
Keeblarcraft.LOGGER.info("[ApplyAttribute] -> " + result);
context.getSource().getPlayer().sendMessage(Text.of(result));
ret = 0;
}
return ret;
}
public int DeleteAttribute(ServerPlayerEntity username, String attributeName, CommandContext<ServerCommandSource> context) {
int ret = -1;
return ret;
}
public int ListAttributes(CommandContext<ServerCommandSource> context) {
int ret = -1;
if (context.getSource().isExecutedByPlayer()) {
ServerPlayerEntity player = context.getSource().getPlayer();
for (Entry<String, Class<? extends AbstractNode>> entry : AttributeMgr.attributes.entrySet()) {
Keeblarcraft.LOGGER.debug("ATTR-LIST: " + entry.getKey() + " LINKS " + entry.getValue());
player.sendMessage(Text.of(entry.getKey()));
}
}
return ret;
}
}

View File

@ -21,12 +21,14 @@ public class CustomCommandManager {
ShortcutCommands shortcuts = new ShortcutCommands(); ShortcutCommands shortcuts = new ShortcutCommands();
NoteCommands noteCommands = new NoteCommands(); NoteCommands noteCommands = new NoteCommands();
BankCommands bankCommands = new BankCommands(); BankCommands bankCommands = new BankCommands();
AttributeCommands attributeCommands = new AttributeCommands();
// REGISTER COMMANDS BELOW // REGISTER COMMANDS BELOW
System.out.println(ChatUtil.ColoredString("REGISTERING CUSTOM COMMAND EXTENSIONS BELOW", CONSOLE_COLOR.BLUE)); System.out.println(ChatUtil.ColoredString("REGISTERING CUSTOM COMMAND EXTENSIONS BELOW", CONSOLE_COLOR.BLUE));
shortcuts.RegisterShortcutCommands(); shortcuts.RegisterShortcutCommands();
noteCommands.RegisterNoteCommands(); noteCommands.RegisterNoteCommands();
bankCommands.RegisterCommands(); bankCommands.RegisterCommands();
attributeCommands.RegisterCommands();
} }
} }

View File

@ -4,6 +4,8 @@
* *
* A class that simplifies some of the current vanilla commands with shortcut commands in the game. You may remember an old plugin * A class that simplifies some of the current vanilla commands with shortcut commands in the game. You may remember an old plugin
* called "Essentials" (Or EssentialsEx in a later version) -> This file is re-creating a portion of that plugin but in mod-format * called "Essentials" (Or EssentialsEx in a later version) -> This file is re-creating a portion of that plugin but in mod-format
*
*
*/ */
package jesse.keeblarcraft.Commands; package jesse.keeblarcraft.Commands;

View File

@ -12,7 +12,6 @@
package jesse.keeblarcraft.ConfigMgr; package jesse.keeblarcraft.ConfigMgr;
import java.io.FileWriter; import java.io.FileWriter;
import java.io.FileReader;
import java.io.File; import java.io.File;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
import java.io.IOException; import java.io.IOException;
@ -21,27 +20,19 @@ import com.google.common.base.Charsets;
import com.google.common.io.Files; import com.google.common.io.Files;
import com.google.gson.Gson; import com.google.gson.Gson;
import com.google.gson.GsonBuilder; import com.google.gson.GsonBuilder;
import com.google.gson.JsonArray;
import com.google.gson.JsonIOException; import com.google.gson.JsonIOException;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.google.gson.JsonSyntaxException; import com.google.gson.JsonSyntaxException;
import java.util.List; import java.util.List;
import org.apache.commons.io.FileUtils; import org.apache.commons.io.FileUtils;
import org.spongepowered.asm.mixin.injection.struct.InjectorGroupInfo.Map;
import java.util.ArrayList; import java.util.ArrayList;
import jesse.keeblarcraft.Utils.ChatUtil; import jesse.keeblarcraft.Utils.ChatUtil;
import jesse.keeblarcraft.Utils.ChatUtil.CONSOLE_COLOR; import jesse.keeblarcraft.Utils.ChatUtil.CONSOLE_COLOR;
// Import all custom exceptions
import jesse.keeblarcraft.Utils.CustomExceptions.*; import jesse.keeblarcraft.Utils.CustomExceptions.*;
//minecraft server instance
import net.minecraft.server.MinecraftServer;
public class ConfigManager { public class ConfigManager {
// Pedantic empty constructor // Pedantic empty constructor

View File

@ -0,0 +1,79 @@
/*
*
* BlockManager
*
* The mod block manager
*
*
*/
package jesse.keeblarcraft.CustomBlocks;
import java.util.ArrayList;
import java.util.List;
import jesse.keeblarcraft.Keeblarcraft;
import net.fabricmc.fabric.api.item.v1.FabricItemSettings;
import net.fabricmc.fabric.api.object.builder.v1.block.FabricBlockSettings;
import net.minecraft.block.Block;
import net.minecraft.block.Blocks;
import net.minecraft.block.ExperienceDroppingBlock;
import net.minecraft.item.BlockItem;
import net.minecraft.registry.Registries;
import net.minecraft.registry.Registry;
import net.minecraft.sound.BlockSoundGroup;
import net.minecraft.util.Identifier;
import net.minecraft.util.math.intprovider.UniformIntProvider;
public class BlockManager {
/// The block list. DO NOT ADD TO THE LIST YOURSELF. USE
/// THE RegisterBlock(...) FUNCTION OTHERWISE YOUR BLOCK WILL
/// NOT BE REGISTERED PROPERLY AND MAY BREAK THE GAME
public static final List<Block> blockList = new ArrayList<Block>();
/////////////////////////////////////////////////////////////////////////////
/// @fn RegisterBlock
///
/// @arg[in] name is the block name. IMPORTANT: Name must adhere to rules:
/// 1. The name provided here must match these names:
/// * This blocks models/block name
/// * This blocks textures/block name
/// 2 Name must be lowercase & no special characters besides '_'
///
/// @arg[in] block is the block to be added to the block list
///
/// @brief This is the call to register your block to the game! Please
/// do not forget to update the models/block json file, the
/// textures/block png name, and finally the lang/en_us.json file
/////////////////////////////////////////////////////////////////////////////
public static void RegisterBlock(String name, Block block) {
// This call registers the block as an item in inventories
Registry.register(Registries.ITEM, new Identifier(Keeblarcraft.MOD_ID, name), new BlockItem(block, new FabricItemSettings()));
// This call registers the block as placed
Block newBlock = Registry.register(Registries.BLOCK, new Identifier(Keeblarcraft.MOD_ID, name), block);
// Add the block to the block list
blockList.add(newBlock);
}
/////////////////////////////////////////////////////////////////////////////
/// @fn RegisterBlocks
///
/// @brief This function is only meant to be called by the main mod
/// execution path and should only be called once. This is a
/// glorified print statement - but also serves to add the
/// example block in the game
/////////////////////////////////////////////////////////////////////////////
public static void RegisterBlocks() {
Keeblarcraft.LOGGER.info("Registering modded blocks for " + Keeblarcraft.MOD_ID);
// Register example block to the mod
Block exampleBlock = new Block(FabricBlockSettings.copyOf(Blocks.IRON_BLOCK).sounds(BlockSoundGroup.AMETHYST_BLOCK).requiresTool().breakInstantly());
Block exampleBlockOre = new ExperienceDroppingBlock(FabricBlockSettings.copyOf(Blocks.IRON_BLOCK).sounds(BlockSoundGroup.ANCIENT_DEBRIS).requiresTool(), UniformIntProvider.create(4, 20));
RegisterBlock("example_block_ore", exampleBlockOre);
RegisterBlock("example_block", exampleBlock);
}
}

View File

@ -0,0 +1,41 @@
package jesse.keeblarcraft.CustomItems;
import jesse.keeblarcraft.Keeblarcraft;
import jesse.keeblarcraft.CustomBlocks.BlockManager;
import net.fabricmc.fabric.api.itemgroup.v1.FabricItemGroup;
import net.minecraft.item.ItemGroup;
import net.minecraft.item.ItemStack;
import net.minecraft.item.Items;
import net.minecraft.registry.Registries;
import net.minecraft.registry.Registry;
import net.minecraft.text.Text;
import net.minecraft.util.Identifier;
public class CustomItemGroups {
// This is the custom mod group for the mod
public static final ItemGroup MOD_GROUP = Registry.register(Registries.ITEM_GROUP,
new Identifier(Keeblarcraft.MOD_ID, "keeblarcraft"),
FabricItemGroup.builder().displayName(Text.translatable("itemgroup.keeblarcraft"))
.icon(() -> new ItemStack(Items.ANVIL)).entries((displayContext, entries) -> {
// We iterate through all the modded items and add them to the custom item group here
for (int i = 0; i < ItemManager.itemList.size(); i++) {
entries.add(ItemManager.itemList.get(i));
}
// We iterate through all the modded blocks and add them to the custom block group here
for (int i = 0; i < BlockManager.blockList.size(); i++) {
entries.add(BlockManager.blockList.get(i));
}
}).build());
/////////////////////////////////////////////////////////////////////////////
/// @fn RegisterGroups
///
/// @brief Glorified print statement that the class has initialized
/// basically - meaning that all item groups have registered
/////////////////////////////////////////////////////////////////////////////
public static void RegisterGroups() {
Keeblarcraft.LOGGER.info("Registering item groups for " + Keeblarcraft.MOD_ID);
}
}

View File

@ -0,0 +1,70 @@
/*
*
* ItemManager
*
* This is the general purpose item manager for the mod. All items will be registered through
* this class in order to make custom items a lot cleaner to make!
*
*
*/
package jesse.keeblarcraft.CustomItems;
import java.util.ArrayList;
import java.util.List;
import jesse.keeblarcraft.Keeblarcraft;
import net.fabricmc.fabric.api.item.v1.FabricItemSettings;
import net.minecraft.item.Item;
import net.minecraft.registry.Registries;
import net.minecraft.registry.Registry;
import net.minecraft.util.Identifier;
public class ItemManager {
/// The item list. DO NOT ADD TO THE LIST YOURSELF. USE
/// THE RegisterItem(...) FUNCTION OTHERWISE YOUR ITEM WILL
/// NOT BE REGISTERED PROPERLY AND MAY BREAK THE GAME
public static final List<Item> itemList = new ArrayList<Item>();
/////////////////////////////////////////////////////////////////////////////
/// @fn RegisterItem
///
/// @arg[in] name is the item name. IMPORTANT: Name must adhere to rules:
/// 1. The name provided here must match these names:
/// * This items models/item name
/// * This items textures/item name
/// 2 Name must be lowercase & no special characters besides '_'
///
/// @arg[in] item is the item to be added to the item list
///
/// @brief This is the call to register your item to the game! Please
/// do not forget to update the models/item json file, the
/// textures/item png name, and finally the lang/en_us.json file
/////////////////////////////////////////////////////////////////////////////
public static void RegisterItem(String name, Item item) {
Item newItem = Registry.register(Registries.ITEM, new Identifier(Keeblarcraft.MOD_ID, name), item);
itemList.add(newItem);
}
/////////////////////////////////////////////////////////////////////////////
/// @fn RegisterAllItems
///
/// @brief This function is only meant to be called by the main mod
/// execution path and should only be called once. This is a
/// glorified print statement - but also serves to add the
/// example item in the game
/////////////////////////////////////////////////////////////////////////////
public static void RegisterAllItems() {
Keeblarcraft.LOGGER.info("Registering mod items for " + Keeblarcraft.MOD_ID);
// Call the item group register function first
CustomItemGroups.RegisterGroups();
// The example item provides a demo of how you could make an item in your class
// Item exampleItem = new Item(new FabricItemSettings());
// RegisterItem("metaljacket_helmet", exampleItem);
}
}

View File

@ -10,6 +10,7 @@
package jesse.keeblarcraft.EventMgr; package jesse.keeblarcraft.EventMgr;
public class EventManager { public class EventManager {
} }

View File

@ -1,20 +1,21 @@
package jesse.keeblarcraft; package jesse.keeblarcraft.EventMgr;
import jesse.CommonServerUtils; import jesse.CommonServerUtils;
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerTickEvents; import net.fabricmc.fabric.api.event.lifecycle.v1.ServerTickEvents;
import net.minecraft.server.MinecraftServer; import net.minecraft.server.MinecraftServer;
//this lets get the MinecraftServer instance and also do stuff on the end of the tick if we wanted to // This interface is responsible for the end tick of a server world event tick
public class ServerTickListener implements ServerTickEvents.EndTick { public class ServerTickListener implements ServerTickEvents.EndTick {
CommonServerUtils config = new CommonServerUtils(); CommonServerUtils config = new CommonServerUtils();
@Override @Override
public void onEndTick(MinecraftServer server) { public void onEndTick(MinecraftServer server) {
//Code that runs on end of each tick yes this actually works and tested if (server != null) {
config.SetServerInstance(server); config.SetServerInstance(server);
} }
}
// Static method to register the server tick listener // Static method to register the server tick listener
public static void initialize() { public static void InitializeServerTicks() {
ServerTickEvents.END_SERVER_TICK.register(new ServerTickListener()); ServerTickEvents.END_SERVER_TICK.register(new ServerTickListener());
} }
} }

View File

@ -12,23 +12,25 @@
package jesse.keeblarcraft; package jesse.keeblarcraft;
import net.fabricmc.api.ModInitializer; import net.fabricmc.api.ModInitializer;
// import net.minecraft.server.command.ServerCommandSource;
import net.fabricmc.fabric.api.networking.v1.ServerPlayConnectionEvents;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import jesse.keeblarcraft.AttributeMgr.AttributeMgr;
import jesse.keeblarcraft.AttributeMgr.AttributeTree;
import jesse.keeblarcraft.Commands.CustomCommandManager; import jesse.keeblarcraft.Commands.CustomCommandManager;
import jesse.keeblarcraft.CustomBlocks.BlockManager;
import jesse.keeblarcraft.CustomItems.ItemManager;
import jesse.keeblarcraft.EventMgr.ServerTickListener;
import jesse.keeblarcraft.Utils.CustomExceptions.SETUP_FAILED_EXCEPTION; import jesse.keeblarcraft.Utils.CustomExceptions.SETUP_FAILED_EXCEPTION;
import jesse.keeblarcraft.Utils.ChatUtil; import jesse.keeblarcraft.Utils.ChatUtil;
import jesse.keeblarcraft.Utils.Setup; import jesse.keeblarcraft.Utils.Setup;
import jesse.keeblarcraft.Utils.ChatUtil.CONSOLE_COLOR; import jesse.keeblarcraft.Utils.ChatUtil.CONSOLE_COLOR;
// import com.mojang.brigadier.Command;
public class Keeblarcraft implements ModInitializer { public class Keeblarcraft implements ModInitializer {
// This logger is used to write text to the console and the log file. public static String MOD_ID = "keeblarcraft";
// It is considered best practice to use your mod id as the logger's name.
// That way, it's clear which mod wrote info, warnings, and errors.
public static final Logger LOGGER = LoggerFactory.getLogger("keeblarcraft"); public static final Logger LOGGER = LoggerFactory.getLogger("keeblarcraft");
CustomCommandManager cmdMgr = new CustomCommandManager(); CustomCommandManager cmdMgr = new CustomCommandManager();
@ -47,10 +49,45 @@ public class Keeblarcraft implements ModInitializer {
LOGGER.info("\033[34m Running setup stage \033[0m"); LOGGER.info("\033[34m Running setup stage \033[0m");
setup.RunSetup(); setup.RunSetup();
// This is a very special case where this must be in this classes' initializer
// method
ServerPlayConnectionEvents.JOIN.register((handler, sender, server) -> {
var player = handler.player;
Keeblarcraft.LOGGER.info("Player " + player.getName() + " has logged in. Creating tree...");
if (AttributeMgr.activeTrees.containsKey(player.getUuidAsString()) == false) {
AttributeMgr.activeTrees.put(player.getUuidAsString(), new AttributeTree(player.getUuidAsString()));
}
});
ServerPlayConnectionEvents.DISCONNECT.register((handler, server) -> {
var player = handler.player;
Keeblarcraft.LOGGER.info("Player " + player.getName() + " has logged out. Deleting tree...");
if (AttributeMgr.activeTrees.containsKey(player.getUuidAsString()) == true) {
AttributeMgr.activeTrees.remove(player.getUuidAsString());
}
});
// Initialize our ticks!!
ServerTickListener.InitializeServerTicks();
// Run command registrations from the command manager // Run command registrations from the command manager
LOGGER.info("\033[34m Running command registration \033[0m"); LOGGER.info("\033[34m Running command registration \033[0m");
cmdMgr.RegisterCustomCommands(); cmdMgr.RegisterCustomCommands();
// Register attributes
AttributeMgr.RegisterAttributes();
/// THE BELOW ITEMS MUST BE DONE LAST IN THE STEPS
// Register items
ItemManager.RegisterAllItems();
// Register blocks
BlockManager.RegisterBlocks();
} catch (SETUP_FAILED_EXCEPTION e) { } catch (SETUP_FAILED_EXCEPTION e) {
System.out.println(ChatUtil.ColoredString("ERROR. Setup failed to initialize environment. Mod likely does not have read/write permissions inside area. Mod will now close out.", CONSOLE_COLOR.RED)); System.out.println(ChatUtil.ColoredString("ERROR. Setup failed to initialize environment. Mod likely does not have read/write permissions inside area. Mod will now close out.", CONSOLE_COLOR.RED));
e.printStackTrace(); e.printStackTrace();

View File

@ -12,17 +12,12 @@ package jesse.keeblarcraft.Utils;
import java.util.List; import java.util.List;
import org.apache.commons.io.FileUtils;
import org.spongepowered.include.com.google.common.io.Files;
import java.util.List;
import java.util.ArrayList; import java.util.ArrayList;
import jesse.keeblarcraft.Keeblarcraft;
import jesse.keeblarcraft.ServerTickListener;
import jesse.keeblarcraft.ConfigMgr.ConfigManager; import jesse.keeblarcraft.ConfigMgr.ConfigManager;
import jesse.keeblarcraft.EventMgr.ServerTickListener;
import jesse.keeblarcraft.Utils.ChatUtil.CONSOLE_COLOR; import jesse.keeblarcraft.Utils.ChatUtil.CONSOLE_COLOR;
import jesse.keeblarcraft.Utils.CustomExceptions.DIRECTORY_CREATE_EXCEPTION; import jesse.keeblarcraft.Utils.CustomExceptions.DIRECTORY_CREATE_EXCEPTION;
import jesse.keeblarcraft.Utils.CustomExceptions.DIRECTORY_DELETE_EXCEPTION;
import jesse.keeblarcraft.Utils.CustomExceptions.SETUP_FAILED_EXCEPTION; import jesse.keeblarcraft.Utils.CustomExceptions.SETUP_FAILED_EXCEPTION;
// Singleton class is designed to help the mod set itself up and create all the important things. It does two things: // Singleton class is designed to help the mod set itself up and create all the important things. It does two things:
@ -62,14 +57,16 @@ public final class Setup {
add("commands"); // Expect 1 file per command that's configurable! add("commands"); // Expect 1 file per command that's configurable!
add("events"); // Expect 1 file per event that is configurable! add("events"); // Expect 1 file per event that is configurable!
add("bank"); add("bank");
add("attributes");
}}; }};
// These will be top-level config files above the directories this mod creates // These will be top-level config files above the directories this mod creates
private static final List<String> FILE_LIST = new ArrayList<String>() {{ private static final List<String> FILE_LIST = new ArrayList<String>() {{
add("story/story.json"); // Big config file, determines when players can do certain things at different story levels add("story/general_story_config.json"); // Big config file, determines when players can do certain things at different story levels
add("factions/factions.json"); // General configuration file for factions stuff add("factions/general_factions_config.json"); // General configuration file for factions stuff
add("events/1events.json"); // General configuration file for story events! add("events/general_event_config.json"); // General configuration file for story events!
add("general.json"); // The super general configuration file! (May be removed) add("general.json"); // The super general configuration file! (May be removed)
add("attributes/general_attribute_config.json");
}}; }};
// RunChecks() // RunChecks()
@ -159,21 +156,8 @@ public final class Setup {
throw new SETUP_FAILED_EXCEPTION(); throw new SETUP_FAILED_EXCEPTION();
} }
//testing for this
try {
onInitialize();
} catch (Exception e){
System.out.println(ChatUtil.ColoredString("servertick failed to inilize.", CONSOLE_COLOR.RED));
throw new SETUP_FAILED_EXCEPTION();
}
System.out.println(ChatUtil.ColoredString("DID SETUP COMPLETE SUCCESSFULLY? ", CONSOLE_COLOR.YELLOW) + (ret ? ChatUtil.ColoredString("YES", CONSOLE_COLOR.YELLOW) : ChatUtil.ColoredString("NO", CONSOLE_COLOR.YELLOW))); System.out.println(ChatUtil.ColoredString("DID SETUP COMPLETE SUCCESSFULLY? ", CONSOLE_COLOR.YELLOW) + (ret ? ChatUtil.ColoredString("YES", CONSOLE_COLOR.YELLOW) : ChatUtil.ColoredString("NO", CONSOLE_COLOR.YELLOW)));
return ret; return ret;
} }
public void onInitialize() {
// Call the setup file to register event listeners and other setup tasks
ServerTickListener.initialize();
}
} }

View File

@ -0,0 +1,7 @@
{
"variants": {
"": {
"model": "keeblarcraft:block/example_block"
}
}
}

View File

@ -0,0 +1,7 @@
{
"variants": {
"": {
"model": "keeblarcraft:block/example_block_ore"
}
}
}

View File

@ -0,0 +1,11 @@
{
"item.keeblarcraft.metaljacket_helmet": "MetalJacket Helmet",
"item.keeblarcraft.metaljacket_chestplate": "MetalJacket Chestplate",
"item.keeblarcraft.metaljacket_leggings": "MetalJacket Leggings",
"item.keeblarcraft.metaljacket_boots": "MetalJacket Booties",
"itemgroup.keeblarcraft": "Keeblarcraft Modded Items",
"block.keeblarcraft.example_block": "Keeblarcraft example block",
"block.keeblarcraft.example_block_ore": "Keeblarcraft example block ore"
}

View File

@ -0,0 +1,6 @@
{
"parent": "block/cube_all",
"textures": {
"all": "keeblarcraft:block/example_block"
}
}

View File

@ -0,0 +1,6 @@
{
"parent": "block/cube_all",
"textures": {
"all": "keeblarcraft:block/example_block_ore"
}
}

View File

@ -0,0 +1,3 @@
{
"parent": "keeblarcraft:block/example_block"
}

View File

@ -0,0 +1,3 @@
{
"parent": "keeblarcraft:block/example_block_ore"
}

View File

@ -0,0 +1,6 @@
{
"parent": "item/generated",
"textures": {
"layer0": "keeblarcraft:item/metaljacket_boots"
}
}

View File

@ -0,0 +1,6 @@
{
"parent": "item/generated",
"textures": {
"layer0": "keeblarcraft:item/metaljacket_chestplate"
}
}

View File

@ -0,0 +1,6 @@
{
"parent": "item/generated",
"textures": {
"layer0": "keeblarcraft:item/metaljacket_helmet"
}
}

View File

@ -0,0 +1,6 @@
{
"parent": "item/generated",
"textures": {
"layer0": "keeblarcraft:item/metaljacket_leggings"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 269 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 287 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 263 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 267 B

View File

@ -0,0 +1,6 @@
{
"replace": false,
"values": [
"keeblarcraft:example_block_ore"
]
}

View File

@ -0,0 +1,20 @@
{
"type": "minecraft:block",
"pools": [
{
"bonus_rolls": 0.0,
"conditions": [
{
"condition": "minecraft:survives_explosion"
}
],
"entries": [
{
"type": "minecraft:item",
"name": "keeblarcraft:example_block"
}
],
"rolls": 1.0
}
]
}

View File

@ -0,0 +1,20 @@
{
"type": "minecraft:block",
"pools": [
{
"bonus_rolls": 0.0,
"conditions": [
{
"condition": "minecraft:survives_explosion"
}
],
"entries": [
{
"type": "minecraft:item",
"name": "keeblarcraft:example_block_ore"
}
],
"rolls": 1.0
}
]
}

View File

@ -0,0 +1,18 @@
{
"type": "minecraft:crafting_shaped",
"category": "misc",
"pattern": [
" # ",
"###",
" # "
],
"key": {
"#": {
"item": "keeblarcraft:example_block_ore"
}
},
"result": {
"item": "keeblarcraft:example_block",
"count": 8
}
}

View File

@ -0,0 +1,21 @@
{
"type": "minecraft:crafting_shaped",
"category": "misc",
"pattern": [
"#C#",
"###",
"#C#"
],
"key": {
"#": {
"item": "keeblarcraft:example_block"
},
"C": {
"item": "minecraft:coal"
}
},
"result": {
"item": "keeblarcraft:example_block",
"count": 8
}
}

View File

@ -0,0 +1,13 @@
{
"type": "minecraft:crafting_shapeless",
"category": "building",
"ingredients": [
{
"item": "keeblarcraft:example_block"
}
],
"result": {
"item": "keeblarcraft:example_block",
"count": 1
}
}

View File

@ -0,0 +1,7 @@
{
"replace": false,
"values": [
"keeblarcraft:example_block",
"keeblarcraft:example_block_ore"
]
}

View File

@ -0,0 +1,6 @@
{
"replace": false,
"values": [
"keeblarcraft:example_block"
]
}