From 147dc403658a7c283326038603461c1cd9c6af05 Mon Sep 17 00:00:00 2001
From: Gabriel Tofvesson <gabriel@tofvesson.se>
Date: Tue, 3 Dec 2024 22:36:23 +0100
Subject: [PATCH] Try to enforce better encapsulation with getters

---
 storage/itemstack.lua | 123 +++++++++++++++++++++++++-----------------
 1 file changed, 73 insertions(+), 50 deletions(-)

diff --git a/storage/itemstack.lua b/storage/itemstack.lua
index b5539de..5f48f21 100644
--- a/storage/itemstack.lua
+++ b/storage/itemstack.lua
@@ -19,7 +19,7 @@ function ItemStack:fromDetail(inv, detail, slot)
         obj.damage = detail.damage
         obj.maxDamage = detail.maxDamage
         obj.count = detail.count
-        obj.maxCount = detail.maxCount
+        obj.maxCount = detail.maxCount or 64
         obj.enchantments = detail.enchantments
         obj.displayName = detail.displayName
         obj.nbt = detail.nbt
@@ -33,16 +33,16 @@ end
 
 function ItemStack:clone(withSlot)
     local obj = {
-        slot = withSlot or self.slot,
-        inv = self.inv,
-        name = self.name,
-        damage = self.damage,
-        maxDamage = self.maxDamage,
-        count = self.count,
-        maxCount = self.maxCount,
-        enchantments = self.enchantments,
-        displayName = self.displayName,
-        nbt = self.nbt
+        slot = withSlot or self:getSlot(),
+        inv = self:getInventory(),
+        name = self:getName(),
+        damage = self:getDamage(),
+        maxDamage = self:getMaxDamage(),
+        count = self:getCount(),
+        maxCount = self:getMaxCount(),
+        enchantments = self:getEnchantments(),
+        displayName = self:getDisplayName(),
+        nbt = self:getNBT()
     }
 
     setmetatable(obj, self)
@@ -53,19 +53,19 @@ end
 
 function ItemStack:toSerializable()
   local ser = {
-    slot = self.slot,
-    maxCount = self.maxCount
+    slot = self:getSlot(),
+    maxCount = self:getMaxCount()
   }
 
   if not self:isEmpty() then
     -- Not empty
-    ser.name = self.name
-    ser.damage = self.damage
-    ser.maxDamage = self.maxDamage
-    ser.count = self.count
-    ser.enchantments = self.enchantments
-    ser.displayName = self.displayName
-    ser.nbt = self.nbt
+    ser.name = self:getName()
+    ser.damage = self:getDamage()
+    ser.maxDamage = self:getMaxDamage()
+    ser.count = self:getCount()
+    ser.enchantments = self:getEnchantments()
+    ser.displayName = self:getDisplayName()
+    ser.nbt = self:getNBT()
   end
 
   return ser
@@ -149,12 +149,14 @@ function ItemStack:getSimpleName()
 end
 
 function ItemStack:hasChanged(listObj, thorough)
-  local listItem = listObj[self.slot]
-  if listItem == nil or listItem.name ~= self.name or listItem.count ~= self.count then
+  local listItem = listObj[self:getSlot()]
+  if listItem == nil or listItem.name ~= self.name or listItem.count ~= self:getCount() then
     return true
   end
 
-  return thorough and (self ~= self:fromDetail(self.inv, self.inv.getItemDetail(self.slot), self.slot))
+  local inv = self:getInventory()
+  local slot = self:getSlot()
+  return thorough and (self ~= self:fromDetail(inv, inv.getItemDetail(slot), slot))
 end
 
 function ItemStack:_modify(countDelta, stack)
@@ -176,14 +178,13 @@ function ItemStack:_modify(countDelta, stack)
   else
     -- If stack is empty, copy stack data from source
     if self:isEmpty() then
-      self.maxCount = stack.maxCount
-      self.name = stack.name
-      self.damage = stack.damage
-      self.maxDamage = stack.maxDamage
-      self.maxCount = stack.maxCount
-      self.enchantments = stack.enchantments
-      self.displayName = stack.displayName
-      self.nbt = stack.nbt
+      self.name = stack:getName()
+      self.damage = stack:getDamage()
+      self.maxDamage = stack:getMaxDamage()
+      self.maxCount = stack:getMaxCount()
+      self.enchantments = stack:getEnchantments()
+      self.displayName = stack:getDisplayName()
+      self.nbt = stack:getNBT()
     end
 
     self.count = newCount
@@ -244,23 +245,45 @@ local function objEquals(o1, o2)
   end
 end
 
-function ItemStack:__eq(other)
-  return type(other) == "table" and
-          self.count == other.count and
-          self.maxCount == other.maxCount and
-          self:canTransfer(other)
+local function runGetter(obj, name)
+  local fun = obj[name]
+  if type(fun) ~= "function" then
+    return false, ("Function '%s' cannot be found in object"):format(name)
+  end
+  return pcall(fun, obj)
 end
 
+local function checkEqual(obj1, obj2, funcName)
+  local result1 = { runGetter(obj1, funcName) }
+  local result2 = { runGetter(obj2, funcName) }
+  return result1[1] and result2[2] and (result1[2] == result2[2])
+end
+
+local function checkEnchantments(obj1, obj2)
+  local GETTER_FUNC_NAME = "getEnchantments"
+  local result1 = { runGetter(obj1, GETTER_FUNC_NAME) }
+  local result2 = { runGetter(obj2, GETTER_FUNC_NAME) }
+  return result1[1] and result2[1] and objEquals(result1[2], result2[2])
+end
+
+function ItemStack:__eq(other)
+  return type(other) == "table" and
+          checkEqual(self, other, "getCount") and
+          checkEqual(self, other, "getMaxCount") and
+          self:canTransfer(other)
+end
 
 -- Determines if two stacks can be transferred to eachother
 -- Empty stacks are always valid transfer nodes
 function ItemStack:canTransfer(stack)
-  return self:isEmpty() or stack:isEmpty() or (self.name == stack.name and
-          self.damage == stack.damage and
-          self.maxDamage == stack.maxDamage and
-          self.displayName == stack.displayName and
-          self.nbt == stack.nbt and
-          objEquals(self.enchantments, stack.enchantments))
+  return self:isEmpty() or stack:isEmpty() or (
+    checkEqual(self, stack, "getName") and
+    checkEqual(self, stack, "getDamage") and
+    checkEqual(self, stack, "getMaxDamage") and
+    checkEqual(self, stack, "getDisplayName") and
+    checkEqual(self, stack, "getNBT") and
+    checkEnchantments(self, stack)
+  )
 end
 
 local function queryField(query, field)
@@ -283,14 +306,14 @@ function ItemStack:matches(query)
     return query(self)
   end
 
-  return queryField(query.name, self.name) and
-          queryField(query.damage, self.damage) and
-          queryField(query.count, self.count) and
-          queryField(query.maxDamage, self.maxDamage) and
-          queryField(query.enchantments, self.enchantments) and
-          queryField(query.maxCount, self.maxCount) and
-          queryField(query.nbt, self.nbt) and
-          queryField(query.displayName, self.displayName)
+  return queryField(query.name, self:getName()) and
+          queryField(query.damage, self:getDamage()) and
+          queryField(query.count, self:getCount()) and
+          queryField(query.maxDamage, self:getMaxDamage()) and
+          queryField(query.enchantments, self:getEnchantments()) and
+          queryField(query.maxCount, self:getMaxCount()) and
+          queryField(query.nbt, self:getNBT()) and
+          queryField(query.displayName, self:getDisplayName())
 end
 
 return ItemStack
\ No newline at end of file