#KRPG Enchantment
1856 messages · Page 3 of 2
I dont think you can enchant the handle?
YK I should try that lol
I've sent the Pull Request

If everything I sent works and it gets published to the mod then a ping about the update would be awsome.
I added some comments for necessary changes, if you wanna update those and try again
I dont see where you sent them. Is it in the pull request or somewhere else?
I don't see the comments you mentioned but I did fix the one spot where I commented out something that didn't need to be.
This is all I see on the pull request btw
Oh, sorry. Didn't realize that wasn't visible to you. One minute
You don't see these?
Sorry, I'm probably doing something wrong. It's pretty late for me
I totally replied to the other one too lol
Your all good. I'll try to fix the Modsystem part.
I dont know how to explicitly reference the method I made. Everything I tried threw an error.
Ah there we go. I had to submit the comments
I see them now LOL
oopsie, but now I know
@dawn kernel Everything you left comments on should be fixed now.
oops. I accidently pressed a button that said unassign me? I hope that wasn't important LOL.
I wonder what that functionally does?
Its 11:40PM for me. I'm going to get some sleep. If there is anything else I need to change feel free to put it in the pull requests comments and I'll look at it when I can.
Thanks for all the help with this! Your much cooler about this kind of thing than some other mod devs I've talked to for other games.
All good, I had already passed out lol it was even later for me
LOL. Your a legend. I'm super thankful that you've been so patient with me. While I can make things "work" its not often the best or safest way to do so, so having your explanations on why we want to do something a specific way really helps.
ngl, it also sort of helps me contextualize the project and think about how it's designed a little differently.
It's also nice to have a little bit of help 
When comparing what I've been doing with the ToolsmithSystem Compatibility I noticed that the COSystem explicitly states ICoreClientAPI & ICoreServerAPI for the StartClient/ServerSide methods used in the EnchantmentSystem file. But The WandsSystem one is using ICoreAPI instead of explicitly specifying which one and seems to possably convert it to ICoreClient/ServerAPI.
yeah, its a bit diff based on if you need explicitly sided API access
Then there are several ways to get that sided API
like the EnchantAccessor has different controls based on which API you address its interface from
Is there a place where the thing you mentioned in the your comment is done that I can use as reference?
KRPGEnchantment doesn't appear to be valid?
Changing that to the ToolmithSystem class name doesn't work either
Initialize is definitely the right spot to do it. I guess I need to update Lightning
KRPGEnchantmentSystem
Assuming you override Initialize, you still need to run the base method
Ya, I've learned about how to use base. If I'm not mistaken it lets you override a method and by using base you can make it also use the original method just with your additions.
Exactly
Ok, I think I got it "working".
Under ProcessReversion where I was calling a static ToolsmithReversion from the ToolsmithSystem itself I now have it pointing to the ToolsmithSysServer in the KRPGEnchantmentSystem which lets me access my now non-static ToolsmithReversion method
public class TrversionEnchantment : Enchantment
{
//...
ToolsmithSystem ToolsmithSystem;
//...}
public override void Initialize(EnchantmentProperties properties)
{
//Other Initialize stuff
ToolsmithSystem = Api.ModLoader.GetModSystem<KRPGEnchantmentSystem>()?.ToolsmithSysServer;
}
//...
private void ProcessReversion(ItemSlot slot, int power)
{
//ProcessReversion Logic
ToolsmithSystem.ToolsmithReversion(slot, amount);
}
Now I just need to check that it still makes the items repair correctly. And Assuming I did it the way you were telling me about it will hopefully be good?
Yep the tool is repairing itself still
Yep, that's it exactly!
I would make sure to null-safe all your stuff, but that's basically the KRPGEnchantment "right way" of doing things
I'm probably going to get suplexed for this question but how do you make it null safe in this context. Was it that ? part? If so I think I can do that
It's sort of a process of checking that everything you don't necessarily have control over doesn't return null in a way that would crash any later code
adding a ? after something in a get method will check if the object is null before continuing
AHH I DID IT!
One sec. I'll update this.
Ex:
Api?.ModLoader?.GetModSystem<KRPGEnchantmentSystem>()?.ToolsmithSysServer
Will allow you to 1-line a complex set of checks while getting the ToolsmithSysServer
We don't need to store KRPGEnchantmentSystem itself, just the ultimate endpoint of ToolsmithSysServer
I get why we use the ?.ToolsmithSysServer but why do we do that to the Api?.Modloader?.GetModSystem<KRPGEnchantmentSystem>()
Then, when you go to
private void ProcessReversion(ItemSlot slot, int power)
{
if (toolsmithSysServer == null)
{
Api.Logger.Error("[KRPGEnchantment] Toolsmith compatibility system null during Reversion check!");
return;
}
// Other logic
toolsmithSysServer.ToolsmithReversion(slot, amount);
}
I figure that Modloader and GetModSystem would always be present so would just checking for ToolsmithSysServer work?
Assuming the ? applies to the part after itself
they should be present
Oh, I see
the difference is getting an error about it or crashing the server
Fair enough
Because toolsmithSysServer only exists as a component of GetModSystem<KRPGEnchantmentSystem>() we would check if ToolsmithSystem is null instead if I'm not mistaken.
And because ToolsmithSystem doesn't get assigned right away it should be null by defualt unless it gets assigned during the Initialization process.
Ok, I did something wrong because in testing I got.
[KRPGEnchantment] Toolsmith compatibility system null during Reversion check!
heheh
You obviously know something that I don't đ€
Was my assumption here wrong?
Any part of this can be null at different points in time.
That's why we're checking
Also instead of the if at the start I'm having it just before the ToolsmithReversion to make sure the default repair logic can run even if the Toolsmith compatibility system fails to return != null
private void ProcessReversion(ItemSlot slot, int power)
{
if (slot.Empty == true) return;
int amount = power * PowerMultiplier;
int remDur = slot.Itemstack.Collectible.GetRemainingDurability(slot.Itemstack);
int maxDur = slot.Itemstack.Collectible.GetMaxDurability(slot.Itemstack);
if (remDur < maxDur)
{
remDur += amount;
remDur = Math.Min(remDur, maxDur);
slot.Itemstack.Attributes.SetInt("durability", remDur);
if (EnchantingConfigLoader.Config?.Debug == true) { Api.Logger.Event("[KRPGEnchantment] Restoring {0} durability.", amount); }
}
if (ToolsmithSystem == null)
{
Api.Logger.Error("[KRPGEnchantment] Toolsmith compatibility system null during Reversion check!");
return;
}
else if(EnchantingConfigLoader.Config?.Debug == true)
{
Api.Logger.Event("[KRPGEnchantment] Toolsmith compatibility system is active.");
}
ToolsmithSystem.ToolsmithReversion(slot, amount);
}
I may have to look at it in context if you wanna commit to your repo
Ya give me a sec
The idea is that we need to determine if the ToolsmithSysServer actually loaded or not, then choose to run the custom logic or not based on if it's null or !null
Its updated now
Note that there are 2 branches. Working changes are pushed to you through the "clean" branch. And my latest stuff is on main with a bunch of other files that may not be relevant because it was auto generated or change by my IDE
okay, so master is the right branch?
Master is all the stuff I was just working on rn.
does Toolsmith affect weapons as well as tools?
So we need 1 more thing to determine if it's a Toolsmith enabled tool
Thats done in the ToolsmithReversion method
slot.Itemstack.GetToolhandleForData() != null
Checks if it has a toolsmith handle and this is also done seperatly for the binding
private void ProcessReversion(ItemSlot slot, int power)
{
if (slot.Empty == true) return;
int amount = power * PowerMultiplier;
if (IsTSTool && ToolsmithSystem != null)
{
ToolsmithSystem.ToolsmithReversion(slot, amount);
return;
}
int remDur = slot.Itemstack.Collectible.GetRemainingDurability(slot.Itemstack);
int maxDur = slot.Itemstack.Collectible.GetMaxDurability(slot.Itemstack);
if (remDur < maxDur)
{
remDur += amount;
remDur = Math.Min(remDur, maxDur);
slot.Itemstack.Attributes.SetInt("durability", remDur);
if (EnchantingConfigLoader.Config?.Debug == true) { Api.Logger.Event("[KRPGEnchantment] Restoring {0} durability.", amount); }
}
}
This way we only skip default logic if ToolsmithSystem does exist AND the tool is a Toolsmith enabled tool
Because the tool head uses the base vanilla durability of the tool your preexisting repair logic only fixes the tool head. The ToolsmithReversion method checks if the held item with reversion has a tool handle or binding and if it does then it repairs it.
So we only need to have a check to make sure Toolsmith is installed to prevent the game from stopping when trying to call ToolsmithReversion if it isn't present
Shears dont have a handle or binding so I use them for testing
Ok, so it would just go to something like this then?
private void ProcessReversion(ItemSlot slot, int power)
{
if (slot.Empty == true) return;
int amount = power * PowerMultiplier;
int remDur = slot.Itemstack.Collectible.GetRemainingDurability(slot.Itemstack);
int maxDur = slot.Itemstack.Collectible.GetMaxDurability(slot.Itemstack);
if (remDur < maxDur)
{
remDur += amount;
remDur = Math.Min(remDur, maxDur);
slot.Itemstack.Attributes.SetInt("durability", remDur);
if (EnchantingConfigLoader.Config?.Debug == true) { Api.Logger.Event("[KRPGEnchantment] Restoring {0} durability.", amount); }
}
if (ToolsmithSystem != null)
{
ToolsmithSystem.ToolsmithReversion(slot, amount);
}
}
or I guess it would be inside the remDur<MaxDur condition
No
If its in the RemDur condition it will prevent the handle and tool binding from repairing unless the tool head it damaged
There is a separate remDur for the handle and binding
Okay, then we just needed to simplify the null checks
Sounds about right
Awesome, sounds like we might be near the finish line 
LOL, thats what I said yesterday
Needs testing in SP and MP, with and without Toolsmith
The issue I'm running into is that the ToolsmithSystem check is always returning null
if (ToolsmithSystem == null && EnchantingConfigLoader.Config?.Debug == true)
{
Api.Logger.Error("[KRPGEnchantment] Toolsmith compatibility system null during Reversion check!");
return;
}
else if (ToolsmithSystem == null)
{
return;
}
else if (EnchantingConfigLoader.Config?.Debug == true)
{
Api.Logger.Event("[KRPGEnchantment] Toolsmith compatibility system is active.");
ToolsmithSystem.ToolsmithReversion(slot, amount);
}
else
{
ToolsmithSystem.ToolsmithReversion(slot, amount);
}
There is probably a simpler way to do that if stuff but this is just expanded form
This whole block can really just be
if (ToolsmithSystem != null)
{
ToolsmithSystem.ToolsmithReversion(slot, amount);
}
If you want to put an else for just logging, then you need to identify what is null. Perhaps using the wrong sided API?
oh nvm brain what?
I'll see if I can make it print what its seeing for each part of the Toolsmith Initialisation
That might tell us why its returning null
KRPGLib.Enchantment.KRPGEnchantmentSystem.ToolsmithSysServer.get returned null.
Ah, yes. My IDE is obviously a genius. I could never have figured that out on my own đ
Its returning null because we were using .ToolsmithSysServer after GetModSystem
Is that for a Client sided null check?
It shouldn't even touch the client side one if I'm not mistaken because its using ToolsmithSysServer
Ment shouldn't not should
Initialize will run on either side, so you should maybe API.Side check before assigning server
Like checking that its using the sApi instead of just Api because Api can also be cApi?
so something more like
public override void Initialize(EnchantmentProperties properties)
{
base.Initialize(properties);
tempStabilitySys = Api.ModLoader.GetModSystem<SystemTemporalStability>();
riftSys = Api.ModLoader.GetModSystem<ModSystemRifts>();
if (Api is ICoreServerAPI sapi)
{
ToolsmithSystem = sapi.ModLoader.GetModSystem<KRPGEnchantmentSystem>()?.ToolsmithSysServer;
}
}
Ok perfect because I was actually just looking at and looking up how it worked on google
public void StartServerSide(ICoreAPI api)
{
if (!(api is ICoreServerAPI sapi)) return;
}
Yeah, we're gonna do a positive check vs a negative check because we may have other logic to run
negative check like that would be if the method must only run on a certain side
but Initialize will run on both client and server side, so we just need to only grab the ToolsmithSysServer on the Server side, and we can grab the client sided version if we need it for some other reason by just changing over the side of the statement
And because durability is handled server side regardless of multiplayer or single player we just need to worry about using server side.
Right. Now, if we wanted to say trigger particles, or do something else client sided, we will have to build it out for that specifically
Ya
(There are some things which just happen client side in VS that will catch you off guard)
Like player positioning. The server assigns too much trust to the client which can be seen during periods of high server lag.
Meaning someone could possibly make a mod to allow for the player to teleport around thats client only.
Assuming they dont have server side safe guards for that.
I suppose that the server could allow it though if it was due to packet loss or overload or something like that.
There are some safeguards for position changing. I know they changed some of that in 1.22, but there was specifically server-sided positioning you had to use over client-sided to avoid that stuff
mining values is also affected by this
Talk about a nightmare getting that to respect the server's Enchantment configs 
I remember that during a period of high server lag I was fighting but then ran into a house and 3 minutes later got downed (in a room without mobs) and saw a trail of blood slowly creep under my door.
So the server thought that my player was killed outside and crawled inside when on the client I had walked normally into the house while being alive.
It was kind funny
I got a screenshot of it. I titled it "The lag is killing me"
15.10.2026 11:11:40 [Server Event] [KRPGEnchantment] Api is ICoreServerAPI sapi
15.10.2026 11:12:09 [Client Event] [KRPGEnchantment] Api is not ICoreServerAPI sapi
@dawn kernel
I can place a ? on ToolsmithSystemServer to stop it from throwing the exception but that doen't make it work.
I think that the API side is already correct.
The issue is probably somewhere else
Here is what google thinks
If ToolsmithSystemServer is a property with a custom setter, or if there is an implicit type conversion happening on the assignment side, the compiler can sometimes struggle to evaluate the null-propagation chain correctly.
By pulling it out into a standalone var statement, you force the compiler to strongly type the returned KRPGEnchantmentSystem object before you attempt to read fields or properties from it.
Its failing at the ToolsmithSysServer
Initialize() is being called before StartServerSide()
@dawn kernel
Its the right information at the wrong time kind of thing.
those block blood bits 
lol
It's possible something is out of order
I'm testing an idea that might fix it
Did it
private ModSystemRifts riftSys;
private SystemTemporalStability tempStabilitySys;
private KRPGEnchantmentSystem EnchantSysCore;
private ToolsmithSystem ToolsmithSystemServer => EnchantSysCore?.ToolsmithSysServer;
public override void Initialize(EnchantmentProperties properties)
{
base.Initialize(properties);
tempStabilitySys = Api.ModLoader.GetModSystem<SystemTemporalStability>();
riftSys = Api.ModLoader.GetModSystem<ModSystemRifts>();
if (Api is ICoreServerAPI sapi) { EnchantSysCore = sapi?.ModLoader?.GetModSystem<KRPGEnchantmentSystem>(); }
}
private ToolsmithSystem ToolsmithSystemServer => EnchantSysCore?.ToolsmithSysServer; //This fixes the issue by pointing to a varable that gets filled out at a later time (I think)
To to make sure that it doesn't break if it fails once we can use
ToolsmithSystemServer?.ToolsmithReversion(slot, amount);
The ? should prevent it from crashing by checking if ToolsmithSystemServer is != null right?
@dawn kernel I've update my github master branch with the fixed null checks
Awesome, sorry for lack of input. Had some work calls
It's probably good enough for me to take over if you got it working reliably on your end, though
I think soo too. I've pushed the change from the main branch I had to the clean one and so the pull request should be fully up to date other than one missing dependency.
I've added the reference to the krpgenchantment.csproj file
I use $(VINTAGE_STORY_DATA) on my pc but I've made it match your directory setup. (Aka the one I saw in your github)
Yours:
<Reference Include="toolsmith">
<HintPath>../../../Examples/toolsmith_1.2.19/Toolsmith.dll</HintPath>
<Private>false</Private>
</Reference>
Mine:
<Reference Include="toolsmith">
<HintPath>$(VINTAGE_STORY_DATA)/Mods/toolsmith_1.2.19/Toolsmith.dll</HintPath>
<Private>false</Private>
</Reference>
Awesome, tysm
Silly question, but was the Tool Binding also affected by Reversion or not?
After my fix yes both the handle and binding
Before the fix it was only the tool head
I see you added it, but in my testing it wasn't working for binding
Handle yes, binding no
That's odd. The method for the binding and handle should be the same other than the key word binding and handle.
I just grabbed a random tool from Creative menu, so idk if it's just the way I did it
I'll test my end rq
I see no reason why it shouldn't work
Oh then it doesn't have a actual binding I think
Hmmm
I didn't think about that.
To explain...
The âbindingâ durability of a bindless tool is set to something in particular
But it doesnât exist so
When crafting a tool you don't need to provide a binding. But because it needs something to define if the head is attached to the handle it must generate a "Empty" binding as a place holder.
Might not be able to be ârevertedâ
I don't know off the top of my head how the binding durability function deals with an empty binding slot.
But if a tool is crafted with a binding it should work.
Would glue work as a reversion target ? Or is it only like actual binding such as rope, twine, nails, metal parts
Anything that the Toolsmith mod uses as a binding in the tool assembly table to my knolage.
Is it possible to make a tool without binding in survival? Like is this only a creative problem?
The empty tool bind appears to be the only acception.
No itâs possible in survival
Hold stick it off hand and tool head in main hand then right click hold
To add binding you can hold binding in off hand and the partialy assembled tool in main hand and hold right click to compleate it
But you can hold rightclick without a binding on the unfinished tool rod and head to finish without binding
Hmmm, okay.
I was going through and adding some extra like configurable Reversion multipliers for Handle and Binding, so be sure to pull from my latest commit if you go to try more testing.
I also put in a variable in the csproj for those references to make it easier to swapsy
Thankyou that saves so much time.
HasToolbindingCurrentDurability
Returns a bool for if there is durability instead of if there is a tool binding. I'll implement and test.
I'll change the one for the tool handle as well just in case of special instances where a tool might not have a tool handle but still have a handle durability.
My change works
I'll get it committed and let you know when I'm done.
Awesome, good work hunting that down.
Thanks again for your hard work on this. I've been so tied up with work and some other health problems making it hard to use the computer lately and I haven't been able to give the mod as much attention as I'd like to
Your all good! I'm glad I was able to help.
A pull request has been sent with the change.

Also, how do you feel about the default multipliers for Bindings/Handles?
I think they look fine.
Tool bindings generally have less total durability I think so the half restore speed should work fine.
I honestly think handle could also go 1/2 as well. 1/3 just doesn't fit into a scale of 1-5 well
Could make it restore as a % of total instead with a floor value.
This would make it more of a repair rate instead of a repair value amount
And if it doesn't already exist you could make a template for people to customize the repair rate / max enchant lvl / per lever repair scale of individual items.
So mods that would become unbalanced due to the enchant can make their mod add the custom item enchant values to the configs and so server owners could fix it if the mod author doesn't implement it themselves.
That sounds like another balance patch. We'll put a pin in that and push Toolsmith compat to start
Sounds good
WOOOOOOOOO
The real test to see if it works will with be with an actual server. I'll let someone I know that runs a server about the update because they use the mod and we should find out if there are any bugs if players report issues while enchanting.
Hello I have a big question bout all of this very impressive stuff, does this apply to Toolsmith CO weapons ?
I think it should work in theory? Assuming they use tool heads, binding, and handle just like a regular tool
It really needs testing to confirm
If you get the chance to test it we would love to hear back from you about it. If it doesn't work then I might be so inclined to take a peek at it.
heh, got Light on my Night Vision Mask
