Sign in to follow this  
TheSkylarr

Making inst work outside the main function

Recommended Posts

TheSkylarr    93

Hello! I got some help on this post a few days ago, and thank you so much to the people that helped me, but I'm running into another problem while trying to customize to work the way I want it to, which is completely unrelated and is only happening because of my incompetence with lua.

The log shows this error, which seems to show that inst isn't getting passed to my keydown handler (seen in my script below the log)

[01:25:06]: [string "../mods/2.2.1/scripts/prefabs/polarhat.lua"]:141: variable 'inst' is not declared
LUA ERROR stack traceback:
    =[C]:-1 in (global) error (C) <-1--1>
    scripts/strict.lua:23 in () ? (Lua) <21-26>
    ../mods/2.2.1/scripts/prefabs/polarhat.lua:141 in (field) fn (Lua) <140-142>
    scripts/events.lua:46 in (method) HandleEvent (Lua) <42-49>
    scripts/input.lua:187 in (method) OnRawKey (Lua) <184-191>
    scripts/input.lua:396 in () ? (Lua) <395-397>

My script is on pastebin here, so you can see line numbers.

Previously, I was using doPeriodicTask to activate the ability, but only for debugging to get the ability itself functioning as I wanted, I want to move it to a keypress, but I don't know how to do that and still have inst be the right value. Sorry for seeming like a such a noob, I've kinda just skated by without understanding this stuff and I feel so dumb now.

Share this post


Link to post
Share on other sites
Ziro2k    20

What is it that you want the "inst" variable to reference? In your PreFreeze function you treat inst as though it references a player, but then you pass this player variable to the DoFreeze function and treat it as though it references your polarhat. You'll want to get these references ironed out. But more importantly, in your key handler you are passing a variable that doesn't exist. If you want this inst to reference your polarhat, then you'll want to call something like:

