forked from rawii22/ChestInclusionForCrafting
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmodmain.lua
274 lines (253 loc) · 9.14 KB
/
modmain.lua
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
local json = GLOBAL.json
local pcall = GLOBAL.pcall
local RADIUS = GetModConfigData("RADIUS")
local CHESTERON = GetModConfigData("CHESTERON")
function GetOverflowContainers(player)
--[[if GLOBAL.TheNet:GetIsClient() then --apparently this check is not needed because clients have access to TheSim and their own Transform component.
return {}
end]]
local x,y,z = player.Transform:GetWorldPosition()
local chests = GLOBAL.TheSim:FindEntities(x,y,z, RADIUS, nil, {"quantum", "burnt"}, {"chest", "cellar", "fridge", CHESTERON and "chester" or "", CHESTERON and "hutch" or ""})
return #chests > 0 and chests or nil
end
function getNumItems(list) --the value of the table must be a number
local amount = 0
if list == nil then
return amount
end
for k,v in pairs(list) do
amount = amount + v
end
return amount
end
-------------------------------------------------Begin for host
local function HasOverride(component)
local OldHas = component.Has
component.Has = function(self, item, amount, runoriginal)
-- Search in inventory, active item, & backpack
HasItem, ItemCount = OldHas(self, item, amount)
-- Search in nearby containers
local num_left_to_find = amount - ItemCount
local overflows = GetOverflowContainers(self.inst)
if overflows ~= nil then
for k,chest in pairs(overflows) do
local chestHas, chestAmount = chest.components.container:Has(item, num_left_to_find)
ItemCount = ItemCount + chestAmount
end
HasItem = ItemCount >= amount
end
return HasItem, ItemCount
end
end
AddComponentPostInit("inventory", HasOverride)
local function GetItemByNameOverride(component)
local OldGetItemByName = component.GetItemByName
component.GetItemByName = function(self, item, amount)
-- Search in inventory, active item, & backpack
local items = OldGetItemByName(self, item, amount)
-- Search in nearby containers
local itemsCount = getNumItems(items)
local amount_left = amount - itemsCount
if amount_left > 0 then
local chests = GetOverflowContainers(self.inst)
if chests ~= nil then
for i,chest in pairs(chests) do
local chestItems = chest.components.container:GetItemByName(item, amount_left)
if getNumItems(chestItems) > 0 then
for k,v in pairs(chestItems) do
items[k] = v
end
amount_left = amount_left - getNumItems(chestItems)
if amount_left <= 0 then
break
end
end
end
end
end
return items
end
end
AddComponentPostInit("inventory", GetItemByNameOverride)
local function RemoveItemRemote(component)
local OldRemoveItem = component.RemoveItem
component.RemoveItem = function(self, item, wholestack)
-- Remove from inventory, active item, or backpack
local oldItem = OldRemoveItem(self, item, wholestack) --since this function was meant to always work, we pickup here if OldItem returns nil
-- Remove from nearby containers
if oldItem == nil then
local chests = GetOverflowContainers(self.inst)
for k,chest in pairs(chests) do
local remoteOldItem = chest.components.container:RemoveItem(item, wholestack)
if remoteOldItem ~= nil then
return remoteOldItem
end
end
else
return oldItem
end
end
end
AddComponentPostInit("inventory", RemoveItemRemote)
-------------------------------------------------End for host
-------------------------------------------------Begin for client
local function HasClient(prefab)
local OldHas = prefab.Has
prefab.Has = function(inst, item, amount, runoriginal)
-- Search in inventory, active item, & backpack
HasItem, ItemCount = OldHas(inst, item, amount)
-- Search in nearby containers, available on client via variable on player, '_itemTable'
local num_left_to_find = amount - ItemCount
for name,count in pairs(inst._parent.player_classified._itemTable) do
if name == item then
ItemCount = ItemCount + count
break
end
end
HasItem = ItemCount >= amount
return HasItem, ItemCount
end
end
AddPrefabPostInit("inventory_classified", HasClient)
local function RemoveIngredientsClient(prefab)
local OldRemoveIngredients = prefab.RemoveIngredients
prefab.RemoveIngredients = function(inst, recipe, ingredientmod)
if inst:IsBusy() then
return false
end
local chests = GetOverflowContainers(inst._parent) or {}
for k,chest in pairs(chests) do
local chestClassified = chest.replica.container.classified
if chestClassified ~= nil and chestClassified:IsBusy() then
return false
end
end
local allItems = {}
for k,v in ipairs(recipe.ingredients) do
local _, total = inst:Has(v.type, v.amount)
allItems[v.type] = total
end
-- Remove recipe ingredients from inventory, active item, or backpack
OldRemoveIngredients(inst, recipe, ingredientmod)
-- Remove recipe ingredients from nearby containers
local newAllItems = {}
for k,v in ipairs(recipe.ingredients) do
local _, total = inst:Has(v.type, v.amount)
newAllItems[v.type] = total
end
for k,v in ipairs(recipe.ingredients) do
local amountRemoved = allItems[v.type] - newAllItems[v.type]
local amountLeft = v.amount - amountRemoved
if amountLeft > 0 then
for k,chest in pairs(chests) do
local chestHas, chestAmount = chest.replica.container:Has(v.type, amountLeft)
if chest.replica.container.classified ~= nil then
if chestHas then
chest.replica.container.classified:ConsumeByName(v.type, amountLeft)
else
chest.replica.container.classified:ConsumeByName(v.type, chestAmount)
amountLeft = amountLeft - chestAmount
end
end
end
end
end
return true
end
end
AddPrefabPostInit("inventory_classified", RemoveIngredientsClient)
-- Get all prefabs stored in 'chests' and the amount for each
local function findAllFromChest(chests)
if not chests or #chests == 0 then
return {}
end
local items = {}
for k, v in pairs(chests) do
if v.components.container then
local prefabs = {}
for _, i in pairs(v.components.container.slots) do prefabs[i.prefab] = true end
for t, _ in pairs(prefabs) do
local found, amount = v.components.container:Has(t, 1)
items[t] = (items[t] or 0) + amount
end
end
end
return items
end
-- Publish available items in nearby containers to net variable on player, '_items'
local function allItemUpdate(inst)
local chests = GetOverflowContainers(inst._parent)
local items = findAllFromChest(chests)
local r, result = pcall(json.encode, items)
if not r then print("Could not encode all items: "..tostring(items)) end
if result then
inst._items:set(result)
end
end
-- When '_items' changes, store available items in '_itemTable'
local function itemsDirty(inst)
--print("itemsDirty: "..inst._items:value())
local r, result = pcall(json.decode, inst._items:value())
if not r then print("Could not decode JSON: "..inst._items:value()) end
if result then
inst._itemTable = result
end
if GLOBAL.TheNet:GetIsClient() then
inst._parent:PushEvent("refreshcrafting") --stacksizechange
end
end
AddPrefabPostInit("player_classified", function(inst)
inst._itemTable = {}
inst._items = GLOBAL.net_string(inst.GUID, "_items", "itemsDirty")
inst._items:set("")
inst:ListenForEvent("itemsDirty", itemsDirty)
inst.allItemUpdate = allItemUpdate
if GLOBAL.TheWorld.ismastersim then
inst.smashtask = inst:DoPeriodicTask(15 * GLOBAL.FRAMES, allItemUpdate)
end
end)
-------------------------------------------------End for client
-- These functions override the FindItems functionality defined in Gem Core API making Gem Core compatible with this mod.
-- Host
local function FindItemsOverride(component)
local OldFindItems = component.FindItems
component.FindItems = function(self, fn)
-- Search in inventory, active item, & backpack
local items = OldFindItems(self, fn)
-- Search in nearby containers
local overflows = GetOverflowContainers(self.inst) or {}
for k, overflow in pairs(overflows) do
for _, item in pairs(overflow.components.container:FindItems(fn)) do
table.insert(items, item)
end
end
return items
end
end
AddComponentPostInit("inventory", FindItemsOverride) --'FindItems' exists in the main game so we do not need to check if GemCore is enabled
-- Client
local function FindItemsClient(prefab)
local OldFindItems = prefab.FindItems
prefab.FindItems = function(inst, fn)
-- Search in inventory, active item, & backpack
local items = OldFindItems(inst, fn)
-- Search in nearby containers
local overflows = GetOverflowContainers(inst._parent) or {}
for k, overflow in pairs(overflows) do
for _, item in pairs(overflow.replica.container:FindItems(fn)) do
table.insert(items, item)
end
end
return items
end
end
if GLOBAL.KnownModIndex:IsModEnabled("workshop-1378549454") then --This is the name of the Gem Core API Mod
AddPrefabPostInit("inventory_classified", FindItemsClient)
end
------------------------------------------End of Gem Core Compatibility Section
AddPrefabPostInitAny(function(inst)
if inst and (inst:HasTag("chest") or inst:HasTag("cellar") or inst:HasTag("fridge") or inst:HasTag(CHESTERON and "chester" or "")) then
inst:AddComponent("remoteinventory")
inst.components.remoteinventory:SetDist(RADIUS, RADIUS)
end
end)