peter-kish / gloot Goto Github PK
View Code? Open in Web Editor NEWA universal inventory system for the Godot game engine.
License: MIT License
A universal inventory system for the Godot game engine.
License: MIT License
So other thing I've noticed is that when I set an inventory for the CtrlInventoryGridEx via script, unset it and set it again... the sort messes up... also if I use the item (potion) in the inventory and remove it, I believe the empty slot is still selected and sometimes happens that the items change positions an overlap. Try setting it up this way... You have 1 HUD for the inventory and many units with their inventory that have for example consumable items... on click of the unit you set the HUD's ctrl inventory to that units inventory and if you use the item for an example potion of that unit and remove it by using remove_item(item) function and select other unit, you'll get errors like Assertion failed: Item not found in the inventory! The sorting will be messed etc.
Originally posted by @filipinyo in #59 (comment)
res://tests/item_definitions_test.gd:3 - Parse Error: "Inventory" was not found in the current scope
Line 3:Annotation "@tool" must be at the top of the script, before "extends" and "class_name".
This happens with all scripts that contain @tool
InventoryGridEx
with a 20x40 or bigger inventorytested in in godot 3.5.1
The problem seems to be in _input
.
Running in a for loop over every cell to check a ton of properties and if the mouse is in each field seems to be connected to it, but I haven't read the code in detail. This is not a problem in the non-ex version of InventoryGrid
Yup, there was a bug. Luckily it was an easy fix.
create_and_add_item()
should be working properly now.
Originally posted by @peter-kish in #93 (comment)
I think this issue is still happening. I've tried several different methods to create the items, but the issue persists. get_prototype() does return the correct protoset however.
plugin.cfg
name="GLoot"
description="A universal inventory system for the Godot game engine"
author="Peter Kish"
version="2.2.0"
script="gloot.gd"
protoset
[
{
"id": "wheat",
"name": "Wheat",
"stack_size": "1",
"weight": 1
},
{
"id": "iron",
"name": "Iron",
"stack_size": "1",
"weight": 10
},
{
"id": "wood",
"name": "Wood",
"stack_size": "1",
"weight": 5
},
{
"id": "bread",
"name": "Bread",
"stack_size": "1",
"weight": 2
}
]
code for testing
var protoset = preload("res://gloot_inventory/items_protoset.tres")
func _ready():
PlayerManager.player = self
Input.mouse_mode = Input.MOUSE_MODE_CAPTURED
#### testing
var item = InventoryItem.new()
item.prototype_id = "wheat"
inventory_stacked.add_item_automerge(item) # creates wheat
item = InventoryItem.new()
item.prototype_id = "bread"
inventory_stacked.add_item(item) # does not create bread
inventory_stacked.create_and_add_item("bread") # does not create bread
print(inventory_stacked.create_and_add_item("bread").get_title()) # does not create bread, returns wheat
print(protoset.get_prototype("bread")) # outputs the correct prototype for bread
#### testing
Double-clicking items in the inspector plugin list could be used to either remove (analog to adding) or edit that item.
This could speed up inventory management workflows.
CtrlInventoryGrid
, CtrlInventory
and CtrlItemSlot
clean up all child nodes in case the node has been duplicated inside the editor. This is because duplicating a parent node often results in duplicate child nodes in case the child nodes are dynamically created inside _ready()
(they get duplicated, plus dynamically created).
This can have some side effects, as not all child nodes are dynamically created. Some of them may have been created from the editor. Those would be cleaned up and end up missing in the duplicated parent node.
Ideally, _ready()
would only clean up nodes that have been dynamically created.
As discussed in #69, it would be useful to have a way of knowing which item is under the mouse cursor when working with CtrlInventoryGrid
(but also with other Ctrl*
classes).
Either by defining signals similar to the mouse_entered() and mouse_exited() signals of the Control class (for example mouse_entered_item(item)
and mouse_exited_item(item)
) which would trigger when the user hovers over the given items, or by just defining a method that will return the hovered item.
Currently there is an example that demonstrates item transfers using drag and drop between two CtrlInventoryGrid
controls. The purpose of this example is just to demonstrate how such a feature could be implemented by the user, but the plugin itself implements no item transfers using the provided UI controls (CtrlInventory
, CtrlInventoryStacked
and CtrlInventoryGrid
).
Ideally, the user would be able to drag and drop items between inventories out-of-the-box: without the need for extra user code or special Control classes (as long as they use the same protoset).
This could be made so that it works with all UI control classes and with an arbitrary number of displayed controls (would probably require a globally visible autoloaded class to track the dragged InventoryItem
).
Some plugin parameters (size and position of UI controls etc.) could be stored as settings, making them persist across sessions.
Somewhat related to #22.
One thing that I've noticed though... Sometimes (really not always) if I swap items, example I put the item from position 6 to position 2 the item on position 4 gets placed on other position. I'll try to replicate how I trigger this on the weekend.
Originally posted by @filipinyo in #41 (reply in thread)
Hey there. Since create_and_add_item function has been added yesterday, I believe that it needs a separate implementation for the inventory_grid.gd, because when we add and create an item in inventory_grid, it also gets added a position, but in the base inventory, item position is not added. I've noticed this because I wanted to implement a function that gets an item at the certain position in the inventory. This function would be useful for mapping items to hotkeys etc.
For getting item at the position I've made this function
func get_item_at_position(selected_position: Vector2) -> InventoryItem:
if(
selected_position.x < 0 ||
selected_position.x > size.x ||
selected_position.y < 0 ||
selected_position.y > size.y
):
assert("Selected position out of bounds")
for item in get_items():
var item_position = item.get_property(KEY_GRID_POSITION, Vector2.ZERO)
if (
item_position.x == selected_position.x &&
item_position.y == selected_position.y
):
return item
return null
For overriding the base classes function we can use the same function which calls the inventory_grid's add_item functions that handles position properties.
func create_and_add_item(prototype_id: String) -> InventoryItem:
var item: InventoryItem = InventoryItem.new()
item.prototype_id = prototype_id
if add_item(item):
return item
else:
item.free()
return null
If this is already possible in the current implementation, I'd like to know how, so I can use it the way it was meant to be used :D
PS: I really like the plugin
This seems to happen when the linked InventoryGrid
instance has been removed prior to the CtrlInventoryGridEx
isntance.
A simple way to reproduce this is by making the InventoryGrid
a child of the CtrlInventoryGridEx
in the scene.
Hello, I tried to recreate what was written on the readme page about serialization and deserialization, but it doesn't seem to work. Maybe I am doing something wrong? Here is how I try to use it. The file contains this:
{"node_name":"InventoryGridPlayer","item_protoset":"res://ItemProtoset.tres","items":[{"node_name":"2x2_bomb","protoset":"res://ItemProtoset.tres","prototype_id":"2x2_bomb"}],"size":"(10, 5)"}
The serialization code:
if Input.is_action_just_pressed("save_and_close"): # Serialize the inventory into a JSON string var inventory: Inventory = get_node("Inventory/InventoryGridPlayer") var dict: Dictionary = inventory.serialize() var json = JSON.print(dict) # Save to file var file = File.new() file.open("res://inventory_save.res", File.WRITE) file.store_string(json) file.close()
then trying to deserialize the file on launch:
func _ready():
var file = File.new()
file.open("res://inventory_save.res", File.READ)
var read_file = file.get_as_text()
file.close()Deserialize the inventory from a file
var inventory: Inventory = get_node("Inventory/InventoryGridPlayer")
var res: JSONParseResult = JSON.parse(read_file)
if res.error == OK:
var dict = res.result
inventory.deserialize(dict)
or I tried to deserialize on a button press, doesn't work either :(
The target inventory stays empty even if the file contained the json.
Also the Output is giving me this:
Key 'size' has wrong type! Expected '5', got '4'!
Maybe this is the reason, idk what this is, I was copying everything from the instruction.
Maybe I should refresh the inventory or something?
Originally posted by @Ingeniouz in #62
The title says it all basically. I assume the protoset is working correctly, since whenever i add items in the inspector it works just fine and i can also get any property of any item with get_property(). I'm probably doing something wrong, i just can't figure out what it is.
Originally posted by filipinyo August 16, 2022
Hey there. Since create_and_add_item function has been added yesterday, I believe that it needs a separate implementation for the inventory_grid.gd, because when we add and create an item in inventory_grid, it also gets added a position, but in the base inventory, item position is not added. I've noticed this because I wanted to implement a function that gets an item at the certain position in the inventory. This function would be useful for mapping items to hotkeys etc.
For getting item at the position I've made this function
func get_item_at_position(selected_position: Vector2) -> InventoryItem:
if(
selected_position.x < 0 ||
selected_position.x > size.x ||
selected_position.y < 0 ||
selected_position.y > size.y
):
assert("Selected position out of bounds")
for item in get_items():
var item_position = item.get_property(KEY_GRID_POSITION, Vector2.ZERO)
if (
item_position.x == selected_position.x &&
item_position.y == selected_position.y
):
return item
return null
For overriding the base classes function we can use the same function which calls the inventory_grid's add_item functions that handles position properties.
func create_and_add_item(prototype_id: String) -> InventoryItem:
var item: InventoryItem = InventoryItem.new()
item.prototype_id = prototype_id
if add_item(item):
return item
else:
item.free()
return null
If this is already possible in the current implementation, I'd like to know how, so I can use it the way it was meant to be used :D
PS: I really like the plugin
When closing the ProtoSet editor, Godot throws
res://addons/gloot/editor/edit_protoset_button.gd:42 - Invalid call. Nonexistent function 'update_json_data' in base 'Resource (item_protoset.gd)'.
There is no need for the occupied_space
property of InventoryStacked
to be writable by the user. This could lead to some side-effects.
Its value should be managed by InventoryStacked
only.
#28 does not cover undo/redo for moving items in InventoryGrid
The controls in the inspector plugin are fixed in size.
Being able to resize them (horizontally and vertically) would make their appearance more configurable.
Changes done to protosets using the protoset editor are often not written to the file system.
Both the protoset editor and the "Json Data" field reflect the changes, but by looking at the raw .tres
file it is obvious that the changes are not saved.
This results in changes being lost after the Godot editor is closed.
However, adding some debug prints shows that protoset.emit_changed()
is actually being called.
Will have to do some additional analysis to figure out if this is a Godot issue.
Helper functions like _get_item_title()
and _get_item_texture()
are implemented in multiple places in different ways.
All of them should be merged together and moved into a single common place.
line 33 of inventory_grid.gd causes a crash while dragging an item from an inventory to another, when the first inventory is completely full, but the item was not dropped in a free space on the second inventory. commenting out this line fixes the issue.
In some games that use a grid based inventory system it would be useful to have the support for item stacks, similar to Minecraft.
This would require storing the current stack size for a given item, as well as the maximal stack size.
In some cases (adding/removing items) undo and redo operations don't work after switching tabs.
I assume that the inspector controls get re-instantiated after tab switch and methods registered with add_do_method
and add_undo_method
don't get called because the original control instance doesn't exist anymore.
I believe that inventory only needs to add information about items by slots, creating a node for each item generates a lot of unnecessary information for the godot scene tree
I'd expect that using add_item_automerge would only add to matching items, not ones with extra properties defined. Like say I have a unique version of an item you could get, if I get another normal version of that item, it shouldn't add to the unique item which it currently does unless I'm using it incorrectly somehow.
While creating a self-refilling container to allow dragging into other inventorys, i encountered a crash involving line 389 of ctrl_inventory_grid.gd.
A possible solution that has been working for me is to put this code before it:
if typeof(source_inventory) == TYPE_NIL:
return
I was not sure what was causing the crash, but it seems to involve dragging a item that stopped existing in my code that deleted items that were dragged out of the inventory.
ok I've been banging my head against this for the past half week. I'm having a heck of a time getting items to add to my inventory. Also, if you don't want these kind of question in the issues feel free to just close it. I'll completely understand.
I have a basic scene for my inventory with a CtrlInventoryGrid as a child node. I'm creating the InventoryGrid in code (see below). I'm fairly certain the InventoryGrid node is getting created and linked to the CtrlInventoryGrid via the inventory_path property. However when I try to find a free place for the item or add an item I get an error that says:
Invalid call. Nonexistent function 'get_property' in base 'NiL'.
Additionally, inventory_grid_node.get_item_by_id("laptop")
seems to be null so it's acting like it's not even finding the item in the protoset.
[
{
"id": "laptop",
"width": 2,
"height": 2,
"name": "Laptop",
"description": "A general purpose laptop for business.",
"image": "res://items/assets/laptop.png"
}
]
I see that get_property is a method of InventoryItem. is the get_item_by_id function I'm trying to call just searching for the item id in the exiting inventory? also if thats the case, how does one add an item to an inventory in code?
func _ready():
var inventory_grid = initialize_inventory_grid()
create_inventory_grid(inventory_grid)
assign_inventory_grid_to_panel(inventory_grid)
var inventory_grid_node = get_node("InventoryGrid")
add_item(inventory_grid_node)
func initialize_inventory_grid() -> InventoryGrid:
var inventory_grid = load("res://addons/gloot/inventory_grid.gd").new()
inventory_grid.size = Vector2(4, 5)
inventory_grid.item_protoset = load("res://items/ItemProtoset.tres")
inventory_grid.name = "InventoryGrid"
return inventory_grid
func create_inventory_grid(inventory_grid):
add_child(inventory_grid)
func assign_inventory_grid_to_panel(inventory_grid: InventoryGrid):
var inventory_panel = get_node("CtrlInventoryGrid")
inventory_panel.inventory_path = inventory_grid.get_path()
func add_item(inventory_grid_node):
var item = inventory_grid_node.get_item_by_id("laptop")
var item_position = inventory_grid_node.find_free_place(item)
inventory_grid_node.add_item_at(item, item_position)
scroll boxes do not obey mouse input filter flags on parent control objects I.E. Stop, Pass, Ignore.
instead of having input blocked by the filter, you can click behind a control node and interact with a inventory behind it, the same goes for control nodes with clipped outside checked, for example a scrollbox will allow you to drag items not visible due to scrolling.
Steps to reproduce:
After the above the item positions have changed and are not the same as initially.
Add a section to docs/
that describes how the source code is organized.
So far I tried to avoid making the UI control classes "too customizable", simply because a UI is something very specific for each game and I was afraid that increasing customizability to cover as many of those cases as possible could overcomplicate those classes (apart from being a lot of work).
Because if that I was mostly focusing on making some very basic UI control classes that are easy to understand and that could easily be extended or build on top of by the user (I was even thinking about making the grid lines optional). Borders, background images, labels etc. I meant to be added in combination with other control nodes (TextureRect
, ColorRect
, Label
etc.).
But seeing that a lot of people are using the plugin exactly because of the UI control nodes (especially CtrlInventoryGrid
) I think adding something like a CtrInventoryGridEx
(extended) node could be a compromise. It could support some additional customization, while CtrlInventoryGrid
would stay "barebones" enough for anyone who wants to build something unique on top of it.
Originally posted by @peter-kish in #41 (comment)
InventoryItem icons are not displayed when editing an ItemSlot
node, which is not consistent with the other GLoot inspector controls.
The icon of the given item could be obtained in a similar way as in the other controls.
Similar to CtrlInventoryGridEx
, it could offer some extended customizability to CtrlItemSlot
(customizable field style, highlighted field style etc.).
gloot/addons/gloot/inventory_item.gd
Lines 30 to 31 in 7f86281
Is this line have a possibility of getting triggered? Because old_prototype_id
is set as prototype_id
, in line 31 there's an if
statement for that, when is that if
expected to be called?
With a growing number of item prototypes, it would be useful to be able to organize them inside various categories.
Categories should contain item prototypes, but also other categories if needed.
This would require a new protoset JSON structure that is also backward compatible.
The GLoot inspector plugin currently does not support adding, removing and resetting item properties.
and also this one that items overlap:
This last one could be a problem if you remove the items in the scene or something like that?
Originally posted by @filipinyo in #41 (reply in thread)
Hey,
plugin looks cool but I ran into an error in gloot.gd
Couldn't fully preload the script, possible cyclic reference or compilation error. Use "load()" instead if a cyclic reference is intended.
My version of godot is 3.4.4 and I downloaded the freshest version released just couple of minutes ago.
Best regards
Occasionaly this error comes up:
Originally posted by @filipinyo in #41 (reply in thread)
Little bi more of the debugger errors:
seems like it goes in the infinite loop occassionaly.
Originally posted by @filipinyo in #41 (reply in thread)
The issue seems to be related to inventory sorting when items are modified. The sorting moves items around, modifying them, which recursively triggers the sorting again.
Apologies for the inconvenience, but I was running some code to dynamically create an ItemProtoset and found that when receiving a JSONItemPrototype, the received data is incorrect.
Here is some of my code that I used for it:
var item_set = ItemProtoset.new() #Create ItemProtoset
var item_dict = {"id":"TEST"} #Create Item with an id using a dictionary.
item_set.add_prototype(JSON.stringify(item_dict)) #Add JSONItemPrototype to ItemProtoset by converting the dictionary to JSON format.
print(JSON.stringify(item_dict)) #Print Item as JSON.
print(item_set.has_prototype(JSON.stringify(item_dict))) #Print 'true' if item exists.
print(item_set.get_prototype(JSON.stringify(item_dict))) #Print Item received from ItemProtoset.
The output is:
{"id":"TEST"}
true
{ "id": "{\"id\":\"TEST\"}" }
I'm not sure if this is an error of the plugin or an error of my code, but I've tried multiple different methods to get the data and this is the only way that I could find that didn't return an error.
Hello, i have spend one Day on it, but i didn't find it out how i can transfer the Items to another Inventory....
Please... Help me...
Built-in icons can be used to be displayed on UI buttons like Add, Remove, Edit, Filter etc.
Undo and redo features don't work when items and inventories are edited via the inspector.
Godots UndoRedo helper could be used to manage undo/redo operations in the plugin.
Situation
when i upgraded godot to 4.1, the language server prompts this error
res://addons/gloot/editor/inventory_inspector_plugin.gd:47 - Parse Error: The function signature doesn't match the parent. Parent signature is "_parse_property(Object, Variant.Type, String, PropertyHint, String, int, bool) -> bool".
Upon checking, its related to upstream issue godotengine/godot#75311, where a code gen fix has resulted in changed function signature
Expected Behavior
Editor plugin to match the expected parent signature
i can raise a PR if you want, given its just 1 LOC :)
I think your docs outline this somewhere indicating you're working on this, but this would be very helpful in managing the inventory without having to fire a sort after an addition.
I think it's something that's fairly commonly used but would be difficult to implement on top of CtrlInventoryGrid
and now I'm seriously considering to add it as an option.
As you already noted, displaying items that are larger than 1x1 tile would be somewhat of a challenge (the width of a 3x3 item is no longer 3 * field_dimensions.x
, but 3 * field_dimensions.x + 2 * spacing
) and the artwork would need be sized accordingly.
Originally posted by @peter-kish in #41 (comment)
I followed the steps to setup the plugin (recapping here):
ItemProtoset
, JSON below:[
{
"id": "Fireball",
"name": "Fireball",
"image": "res://assets/items/health-potion.png"
},
{
"id": "Pyroblast",
"name": "Pyroblast",
"image": "res://assets/items/health-potion.png"
},
{
"id": "Meteor",
"name": "Meteor",
"image": "res://assets/items/health-potion.png"
},
{
"id": "Flame Horizon",
"name": "Flame Horizon",
"image": "res://assets/items/health-potion.png"
},
{
"id": "Rising Flames",
"name": "Rising Flames",
"image": "res://assets/items/health-potion.png"
}
]
InventoryGrid
and InventoryStacked
node in my debug scene.ItemProtoset
to these nodes and configured the width/height and capacity respectivelyCtrlInventoryGrid
and CtrlInventoryStacked
, pointing at their respective Inventory nodesdefault_item_texture/icon
properties in eachExpected results:
The few items configured in each Inventory would display inside the controls.
Actual results:
The controls display fine, but have no items within them.
Version stuff:
Latest master d71a32358
, Godot v3.5.beta4.official, GDscript binary (no mono), Windows 10
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.