TheInput:AddKeyDownHandler(304, function()
    local inst = ThePlayer.components.inventory:GetEquippedItem(EQUIPSLOTS.HEAD)
    if inst~= nil and inst.prefab == "polarhat" then
        PreFreeze(inst)
    end
end
 

This will pass a reference to the polarhat that the player is wearing to the PreFreeze function, so in this case the PreFreeze function will need to be re-written so that inst is referencing the hat and not a player like it is now:

local function PreFreeze(inst)
  	local owner = inst.components.inventoryitem.owner
  	if not owner.components.health:IsDead() and not owner:HasTag("playerghost") then
		DoFreeze(inst)
  	end
end

Note there there is no need to check for a "WearingIceHat" tag. We already determined that the player is wearing a polarhat in the previous function by accessing the head equipslot and checking it's prefab name.

Now, it's important to realize that the above code will work, but only if you are the host on a server without caves, because in this case the server and the client are the same. TheInput, and by extension AddKeyDownHandler, only reference the local client. This means that if other players try to press the key, they will crash (for a multitude of reasons, including the fact that components like inventory and health do not exist on clients). So, if you want to use a hotkey-activated ability like this, you'll really need to use an RPC. RPC stands for remote procedure call, and essentially it's the way a client can tell a server to do something.

Also note that the first parameter of the Prefab declaration at the bottom of your file should simply be the name of your prefab (in this case "polarhat") and not a filepath.

Hope this helps.

  • Like 2

Share this post


Link to post
Share on other sites
TheSkylarr    93
3 hours ago, Ziro2k said:

What is it that you want the "inst" variable to reference? In your PreFreeze function you treat inst as though it references a player, but then you pass this player variable to the DoFreeze function and treat it as though it references your polarhat. You'll want to get these references ironed out. But more importantly, in your key handler you are passing a variable that doesn't exist. If you want this inst to reference your polarhat, then you'll want to call something like:


TheInput:AddKeyDownHandler(304, function()
    local inst = ThePlayer.components.inventory:GetEquippedItem(EQUIPSLOTS.HEAD)
    if inst~= nil and inst.prefab == "polarhat" then
        PreFreeze(inst)
    end
end
 

This will pass a reference to the polarhat that the player is wearing to the PreFreeze function, so in this case the PreFreeze function will need to be re-written so that inst is referencing the hat and not a player like it is now:


local function PreFreeze(inst)
  	local owner = inst.components.inventoryitem.owner
  	if not owner.components.health:IsDead() and not owner:HasTag("playerghost") then
		DoFreeze(inst)
  	end
end

Note there there is no need to check for a "WearingIceHat" tag. We already determined that the player is wearing a polarhat in the previous function by accessing the head equipslot and checking it's prefab name.

Now, it's important to realize that the above code will work, but only if you are the host on a server without caves, because in this case the server and the client are the same. TheInput, and by extension AddKeyDownHandler, only reference the local client. This means that if other players try to press the key, they will crash (for a multitude of reasons, including the fact that components like inventory and health do not exist on clients). So, if you want to use a hotkey-activated ability like this, you'll really need to use an RPC. RPC stands for remote procedure call, and essentially it's the way a client can tell a server to do something.

Also note that the first parameter of the Prefab declaration at the bottom of your file should simply be the name of your prefab (in this case "polarhat") and not a filepath.

Hope this helps.

Wow, this helped quite a bit, it finally got my ability working in some sense, in a local world without caves enabled as you said it would. I've been referencing this post about a keyhandler/RPC thing, and I'm attempting to get it working. Thanks for all the help, quick question though:

For some reason, I get a crash whenever I try to get any of the components of ThePlayer while caves are enabled. I followed a tutorial on how to do RPC's, but I think I need a general tutorial on the differences in how server's handle things versus how the clients do. I think I need to use a replica of some sort to get the components of ThePlayer, but I have no idea how to use a replica. Do you know what to do here?

Edited by TheSkylarr

Share this post


Link to post
Share on other sites
TheSkylarr    93

Okay, I've learned a lot over the past couple days. I decided to more thoroughly read through this post, and it was a big help in patching some holes in my knowledge! Guess I really should have read the newcomer post haha. https://forums.kleientertainment.com/forums/topic/47353-guide-getting-started-with-modding-dst-and-some-general-tips-for-ds-as-well/

Share this post


Link to post
Share on other sites
Ziro2k    20

Not sure if you've had these questions answered already, but I'll give it a shot anyway.

When you don't have caves enabled, the host server and client are one and the same. However, with caves, you're actually running the servers in separate processes as dedicated servers and then connecting to them as a client (even as the host) like any other player would. This is why ThePlayer doesn't work. I didn't explain this in my previous post, but ThePlayer is in a similar boat to TheInput in that it's a client-only variable that references that player's character and doesn't exist on dedicated servers. Without caves, ThePlayer references the host's character, which is why it works in that scenario. In short, only use ThePlayer on code that is mean to run locally on a client.

This isn't an issue though, because if you use RPCs the player who is sending the RPC is automatically passed to the RPC handler function for use in server-side logic. Here is a sample RPC for your polarhat:

--Executed by the server
AddModRPCHandler(modname, "Polar Hat RPC", function(player)
    local inst = player.components.inventory:GetEquippedItem(EQUIPSLOTS.HEAD)
    if inst~= nil and inst.prefab == "polarhat" then
        PreFreeze(inst)
    end
end)

--Executed by the client.
TheInput:AddKeyDownHandler(304,function()
	SendModRPCToServer(MOD_RPC[modname]["Polar Hat RPC"])
end)

Note that the modname field above can stay as just modname if you're in modmain.lua or a patch file extension of modmain.lua, but if you're in a prefab or component file (like in this case, I'm presuming it is a prefab file) you'll have to manually call the name of your mod first, like this:

--The name of your mod is the string that's assigned to "name" at the top of modinfo.lua.
local modname = KnownModIndex:GetModActualName("insert name of your mod here")

 

  • Like 1

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this