Jump to content

Transitioning from pre-QoL containers to post-QoL containers.


penguin0616
 Share

Recommended Posts

If you've worked with containers, I presume you had a bit of trouble adding your container widget. You either went upvalue hunting, overwrote widgetsetup and called it a day, or tried to pass in your container in as the "data" argument.

If you went with approach 2 or 3, you might now be having issues along the lines of "assertion failed".
If you want to fix this issue, stop overriding widgetsetup and using replica.container:WidgetSetup(...) for the override. There is no longer a need for this. The containers.lua file now includes the "params" table within the returned table, which should make lives a lot easier.  

Instead of doing something like this (rough example): 

Spoiler

local my_container_params =
{
	widget =
	{
		slotpos = {},
		animbank = "ui_backpack_2x4",
		animbuild = "ui_backpack_2x4",
		pos = Vector3(-5, -70, 0),
	},
	issidewidget = true,
	type = "pack",
	openlimit = 1,
}

for y = 0, 3 do
	table.insert(my_container_params.widget.slotpos, Vector3(-162, -75 * y + 114, 0))
	table.insert(my_container_params.widget.slotpos, Vector3(-162 + 75, -75 * y + 114, 0))
end


local params = {}
params.my_container_params = my_container_params


local old_widgetsetup = containers.widgetsetup
function containers.widgetsetup(container, prefab, data)
	local prfb = prefab or container.inst.prefab
	if prfb == "my_container_params" then
		local t = params[pref]
		for k, v in pairs(t) do
			container[k] = v
		end
		container:SetNumSlots(container.widget.slotpos ~= nil and #container.widget.slotpos or 0)
	else
		return old_widgetsetup(container, prefab, data)
	end
 	return old_widgetsetup(container, prefab,data)
end

 

You should instead do something like this (must be run on both client and server) (Take note that the param name must be equal to the prefab name):

Spoiler

local containers = require("containers")

local my_container_params =
{
	widget =
	{
		slotpos = {},
		animbank = "ui_backpack_2x4",
		animbuild = "ui_backpack_2x4",
		pos = Vector3(-5, -70, 0),
	},
	issidewidget = true,
	type = "pack",
	openlimit = 1,
}

for y = 0, 3 do
	table.insert(my_container_params.widget.slotpos, Vector3(-162, -75 * y + 114, 0))
	table.insert(my_container_params.widget.slotpos, Vector3(-162 + 75, -75 * y + 114, 0))
end

containers.params.my_container_params = my_container_params

 

This also means you no longer need to follow up with another replica :WidgetSetup() to make sure your container data functions, if you are doing so.

Side Note: You also no longer need to recursively search for the params upvalue now, even though your code probably still works fine.

While I understand that this short tutorial probably doesn't make much sense, hopefully it helps someone.

Edit: I'll update this sooner or later with some other changes in containers that are worth nothing.

Edited by penguin0616
  • Like 4
  • Thanks 2
Link to comment
Share on other sites

thanks, but is the new code complete?
I guess at least a line like: inst.components.container:WidgetSetup("my_container_params") is missing in the prefab function, isn't it?

And of course, even if overwriting the widgetsetup is now deprecated, please still correct it. The return of the old_widgetsetup is missing data:

return old_widgetsetup(container, prefab,data) -- do not miss data, important!

Now some more questions:
1) Why was the replica.WidgetSeutp call previously necessary? And how did this change? I see no call of this replica in containers, where is it done, why wasn't it done before?
2) If I only wan't the same widget like eg. chester for my anything. Then many mods try "inst.components.container:WidgetSetup("chester")". And I wonder, did this work before? Does this still work? Because when I made my shadowmaxwell mod, I remember that this caused problems and I had to copy paste the params of chester... In addition, if this "chester" line now works, why is the replica WidgetSetup still needed? It will crash on clients on opening, if it is not there.

Link to comment
Share on other sites

1 hour ago, Serpens said:

thanks, but is the new code complete?

No, it is just meant to illustrate how you can work with the new access to params.

1 hour ago, Serpens said:

I guess at least a line like: inst.components.container:WidgetSetup("my_container_params") is missing in the prefab function, isn't it?

Yes, this would be something you need.

1 hour ago, Serpens said:

Why was the replica.WidgetSeutp call previously necessary? And how did this change?

It depends on how each mod set it up before. Some needed it, some don't. 

1 hour ago, Serpens said:

I see no call of this replica in containers, where is it done, why wasn't it done before?

components/container.lua -> Container:WidgetSetup, line 64

1 hour ago, Serpens said:

If I only wan't the same widget like eg. chester for my anything. Then many mods try "inst.components.container:WidgetSetup("chester")". And I wonder, did this work before? Does this still work?

This approach would still work if your approach used the params upvalue and kept your param/prefab name consistent. This technique was uncommon, as people have trouble working with upvalues. It worked before and most likely should still work.

1 hour ago, Serpens said:

I remember that this caused problems and I had to copy paste the params of chester... In addition, if this "chester" line now works, why is the replica WidgetSetup still needed? It will crash on clients on opening, if it is not there.

The replica's WidgetSetup has always been needed for DST, as far as I'm aware. However, I can't think of a reason that a mod should call the replica directly instead of letting DST handle it in the normal container flow, post QoL.

Edited by penguin0616
  • Like 1
Link to comment
Share on other sites

ok thanks. I still don't get why my code version does not work (when remobing the replica), but this container stuff is really specific and really terrible , so I will just accept the new solution :)

One thing you mentioned elsewhere, but you should add it here to your tutorial:
The name of the containerparams, so currently above "my_container_params", needs to match the prefab name you want them to use on.
That means if you want to add 3 things with container, while all of them should use the same size of container, you still need to add all three of them to the containerparams.

And you dont need that big code if you just want to use and exisiting size/typ of container.
You can also do:

containers.params.my_prefab = deepcopy(containers.params.chester)

to use the same like chester.

edit:
deepcopy is important, because otherwise you would also change chesters container, when you change your new one, since they would be linked)

Edited by Serpens
  • Like 1
Link to comment
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
 Share

×
  • Create New...