Jump to content

ZDoctor

Members
  • Posts

    27
  • Joined

  • Last visited

Everything posted by ZDoctor

  1. # A dependency - use the . to indicate dependency for a specific modid. Dependencies are optional. [[dependencies.continfblocklib]] #optional # the modid of the dependency modId="forge" #mandatory # Does this dependency have to exist - if not, ordering below must be specified mandatory=true #mandatory # The version range of the dependency versionRange="[31,)" #mandatory # An ordering relationship for the dependency - BEFORE or AFTER required if the relationship is not mandatory ordering="NONE" # Side this dependency is applied on - BOTH, CLIENT or SERVER side="BOTH" # Here's another dependency [[dependencies.continfblocklib]] modId="minecraft" mandatory=true versionRange="[1.15.2]" ordering="NONE" side="BOTH" [[dependencies.continfblocklib]] modId="continfitemlib" mandatory=true versionRange="any" ordering="AFTER" side="BOTH" This is your code from you item-library mods.toml. Now please explain to me why you have 3 "[[dependencies.continfblocklib]]" and not only that, each has a different modid with the other two being "forge" and "minecraft" not to mention they have versions. Also if it crashing then it's best to figure out why, because that means you usually did something wrong. Before you even touch the gradle (because technically you shouldn't really need to) you should first get your mods able to be run.
  2. So if I understand correctly, your question has two parts, 1) how to reference another library (block reference items) and 2) reference loot tables from another mod. For the first part, I assume you correctly added it as a dependency to the mods.toml file so that it errors when it doesn't find the required mod. However, there still the problem of referencing the other mod in code and building it. There are a number of ways to do this and they all revolve around using the build.gradle file. After messing around with this myself for a while, I understand what a pain this could be and it took hours for me to figure out my setup, but I digress. Once you define in your build.gradle where it can find your library and refresh the gradle it will automatically add it to the external references which will let you reference it in code. There are a number of ways to define it in a gradle and supposedly (according the the build.gradle) there is supposed to be a built in way by putting in in the "libs" folder, but I've had no success trying that method. The next best thing going down that path (the libs folder) is to add "compile fileTree(dir: './libs', include: '*.jar')" or "compile files("./libs/name-of-jar-here.jar")" in the dependencies section of the build.gradle. Though this wasn't sufficient for my needs, but I again digress. For the second part, I'm not quite sure what you mean by referencing a loot table. If you mean referencing by reading the json file, then you'd need to use the resource manager and get the file as a stream using the resource location. If you mean overriding a loot table, then you'd need to create a loot table override, but I believe there should be tutorials about that already and a good reference here: https://minecraft.gamepedia.com/Loot_table#Data_packs Don't worry about it too much if you don't quite understand what I'm saying. As I see it, it isn't technically modding but using an external tool (gradle). You say you are new to modding so I'd suggest trying to first learn and practice making mods that are independent.
  3. May I direct your attention to the mods.toml file. https://mcforge.readthedocs.io/en/latest/gettingstarted/structuring/#the-modstoml-file With it you can declare mods that yours depends on and specify a version (i.e. a minimum or strict version). Doing so will show the user an error message telling them about the missing mods. If I understand your meaning, according to this page in the docs (https://mcforge.readthedocs.io/en/latest/concepts/sides/#writing-one-sided-mods) mods are expected to work regardless of what side they are on, and if they don't that is a problem the the mod author needs to address.
  4. Assuming you are using IntelliJ, once you import the gradle settings the Minecraft source code (along with all the other dependencies) would be under the "External Libraries" in your project. For the code it would be the 'net.minecraftforge:forge:1.X.X-X.X.X_mapped_snapshot' and for the assets (textures, json, etc.) it would be under the 'net.minecraft:client:extra:1.X.X' Intellij also provides shortcuts to getting to the source code of a file by holding control and left clicking the class, method or field. Eclipse is a somewhat similar process.
  5. Even if there isn't an error, the debug log could be useful.
  6. I would look into how redstone does it. Pretty sure you'll need to create a new TileEntity to do this.
  7. You should still get rid of the "value = Dist.CLIENT" pretty sure it will cause a ghost item if someone tried to use it on a server.
  8. And I went ahead and did it to prove I could. First the custom HorseInventoryContainer: public class TestHorseInventory extends HorseInventoryContainer { public TestHorseInventory(int id, PlayerInventory pInv, IInventory iinv, final AbstractHorseEntity horse) { super(id, pInv, iinv, horse); inventorySlots.set(0, new Slot(iinv, 0, 8, 18) { /** * Check if the stack is allowed to be placed in this slot, used for armor slots as well as furnace fuel. */ public boolean isItemValid(ItemStack stack) { return (stack.getItem() == Items.SADDLE || stack.getItem() == Items.DIAMOND) && !this.getHasStack() && horse.canBeSaddled(); } /** * Actualy only call when we want to render the white square effect over the slots. Return always True, except * for the armor slot of the Donkey/Mule (we can't interact with the Undead and Skeleton horses) */ @OnlyIn(Dist.CLIENT) public boolean isEnabled() { return horse.canBeSaddled(); } }); } } The overriding the server container: @Mod.EventBusSubscriber public static class CommonEvents { @SubscribeEvent public static void containerOpen(PlayerContainerEvent.Open event) { if (event.getContainer() instanceof HorseInventoryContainer) { LOGGER.info("Open Inventory"); ServerPlayerEntity player = (ServerPlayerEntity) event.getPlayer(); HorseInventoryContainer oldContainer = (HorseInventoryContainer) event.getContainer(); AbstractHorseEntity horse = ObfuscationReflectionHelper.getPrivateValue(HorseInventoryContainer.class, oldContainer, "horse"); IInventory horseInventory = ObfuscationReflectionHelper.getPrivateValue(HorseInventoryContainer.class, oldContainer, "horseInventory"); if (player != null && horse != null && horseInventory != null) { player.openContainer = new TestHorseInventory(player.currentWindowId, player.inventory, horseInventory, horse); player.openContainer.addListener(player); } } } } Then the HorseInventoryScreen: @Mod.EventBusSubscriber public static class TestClientEvents { @SubscribeEvent public static void openGui(GuiOpenEvent event) { if (event.getGui() instanceof HorseInventoryScreen) { ClientPlayerEntity player = Minecraft.getInstance().player; if (player != null) { HorseInventoryScreen oldGui = (HorseInventoryScreen) event.getGui(); HorseInventoryContainer oldContainer = oldGui.getContainer(); AbstractHorseEntity horse = ObfuscationReflectionHelper.getPrivateValue(HorseInventoryContainer.class, oldContainer, "horse"); IInventory horseInventory = ObfuscationReflectionHelper.getPrivateValue(HorseInventoryContainer.class, oldContainer, "horseInventory"); if (horse != null && horseInventory != null) { HorseInventoryContainer newContainer = new TestHorseInventory(oldContainer.windowId, player.inventory, horseInventory, horse); player.openContainer = newContainer; HorseInventoryScreen newGui = new HorseInventoryScreen(newContainer, player.inventory, horse); event.setGui(newGui); } } } } } The finished product:
  9. So looking into it, as I understand it, you'd need to do the following: 1) You would need to subscribe to the open container event, check if the container is an instance of HorseInventoryContainer and override the openContainer of the player (by casting to ServerPlayerEntity) with your own custom HorseInventoryContainer then add the listener. 1.5) Since the parameters horse and inventoryIn are not passed along with the event, and are private with no accessors, you'd probably have to use reflection to get those values and pass them to your new instance or make a constructor that does that for you. Look at ObfuscationReflectionHelper. 2) Subscribe to the GuiOpenEvent and wait for the ClientPlayNetHandler to open the HorseInventoryScreen(through call handleOpenHorseWindow) and in the event you'd want to set the gui to the new instance of the HorseInventoryScreen with your custom horsecontainer. And that should do it. 2.5) like 1.5 you'd need some parameters not passed by the event, so you'd need reflection again to get them from the old container.
  10. Thanks for the how-to. Took a while to get it working even when reading this. I don't know if I would have had the patience to figure it out without it. XD Just a few notes. 1. You need to press 'Ok' on Intellij to apply changes to plugins. I definitely didn't spend 20 minutes trying to figure this out. 2. The vm option doesn't seem to be needed. The hot swap plugin didn't seem needed either. Was able to hotswap without both, but DCEVM needs to be installed. 3. Under Build the 'Build Project' and 'Recompile' option (and their shortcuts) works just fine, so no need to remap keys. 4. Everything other than installing DCEVM is unnecessary.
  11. I am working with forge-1.15.2-31.1.46. The server runs just fine in Intellij, but when I try to make the forge server run outside of a dev environment it crashes. It is not due to any mods because I was running it without mods. Also, the server ran just fine without forge. Here is the Server Crash Report: https://pastebin.com/7F6WScAW And the Debug Log: https://pastebin.com/37s9LHnx Any ideas? Edit: For anyone wondering, this is my Java Version: java version "1.8.0_241" Java(TM) SE Runtime Environment (build 1.8.0_241-b07) Java HotSpot(TM) 64-Bit Server VM (build 25.241-b07, mixed mode) Edit 2: It should be using java 1.8, but looking at the logs it seems it's using 12? Looking into this. Edit 3: Seems like that was the issue. I had a java 12 also installed along with 1.8. After uninstalling 12 it works fine now.
  12. That's something I never understood as to why (but never bothered to look into it too hard) it happens, but what I do is just Rotate the gl 180 and that should fix it. I assume somewhere in the vanilla code something does that, but I haven't found it.
  13. From what I can see and understand, you are trying to use the default Minecraft player model as your base model, but you are using the default renderer to do it. You can use the MC player model, but you would need to copy it and change the relevant parts, such as what texture is bound to the gl, scale etc. And then render that instead. The renderer is connected to the default mc model which also hard codes it's texture. That's the easy way, or you can just code the model in yourself.
  14. Yeah, I was afraid of that. I tried pushing a fix, but it wasn't well received due to how it affected the patch file. It's too bad, I was hoping there was another way besides my patch. I made a pretty cool damage indicator above anything living that would show the status icons and the hearts would render just like a player's (animated and everything). It's pretty cool. Now if I want it to work like that I would need to learn to edit the files, probably with asm, and even then it would only work like that in single player mod unless the server had the same mod. I guess it would be an interesting skill to have.
  15. I would like to get the current active potion effects of a living entity that is not the player. Ideally, this would be on the client side only needing no assistance from the server using what is available. As far as I can tell and from what I tested, with the exception of the player, when a potion effect is added to an entity it is not updated to the client. The color of the particles as I can tell are stored in the POTION_EFFECTS, but not what type of effect they are. That is why the particles still spawn even if the client does not know what active effects are on the entity. Here is something interesting, I noticed that since the potion effects are written to the nbt, when the world is reloaded, if a potion effect was active, then the client becomes aware of that effect. However, that effect is not removed and remains in the active potion map until next reload.
  16. Recently my pull request was closed due to how the patch formatting was. I tried to follow the format very carefully, but I guess I wasn't careful enough. So I was looking for some tips that may not be in the wiki about contributing. Specifically placement and format of new methods and variables and what an ideal patch file looks like.
  17. I don't quite understand what you mean by this. My mod/lib does not simply register in the preinit. It follows the same specifications that forge wants modders to follow. Modders can initialize items in the preInit, but in the background, my mod tracks these entries and waits for the appropriate registration event before registering them. What bad habits are you talking about? What technical issues? The only defaults I have is for living entities, and perhaps not many will change them unless they know what they are doing or what they are for. But I wouldn't call them wrong as they are based on vanilla values. Perhaps not all of them are at optimal values, but I personally don't know what are or how to determine them. And are you certain that these duplicate default will cause any problems? If so, why? I am not sure how it would cause modders to do things incorrectly. From my own personal experience, it is quite nice to just pass a few values and have everything handle for me. It makes debugging easier as I know what I can count on not being broken. What exactly would the be doing incorrectly? I would love to know, perhaps I can fix it. I don't quite understand what you mean by this. Perhaps it's just my ignorance. I assume by "Auto-magical registration" you meant automatic registration. What do you mean having things statically initialized prevents mods from being hot-swappable? I'm no expert about hot swapping, so what does this have to do with anything? The way that Forge is now, you have to restart if you want to register a new item/block/etc and that is more of an issue with Minecraft's code if I am not mistaken. In my eclipse workspace, I've been able to run debug and change code (which as I understand it is hot-swapping the code) and it works as expected. If forge wants to prevent modders from doing certain things, then I would assume a better alternative should be offered. My system isn't perfect, but I know for sure that it is a whole lot easier, consistent and maintainable than the current structure. On what grounds do you claim this? My system is like a secretary to forge, so if you had to items or whatever that had the same modid and unlocalized name, it would not interfere with any errors forge would have with this. How does it screw up the tracking? It essentially tells forge, "hey here's an object that needs to be registered, and it's for this mod." No duplicate entry would be allowed. Perhaps it is just that my code that the code that I have is a bit hard to parse. Perhaps I'll work on a smaller version so that only the registration is there as to not distract from the code. Is there something that I missed? I truly do want feedback. I am sure an automated registration system would be good for forge. Mods would be easier to maintain and sometimes can carry over to a new version of minecraft. At the very least something should be done about so that the greatest challenge to learning to mod Minecraft isn't just getting an item or block to show up in game.
  18. I don't know if it is just me, but I was having some problems setting up the forge environment following the forgedev setting up the environment tutorial. I kept getting an error that the file was not found. Which file? I do not know, it did not say even with stacktrace, debug or info. It did say the problem was in the build.gradle file at line 365. That line read "branch = "git rev-parse --abbrev-ref HEAD".execute().text.trim()". Well, I noticed that the build.gradle before that line did a check for a system environment variable "GIT_BRANCH". So I went to my environment variables and added "GIT_BRANCH" and pointed it to the main folder of the Forge clone, then I was able to setupForge with no problems. I forked then downloaded the zip of the source and unpacked it in case that matters (I didn't have a GitClient that took commands). The version was 1.12.x
  19. Registering items/blocks/etc is a real hassle, and usually big mods add their own support for registering a bunch of items. Which can be broken with an update. Perhaps it would be better if forge automated that process instead. I worked on such a system that may help. For some time I worked on a mode called LazyModder and now LazyLibrary. The goal of the mod was to make modding easier for modders by handling a lot of the repetitive stuff when it comes registration of items/blocks/entities/etc. I was successful and even made a few mods that use the lib, but I think it would be better if it was built in. I will explain a few of the classes and implementation could be as simple as adding all the classes so modders can have the option of using them, or just adding the methods, interfaces, etc directly to the item class. I am a proponent of the former option. My library adds several classes on which others are built upon and has 2 classes dedicated for handling registration of the objects and their models. With an additional class dedicated to handling sorting the objects for registration and is the parent of the last two classes so that register objects are more readily available (similar to a proxy). The EasyRegistry(GitHub) class is has a register method that takes in an IAutoRegister. These classes should automatically register themselves here and modders can do it manually if they like. The RegistryHandler(GitHub) class subscribes to the registration events and registers the appropriate objects to their registry. The ModelRegistryHandler(GitHub) class subscribes to the relevant Model Registration events and handles registering block/item/entity models along with some helper methods for binding TESR and living entity models. The EasyItem(GitHub) class extends Item and handles its own registration. It adds support for subtypes (which are also automatically registered along with their models) and supports custom names based on meta(subtypes). It can even take in an item as an argument and automatically register that item as well. The EasyBlock(GitHub) class is similar to the item class. It extends the block class, has the same constructors and will automatically create an ItemBlock and register that. It also supports changing the ItemBlock as well. The EasyTileEntityBlock(GitHub) class extends EasyBlock(GitHub) and implements ITileEntity and adds default implementations that can be overridden. Finally, the EasyLivingEntity(GitHub) class adds a few default values for entities (tracking range, send velocity update and update frequency; I'm pretty sure I used the values of an IronGolem) and adds egg support by just telling it what color the egg is or calling setHasEgg and passing true (default colors are black). It has a method getRendererClass that will try to guess the renderer class name based on the given entity name and the package of the entity class following the format <Package>.<modId>.client.renderer.entity.Render + <entityName>. The player would have to make their own renderer class within the expected package and would need to link it to their model class. Some code example: MoTD(GitHub) adds 13 entities with eggs and with models in 13 lines. By passing their Entity classes(GitHub) and created their EntitiyRenderer(GitHub) which the EasyLivingEntity(GitHub) class was able to find by itself. MOTDBlocks(GitHub) created several blocks that extended EasyBlock(GitHub) by just passing a name and material. And MOTDItems(GitHub) created several items by just passing a name and creative tab to BaseItem(GitHub) that extends EasyItem(GitHub). My hope with the automation of registration is for modders to be able to focus on adding content rather than registering it and perhaps make updating mods easier. My library has a bunch of other classes as well, but these are the base classes I feel would be the easiest to implement. These changes only add code and is aimed to work with the system with no changes to that system needed. Adding these classes wouldn't break anything.
  20. It's not that the addition that is making it difficult, but not being able to easily access the variable in the first place. People may find a variety of cases where they have the need for the last health of the entity and not know of a way to get it. For my case, I was making a simple Damage Indicator mod that when the health changed it displayed a certain effect if the health went down. As I said before, what is causing my problem is that the client is unaware of when potion effects are initially active on an entity. Here are some pictures to help demonstrate my point. Here are two entities after they are initially poisoned: Their hearts remain red. Then after leaving and reentering the world: Then after the effect expires (you can tell because of lack of particles): They are no longer poisoned, but they don't know it yet. And it stays like that until the next reload: As a technical note, the PotionEffect onUpdate is still called every tick like an active potion would, but does nothing but waste resources. That is the problem I have with the vanilla version that I think can be easily solved with the solution that I added above.
  21. I am getting the last damage to calculate what the last health was by adding the current health and last damage together. Could not a getter for this combination be added? Here is what I did to prevent that abuse. I would be more than happy to add the relevant code if people think that it is a simple enough solution. First I created a Potion Watcher (data parameter/watcher): public static final DataParameter<NBTTagCompound> WATCHER_POTION_EFFECTS = EntityDataManager.createKey(EntittLivingBase.class, DataSerializers.COMPOUND_TAG); Then overrode the entity init (to implement you would just add to the method): @Override protected void entityInit() { super.entityInit(); this.dataManager.register(WATCHER_POTION_EFFECTS, new NBTTagCompound()); } Then I overrode the notifyDataManagerChange and checked to see if the world was a client and if the parameter changed was the potion effect watcher: @Override public void notifyDataManagerChange(DataParameter<?> key) { super.notifyDataManagerChange(key); if (world.isRemote && WATCHER_POTION_EFFECTS.equals(key)) { NBTTagList nbttaglist = this.dataManager.get(WATCHER_POTION_EFFECTS).getTagList("ActiveEffects", 10); activePotionsMap.clear(); for (int i = 0; i < nbttaglist.tagCount(); ++i) { NBTTagCompound nbttagcompound = nbttaglist.getCompoundTagAt(i); PotionEffect potioneffect = PotionEffect.readCustomPotionEffectFromNBT(nbttagcompound); if (potioneffect != null) { addPotionEffect(potioneffect); } } } } Added this to the resetPotionEffectMetadata: @Override protected void resetPotionEffectMetadata() { super.resetPotionEffectMetadata(); // So the data will sync this.dataManager.set(WATCHER_POTION_EFFECTS, new NBTTagCompound()); } Added this to the updatePotionMetadata, making sure the server was the only one handling this kind of change for active potion effects: @Override protected void updatePotionMetadata() { super.updatePotionMetadata(); // So only server can send updates, would cause recursion otherwise // Would potentially allow the client to add effects, and we wouldn't want that if (world.isRemote) return; NBTTagList nbttaglist = new NBTTagList(); for (PotionEffect potioneffect : getActivePotionMap().values()) { nbttaglist.appendTag(potioneffect.writeCustomPotionEffectToNBT(new NBTTagCompound())); } NBTTagCompound compound = new NBTTagCompound(); compound.setTag("ActiveEffects", nbttaglist); this.dataManager.set(WATCHER_POTION_EFFECTS, compound); } And that's it. It leaves the rest of the code as it is only added a couple dozen lines and ensures that only the server can add potion effects while making sure the client is aware of the changes. I think because potion effects are stuck on the client after reload until next reload that would be considered a memory leak and this will ensure that doesn't happen, but I could be wrong about the terminology. I've tested this on my own mod and it works as intended. Is there something I am missing?
  22. I'll keep this short, the EntityLivingBase class has a protected variable protected float lastDamage. Is there a reason this is protected? I used this to calculate what the previous health was by adding this value to the current health. Since I wasn't using a class that extended this class, I used reflection to get this value. On that note, maybe even a lastHealth variable would be nice as well. Another thing I noticed in that same class that anything that has to do with how potions are only handled on the server. For example, addPotionEffect calls onNewPotionEffect that will not apply the attribute modifiers on the client side as there is a check to see if the world is not remote. Same thing with updatePotionEffects. There is a check to ignore the changes and not add it to the active portion. But when the world is reloaded, the potions are then added to the client. Because it is not allowed to do anything regarding potions, the inactive potions are left in the entity potion map. This isn't a problem for the local player, but other entities will still return true for an expired potion effect (i.e. poison) until the next reload. This is a problem if you want to add a client-side gui of some kind. that displays the effects. I would suggest removing the check from the class.
  23. I noticed that when a player dies and respawns in a single player world, the player ID from Entity.getEntityID on the server side and client side doesn't the match anymore. I think the previous player entity id was not removed from the client side entitiesById list. Is this an intended implementation?
  24. Skill Trees Mod Basic Player Info Page Summary The Skill Trees mod is a small mod that adds an easy way for modders to implement and add skill trees to their mod and aims to provide maximum customizability should the default look not suit your needs. This mod also provides methods for skill tree makers and other modders to check if certain skills are obtained. This mod does not add skills into the game itself. If you would like to be a part of a mod that will, check this post out. And post to the forum here . Skills By default, there are two types of skills and attribute skills. Attribute skills make it easy to affect the player's attributes. As long as the skill is active and the player has this skill, the player's stats will be changed (i.e. Double damage, natural armor, speed, etc). These changes can be viewed in the Player Info Tab (Note: this tab will show all modifiers currently affecting the player). The base skill does not do anything much on its own but can be used as a requirement to do something (i.e. craft swords and other items, use certain tools and weapons, interact with mobs, etc). Modders can also choose to do something special when the skill is obtained or removed (give or take an item from player an item, code particle effects, etc). Skills can also be made to be togglable so that their effects aren't constant. A skill can also be made tickable, meaning you can have something happen every 20 ticks (1 second) the skill is active (night vision, underwater breathing, fire resistance, mana use, etc). Skills can also be linked to each other. So you can require having a certain skill before obtaining a more powerful skill or useful skill down the line. The skills can branch out into multiple trees... skill trees! A line will automatically be drawn between each connected skill. Skill Points By default, this mod does not add any items to the game that give the player skill points. However, it does provide methods for doing so in the API and a base Item.class called ItemSkillPoint that will give the player a number of skill points. How you want the player to get skill points is up to you! Skill Trees By default, you can view your skill trees by pressing 'k' (you can change this in settings). You'll be taken to the last viewed page or the Player Info Page. There are serval default backgrounds (the same as advancements) and an option to use your own. You can discern several pieces of information at a glance: whether or not you have the skill, if you have the requirements to get a skill, if it is active, and the skills parents. If a skill does not have a lock on it, you have already obtained that skill. If a skill has an unlocked lock, it means you are able to buy it, while a skill with a locked lock means its locked. An inactive skill is grey and an active skill is orange. Connected skills are connected with a line (the line can go either way; you do not need to place skills from right to left, you can place them in any format). You can get more info about a skill by hovering over it. That will display its name, requirements, and description (all of these can be defined in the lang file). By default, unfulfilled requirements are displayed as red and fulfilled requirements are green, names of obtained skills are yellow and unobtained are white, and descriptions are white (these can be changed at creation). To purchase a skill, simply click on it. The skill will become active once the skill is purchased. (Note: Once you click a skill, if you could have purchased it, you will!) If the skill is already purchased and the skill is togglable, then clicking it will toggle it instead. By default, skill trees are kept on death. You can change this in the config. (I have included my EasyConfig class in the mod, feel free to use it!). Skill Requirements Skill Requirements are very important because without them you would just be able to buy all the skills. There are 5 default requirements, but you can create your own easily by implementing ISkillRequirment. The first two added are the Name Requirement and Description Requirement. These two add names and the description to the Skill Tooltip and are automatically added and created for by default. There are a few methods to interact with them, but you will most likely not need them unless you are creating skills that act differently than the default. The next most common one is the parent requirement. This automatically created and added to the skill for you. The last two are Skill Point Requirement and Level Requirement. Ther former requires a certain number of skills points that are consumed when purchased, and the latter is the same but for levels. Commands This mod adds commands to interact with the skill tree. Currently, there are 4: reset, addPoints, give and remove. Type "/sk" for usage. Most arguments can be tabbed completed. Server Compatability This mod should be fully server compatible and has been tested. If any bugs are found please report them to the GitHub below. Download You can download it at curse here and visit the forum here Creating a Skill Tree For Documentation and an example Skill Tree and the soruce, visit the Github here. Example Skill Trees
×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.