From 143dc9d288244762022686e27a3abb6c8c9d7681 Mon Sep 17 00:00:00 2001 From: rowan Date: Wed, 11 Jun 2025 00:32:39 -0400 Subject: [PATCH] fix off-by-one in bounded range --- godot/addons/collections/int_range.gd | 12 ++++++---- godot/addons/iterator/bounded_range.gd | 5 ++-- godot/src/h_item_list.gd | 21 ++++++++++++---- godot/src/inventory_ui.gd | 2 -- godot/src/ring_buffer.gd | 33 +++++++++++++++++--------- 5 files changed, 50 insertions(+), 23 deletions(-) diff --git a/godot/addons/collections/int_range.gd b/godot/addons/collections/int_range.gd index 6ccfb6b..2cd3166 100644 --- a/godot/addons/collections/int_range.gd +++ b/godot/addons/collections/int_range.gd @@ -1,13 +1,17 @@ class_name IntRange extends RefCounted -var min: int -var max: int +var minmax: PackedInt32Array + +var min: int: + get: return minmax[0] + +var max: int: + get: return minmax[1] static var Zero = IntRange.new(0, 0) func _init(start: int, end: int, inclusive: bool = false) -> void: - min = start - max = end if not inclusive else end + 1 + minmax = PackedInt32Array([start, end if not inclusive else end + 1]) func length() -> int: return absi(max - min) diff --git a/godot/addons/iterator/bounded_range.gd b/godot/addons/iterator/bounded_range.gd index e5796b0..8895385 100644 --- a/godot/addons/iterator/bounded_range.gd +++ b/godot/addons/iterator/bounded_range.gd @@ -23,6 +23,7 @@ func next() -> Option: return current_value elif limit > 0: limit -= 1 - index = bounds.wrap(index) - return Option.some(index) + var current_value = bounds.wrap(index) + index = current_value + 1 + return Option.some(current_value) else: return Option.none diff --git a/godot/src/h_item_list.gd b/godot/src/h_item_list.gd index 17989fe..72dcaf2 100644 --- a/godot/src/h_item_list.gd +++ b/godot/src/h_item_list.gd @@ -2,7 +2,7 @@ class_name HItemList extends HBoxContainer @export var item_scene: PackedScene @export var max_items: int = 4 -@export var buffered_items: int = 2 +@export var buffered_items: int = 1 @onready var buffer_size = max_items + (buffered_items * 2) var items: Array = [] @@ -11,12 +11,22 @@ var bind_item: Callable = _bind_item var ring_buffer: RingBuffer func _ready() -> void: - ring_buffer = RingBuffer.new(items.size(), buffer_size) + ring_buffer = RingBuffer.new(items.size(), buffer_size, 1, -buffered_items) ring_buffer.updated.connect(_on_updated) for _i in range(buffer_size): add_child(create_item.call()) + _hide_buffered_items() + +func _hide_buffered_items(): + for i in range(buffered_items): + get_child(i).hide() + + var length = buffer_size - 1 + for i in range(length, length - buffered_items, -1): + get_child(i).hide() + func _create_item() -> Node: return item_scene.instantiate() @@ -30,10 +40,13 @@ func _on_updated(_current_range: IntRange, _previous_range: IntRange): func _update_display(): var indices: Array = ring_buffer.range().collect() + prints(indices, ring_buffer.start_index, ring_buffer.end_index, ring_buffer.capacity) for i in range(min(indices.size(), max_items)): - var node = get_child(i + 1) + var node = get_child(i) + prints(ring_buffer.index(i)) var item = items[indices[i]] - bind_item.call(node, item) + if item != null: + bind_item.call(node, item) func add_item(item: Variant): items.append(item) diff --git a/godot/src/inventory_ui.gd b/godot/src/inventory_ui.gd index ae70371..f8c85e0 100644 --- a/godot/src/inventory_ui.gd +++ b/godot/src/inventory_ui.gd @@ -4,6 +4,4 @@ class_name InventoryUI extends VBoxContainer @export var item_list: HItemList func _ready() -> void: - print(inventory) - print(inventory.items) item_list.add_items(inventory.items) diff --git a/godot/src/ring_buffer.gd b/godot/src/ring_buffer.gd index 42592d7..b129fd6 100644 --- a/godot/src/ring_buffer.gd +++ b/godot/src/ring_buffer.gd @@ -12,7 +12,7 @@ var source_size: int: get: return _source_size set(value): set_source_size(value) -func set_source_size(value: int): +func set_source_size(value: int) -> void: assert(value >= 0, "source size must be a non-negative integer") _source_size = value @@ -21,44 +21,55 @@ var capacity: int: get: return _capacity set(value): set_capacity(value) -func set_capacity(value: int): +func set_capacity(value: int) -> void: _capacity = value +var _offset: int +var offset: int: + get: return _offset + set(value): set_offset(value) + +func set_offset(value: int) -> void: + _offset = value + var _index: int var selected_index: int: get: return _index set(value): set_selected(value) -func set_selected(value: int): - _index = self.wrap(value) +func set_selected(value: int) -> void: + _index = self.index(value) var start_index: int: - get: return _index + get: return self.index(_offset + _index) var end_index: int: - get: return self.wrap(_index + _capacity - 1) + get: return self.index(_offset + _index + _capacity - 1) @warning_ignore("shadowed_variable") -func _init(source_size: int, capacity: int, start_index: int = 0) -> void: +func _init(source_size: int, capacity: int, start_index: int = 0, offset: int = 0) -> void: self.source_size = source_size self.capacity = capacity selected_index = start_index + self.offset = offset -func wrap(value: int) -> int: +func index(value: int) -> int: if _source_size == 0: return 0 + elif value < 0: + return _source_size + value % _source_size else: return value % _source_size -func range() -> RangeIterator: - return RangeIterator.new(IntRange.new(start_index, end_index)) +func range() -> BoundedRangeIterator: + return BoundedRangeIterator.new(IntRange.new(start_index, end_index), IntRange.new(0, capacity)) func move(direction: Direction) -> Result: if _source_size <= _capacity: return Result.err("source size is smaller than buffer capacity") var previous = range() - _index = self.wrap(_index + direction) + _index = self.index(_index + direction) updated.emit(range(), previous) return Result.Unit