nut.Inventory - rebel1324/NutScript GitHub Wiki
nut.Inventory
This page is a reference for the members and methods of the nut.Inventory
class.
Members
Members are keys within the nut.Inventory
class. These members usually should not be written to.
data
A table
that contains keys and values for holding arbitrary data in an inventory. The data in this inventory can be saved to a database or replicated to players to access the data. By default, this is the empty table {}
.
items
A table
that holds items belonging to this inventory. The keys are numbers corresponding to IDs of items and the values are the item instances. By default, this is the empty table {}
.
id
A value that is used to identify a specific inventory instance. By default, the value is -1
. Note that this does not need to be a number.
Hooks
Hooks are methods which are usually called by something else rather than you calling them directly. They are for responding to some event, rather than causing something.
onDataChanged(key, oldValue, newValue)
This shared method is called when setData
has been called with the same string key
. oldValue
contains the previous data value prior to setting the data, and newValue
contains the new data set by the call to setData
.
Example:
local Inventory = nut.Inventory:extend("Inventory")
function Inventory:onDataChanged(key, oldValue, newValue)
-- The old behavior of onDataChanged.
self.BaseClass.onDataChanged(self, key, oldValue, newValue)
-- Do some extra stuff when "foo" data has been changed.
if (key == "foo") then
print("Foo changed from "..tostring(oldValue).." to "..tostring(newValue))
end
end
Inventory:register("test")
-- Test the hook.
Inventory:instance({foo = 123})
:next(function(inventory)
inventory:setData("foo", "bar")
end)
This will print "Foo changed from 123 to bar".
onInstanced()
This server method is called after a new inventory instance has been made using the instance
method. Note that this method is called on the new inventory instance itself.
Example:
function Inventory:onInstanced()
print("A new inventory has been made with ID "..self:getID())
end
onLoaded()
This server method is called after an inventory instance and the inventory data has been loaded from storage.
Example:
function Inventory:onLoaded()
print(self:getID().." is back from the database!")
end
Methods
__eq(other)
This shared metamethod determines whether or not two inventory instances are equal. If a
and b
are two inventory instances, a == b
is true
if and only if a:getID() == b:getID()
.
__tostring()
This shared metamethod returns a string in the form of "a[b]" where a is the class name of the inventory and b is the ID of the inventory. This is used for getting the string representation of an inventory instance.
add(item)
This server method takes an item instance as its first parameter and adds it to the inventory. This is done by calling the addItem
method with the item passed as the first argument. You should overwrite this method if you want to change the logic for adding items to an inventory. For example, if you want to restrict how many items an inventory could hold, you would overwrite this method to add that check, then call the addItem
method. If you choose to overwrite this method, you must support calls to this method where the only argument is an item instance.
Example:
nut.Inventory:instance()
:next(function(inventory)
print("My new inventory! "..inventory)
nut.item.instance(0, "someitem", nil, nil, nil, function(item)
print("Adding this item to inventory: ", item)
inventory:add(item)
end)
end)
This creates a new inventory instance and creates a new item of type "someitem". The new item is then added to the inventory. All of the data is also saved to the database!
addAccessRule(rule)
This is a shared method for adding access rules to the inventory. For more information on access rules, see Access Rules. Given an access rule, rule
, this method adds the rule to the list of rules that will run. The order of the access rules matches the order of calls to this method.
addDataProxy(key, onChange)
This shared method takes a string key
and a function onChange
, and has onChange
get called whenever data corresponding to key
changes. onChange
is called with the previous data value for key
as the first argument and the new data value as the second argument. Note that this method is called by the onDataChanged
, so overwriting that method may change the behavior of this method.
Example:
local inventory = nut.Inventory:new()
inventory:addDataProxy("foo", function(oldValue, newValue)
print("Foo was changed from "..tostring(oldValue).." to "..tostring(newValue))
end)
inventory:setData("foo", "bar")
This will print "Foo was changed from nil to bar".
addItem(item)
This server method takes an item instance, sets the invID
member of item
to the ID of the inventory, adds the item to the list of items in this inventory (see items), updates the database to reflect these changes, and calls the syncItemAdded
method to replicate the addition of the item to the client side. Note that this does no validation, it only adds the item. So, this should not really be called elsewhere besides the add
method.
canAccess(action, context)
This shared method is used to determine whether or not an action (represented by a string describing the action) can be done on this inventory. To provide more information about the action, context
can be a table
with the additional information. Access is determined by running all the access rules, passing action
and context
as the second and third arguments, respectively, to each rule. If any of the rules return true
, this method returns true. Similarly, if any return false
, this method returns false
.
Example:
Suppose item1
is some item instance where item1.weight
is 2, item2
is some item instance where item2.weight
is 7, and inventory
is some inventory instance.
local function CanNotAddHeavyItems(inventory, action, context)
-- Only determine access for adding items.
if (action ~= "add") then return end
-- Any item can be added as long as it's not overweight.
if ((context.item.weight or 1) > 5) then
return false, "tooHeavy"
end
return true
end
inventory:addAccessRule(CanNotAddHeavyItems)
print(inventory:canAccess("add", {item = item1})
-- > true
print(inventory:canAccess("add", {item = item2})
-- > false
configure(config)
This shared metamethod is called when an inventory class is registered. It is used to add additional configurations to the inventory. The first parameter config
is a table
containing keys, which can affect the behavior of the inventory. The keys can be modified in this method. You should add your access rules here.
Example:
local UselessInventory = nut.Inventory:extend("UselessInventory")
function UselessInventory:configure(config)
self:addAccessRule(
function(inventory, action, context)
return false
end
)
end
UselessInventory:register("useless")
This creates a new inventory type where nothing practical can be done with it, because nothing can access it.
delete()
This server method deletes all of the database data and the instance in memory for the inventory and for the items within this inventory (both on the server and client). The deletion of the data is permanent. For example, when a character is deleted, this method is called on the character's main inventory. Note that this method calls destroy()
.
destroy()
This server method deletes the data in memory for this inventory along with all the items in this inventory, both for the server and the client.
extend(className)
This shared method returns a new metatable for a new inventory class that inherits from this inventory class. The original members and methods of this inventory class can be accessed using a BaseClass
member for the extended inventory class. This method takes one string parameter, which is the name of the inventory class. The value is className
is stored in a member called className
. Also, the metatable can be accessed using FindMetaTable("class name here")
.
Example:
local NewInventory = nut.Inventory:extend("NewInventory")
print(FindMetaTable("NewInventory") == NewInventory)
-- > true
getData(key, default)
This shared method returns the value of inventory data corresponding to the string key
. If no data exists for key
, then default
(which by default is nil
) is returned.
Example:
Suppose inventory
is some inventory instance.
-- On the server, you could run
inventory:setData("foo", "bar")
-- And on the server/client, you could run
print(inventory:getData("foo", "foo not set"))
-- which would print "bar"
getID()
This shared method returns the ID of the inventory.
getItemCount(itemType)
This shared method returns the number of items whose uniqueID
is equal to itemType
.
Example:
print(inventory:getItemCount("water"))
getItems()
This shared method returns a table
of all the items in this inventory where the key is a number containing the ID of an item and the value is the item instance itself.
getItemsByType(itemType)
This shared method returns a table
containing item instances belonging to this inventory whose uniqueID
is equal to itemType
.
getItemsByUniqueID(itemType)
This is an alias for getItemsByType
.
getRecipients()
This server method returns a list of players who have access to the "repl" (short for replicate) action. This is used to determine who the inventory data should be replicated for, so they can access the data client-side.
Example:
-- Client code:
net.Receive("Test", function()
local inventory = nut.inventory.instances[net.ReadType()]
print("You are a recipient for ", inventory)
end)
-- Server code:
util.AddNetworkString("Test")
net.Start("Test")
net.WriteType(inventory:getID())
net.Send(inventory:getRecipients())
getType()
This shared method returns a string containing the type ID for this inventory that was set by register
.
hasItem(itemType)
This shared method returns true
if and only if the inventory contains at least one item whose uniqueID
is equal to itemType
.
initializeStorage(initialData)
This server method sets up where data for this inventory is saved. It returns a promise with the new ID for the inventory. The default implementation creates a new entry in the nut_inventories
table in the database. You can overwrite if you want to change how data for instances of this inventory class is stored. See Inventory Storage for more information.
instance(initialData)
This server method is for creating a new inventory instance with data of this inventory type. It takes one optional table parameter, initialData
, which is the empty table {}
by default. This sets what the data for this new inventory initially contains. This method then returns a promise which resolves to an inventory instance after all of the inventory data has been set up.
Example:
Assuming you are using the grid inventory plugin, you could write
FindMetaTable("GridInv"):instance({w = 2, h = 3})
:next(function(inventory)
print("New inventory:", inventory)
print("w = "..inventory:getData("w", "unknown width"))
print("h = "..inventory:getData("h", "unknown height"))
end)
loadItems()
This server method loads all of the data for items in this inventory from the database, then creates an object for each item loaded, and stores it in the inventory. After all items have been loaded, the onItemsLoaded
method is called with one argument: a table containing all of the loaded items.
new()
This shared method returns a new inventory object of this class. This does not actually save anything to the database.
register(typeID)
This shared method sets the type ID of the inventory class to the string typeID
. This allows the inventory type to be identified by the string. typeID
should be short and alphanumeric. Then, it sets up the inventory configuration using configure
, and stores information about the inventory type in NutScript so it can be used later.
Example:
local CoolInventory = nut.Inventory:extend("CoolInventory")
CoolInventory:register("cool")
remove(itemID)
This server method removes the item whose ID is the number itemID
from this inventory, if it contains it. By default, the implementation just delegates to removeItem
. However, you can overwrite this method. If you do, you must support calls to this method where the only parameter is a number containing the ID of some item.
Example:
Suppose inventory
is some inventory instance and item
is some item instance.
inventory:removeItem(item:getID())
removeItem(itemID, preserveItem)
This server method removes the item whose ID is the number itemID
from this inventory without any validation. If preserveItem
is true
, then the item is not deleted. Otherwise, the item is deleted as well. This method updates the database to reflect the removal of the item. Also, the removal is replicated to the client-side. This method returns a promise that is resolved after the item has been removed from the inventory.
Example:
Suppose inventory
is some inventory instance and item
is some item instance.
inventory:removeItem(item:getID())
restoreFromStorage(id)
This server method is called when some inventory with a certain ID needs to be loaded. If this inventory type is responsible for loading that inventory ID in particular, then a promise that resolves to an inventory should be returned. This allows for custom data storage of inventories.
Example: Inventory with data saved in a file
setData(key, value)
This server method stores some value
in the inventory which can later be accessed by getData
using the string key
. After the data is set, the database is updated to make the data change persistent and syncData
is called to replicate the data change to the client-side. Finally, onDataChanged
is called, passing in key
, the previous data value corresponding to key
, and value
. The following types of values can not be set:
- Functions
- Entities
Also, Vector
and Angle
value end up being converted back to an array with numeric keys when restored. Moreover, try to keep the length of key
short.
Example:
Suppose inventory
is some inventory instance.
inventory:setData("foo", "bar")
inventory:setData("baz", 123)
show(parent)
This client method creates a view for the inventory. It does so by calling the CreateInventoryPanel
hook, passing in the inventory and parent as the first and second arguments, respectively. The panel returned by the hook is stored in nut.gui["inv"..id]
where id
is the ID of the inventory. So, if your inventory has ID 123, you can access the panel for it with nut.gui.inv123
.
Example:
inventory:show()
-- or, if you want the panel parented to some other one, then
local frame = vgui.Create("DFrame")
frame:SetSize(512, 512)
frame:Center()
frame:MakePopup()
inventory:show(frame)
sync(recipients)
This server method sends all the data for the inventory and the items in the inventory to recipients
, a Player
or a table of Player
s. This allows the inventory instance to be accessed on the client-side. recipients
defaults to the result of the getRecipients
method.
Example:
inventory:sync(player.GetAll())
This makes the inventory available to everyone on the client-side.
syncData(key, recipients)
This server method replicates the data value corresponding to key
to recipients
(a Player
or a table of Player
s), so that data can be accessed on the client-side. recipients
defaults to the result of the getRecipients
method.
syncItemAdded(item)
This server method replicates the addition of item
to the inventory on the client-side. The players who receive the data are determined by the result of the getRecipients
method.