1265 lines
46 KiB
Lua
1265 lines
46 KiB
Lua
if SERVER then return end --prevents it from running on the server
|
||
|
||
local path_to_loaded_file = nil
|
||
local has_load_completed_array = {
|
||
["clear_components_complete"] = false,
|
||
["clear_IO_label_complete"] = false,
|
||
["clear_IO_position_complete"] = false,
|
||
["add_components_complete"] = false,
|
||
["add_wires_complete"] = false,
|
||
["add_labels_complete"] = false,
|
||
["rename_labels_complete"] = false,
|
||
["change_input_output_labels_complete"] = false,
|
||
["update_values_in_components_complete"] = false,
|
||
["resize_labels_complete"] = false,
|
||
["move_input_output_nodes_complete"] = false
|
||
}
|
||
|
||
|
||
|
||
function blue_prints.parseXML(xmlString)
|
||
|
||
-- Define HTML entities for backwards compatibility
|
||
local html_entities = {
|
||
['"'] = '"',
|
||
['&'] = '&',
|
||
['<'] = '<',
|
||
['>'] = '>',
|
||
[' '] = ' ',
|
||
['¡'] = '¡',
|
||
['¢'] = '¢',
|
||
['£'] = '£',
|
||
['¤'] = '¤',
|
||
['¥'] = '¥',
|
||
['¦'] = '¦',
|
||
['§'] = '§',
|
||
['¨'] = '¨',
|
||
['©'] = '©',
|
||
['ª'] = 'ª',
|
||
['«'] = '«',
|
||
['¬'] = '¬',
|
||
['­'] = '',
|
||
['®'] = '®',
|
||
['¯'] = '¯',
|
||
['°'] = '°',
|
||
['±'] = '±',
|
||
['²'] = '²',
|
||
['³'] = '³',
|
||
['´'] = '´',
|
||
['µ'] = 'µ',
|
||
['¶'] = '¶',
|
||
['·'] = '·',
|
||
['¸'] = '¸',
|
||
['¹'] = '¹',
|
||
['º'] = 'º',
|
||
['»'] = '»',
|
||
['¼'] = '¼',
|
||
['½'] = '½',
|
||
['¾'] = '¾',
|
||
['¿'] = '¿',
|
||
['
'] = '\n',
|
||
['
'] = '\n'
|
||
}
|
||
|
||
local function contains_html_entities(str)
|
||
return str and str:find('&[^;]+;')
|
||
end
|
||
|
||
local function decode_html_entities(str)
|
||
if not str or not contains_html_entities(str) then
|
||
return str
|
||
end
|
||
return (str:gsub('(&[^;]+;)', function(entity)
|
||
return html_entities[entity] or entity
|
||
end))
|
||
end
|
||
|
||
-- Function to decode a string that might be in either format
|
||
local function decode_string(str)
|
||
if not str then return "" end
|
||
|
||
-- First try new format
|
||
local delimited_content = str:match("<<<STRINGSTART>>>(.-)<<<STRINGEND>>>")
|
||
if delimited_content then
|
||
-- Unescape any escaped delimiters
|
||
return delimited_content:gsub("\\<<<STRINGSTART>>>", "<<<STRINGSTART>>>")
|
||
:gsub("\\<<<STRINGEND>>>", "<<<STRINGEND>>>")
|
||
end
|
||
|
||
-- If not in new format, try old format with HTML entities
|
||
return decode_html_entities(str)
|
||
end
|
||
|
||
local inputs = {}
|
||
local outputs = {}
|
||
local components = {}
|
||
local wires = {}
|
||
local labels = {}
|
||
local inputNodePos = {}
|
||
local outputNodePos = {}
|
||
|
||
-- Parse InputNode
|
||
local inputNode = xmlString:match("<InputNode[^>]+>")
|
||
if inputNode then
|
||
local posX, posY = inputNode:match('pos="([%d%.%-]+),([%d%.%-]+)"')
|
||
inputNodePos = { x = tonumber(posX), y = tonumber(posY) }
|
||
end
|
||
|
||
-- Parse OutputNode
|
||
local outputNode = xmlString:match("<OutputNode[^>]+>")
|
||
if outputNode then
|
||
local posX, posY = outputNode:match('pos="([%d%.%-]+),([%d%.%-]+)"')
|
||
outputNodePos = { x = tonumber(posX), y = tonumber(posY) }
|
||
end
|
||
|
||
-- Parse input and output labels (if any)
|
||
for name, value in xmlString:gmatch('<ConnectionLabelOverride name="([^"]+)" value="([^"]+)"') do
|
||
if name:match("^signal_in") then
|
||
inputs[name] = decode_string(value)
|
||
elseif name:match("^signal_out") then
|
||
outputs[name] = decode_string(value)
|
||
end
|
||
end
|
||
|
||
-- Parse Components
|
||
for component in xmlString:gmatch('<Component.-/>') do
|
||
|
||
local id = component:match('id="(%d+)"')
|
||
local positionX, positionY = component:match('position="([%-%d%.]+),([%-%d%.]+)"')
|
||
local usedResource = component:match('usedresource="([^"]+)"')
|
||
|
||
--try both formats for backwards compatibility
|
||
|
||
local item = component:match('item=<<<STRINGSTART>>>([^<]+)<<<STRINGEND>>>')
|
||
if not item or item == "" then
|
||
item = component:match('%sitem="([^"]+)"')
|
||
end
|
||
|
||
local class = component:match('Class=<<<STRINGSTART>>>([^<]+)<<<STRINGEND>>>')
|
||
if not class or class == "" then
|
||
class = component:match('%sClass="([^"]+)"')
|
||
end
|
||
|
||
local componentData = {
|
||
id = id,
|
||
position = { x = tonumber(positionX), y = tonumber(positionY) },
|
||
usedResource = usedResource,
|
||
item = item,
|
||
class = {
|
||
name = class,
|
||
attributes = {}
|
||
}
|
||
}
|
||
|
||
-- Parse attributes in both new and old formats
|
||
-- First try new format
|
||
for attr, value in component:gmatch('(%w+)=<<<STRINGSTART>>>(.-)<<<STRINGEND>>>') do
|
||
if attr ~= "id" and attr ~= "position" and attr ~= "backingitemid" and
|
||
attr ~= "usedresource" and attr ~= "item" and attr ~= "Class" then
|
||
componentData.class.attributes[attr] = decode_string(value)
|
||
end
|
||
end
|
||
|
||
-- If no attributes found in new format, try old format
|
||
if next(componentData.class.attributes) == nil then
|
||
for attr, value in component:gmatch('(%w+)="(.-)"') do
|
||
if attr ~= "id" and attr ~= "position" and attr ~= "backingitemid" and
|
||
attr ~= "usedresource" and attr ~= "item" and attr ~= "Class" then
|
||
componentData.class.attributes[attr] = decode_html_entities(value)
|
||
end
|
||
end
|
||
end
|
||
|
||
table.insert(components, componentData)
|
||
end
|
||
|
||
-- Parse Wires
|
||
wires = {}
|
||
for wire in xmlString:gmatch("<Wire.-</Wire>") do
|
||
local wireData = {
|
||
id = wire:match('id="(%d+)"'),
|
||
prefab = wire:match('prefab="([^"]+)"')
|
||
}
|
||
|
||
local fromName, fromTarget = wire:match('<From name="([^"]+)" target="([^"]*)"')
|
||
local toName, toTarget = wire:match('<To name="([^"]+)" target="([^"]*)"')
|
||
|
||
wireData.from = { name = fromName, target = fromTarget ~= "" and fromTarget or nil }
|
||
wireData.to = { name = toName, target = toTarget ~= "" and toTarget or nil }
|
||
|
||
table.insert(wires, wireData)
|
||
end
|
||
|
||
-- Parse Labels with correct pattern matching
|
||
for label in xmlString:gmatch('<Label.-/>') do
|
||
-- Extract all attributes using individual pattern matches
|
||
local id = label:match('id="(%d+)"')
|
||
local color = label:match('color="([^"]+)"')
|
||
local posX, posY = label:match('position="([%d%.%-]+),([%d%.%-]+)"')
|
||
local sizeW, sizeH = label:match('size="([%d%.%-]+),([%d%.%-]+)"')
|
||
|
||
-- Use decode_string for both header and body
|
||
local header = decode_string(label:match('header="(.-)"'))
|
||
local body = decode_string(label:match('body="(.-)"'))
|
||
|
||
table.insert(labels, {
|
||
id = id,
|
||
color = color,
|
||
position = { x = tonumber(posX), y = tonumber(posY) },
|
||
size = { width = tonumber(sizeW), height = tonumber(sizeH) },
|
||
header = header,
|
||
body = body
|
||
})
|
||
end
|
||
|
||
blue_prints.add_advertisement_label(components, labels, inputNodePos, outputNodePos) --if there is no ad, add one
|
||
|
||
--[[
|
||
-- Add this right before the return statement in blue_prints.parseXML:
|
||
print("Parsed Components:")
|
||
for i, component in ipairs(components) do
|
||
print(string.format("Component %d:", i))
|
||
print(string.format(" ID: %s", component.id))
|
||
print(string.format(" Position: (%.2f, %.2f)", component.position.x, component.position.y))
|
||
print(string.format(" Item: %s", component.item))
|
||
print(string.format(" Class: %s", component.class.name))
|
||
print(" Attributes:")
|
||
for attr, value in pairs(component.class.attributes) do
|
||
print(string.format(" %s: %s", attr, value))
|
||
end
|
||
print("----------")
|
||
end
|
||
--]]
|
||
|
||
return inputs, outputs, components, wires, labels, inputNodePos, outputNodePos
|
||
end
|
||
|
||
|
||
|
||
|
||
function blue_prints.check_inventory_for_requirements(components)
|
||
--print("Game mode: ", Game.IsSubEditor)
|
||
|
||
local missing_components = {}
|
||
|
||
if Game.IsSubEditor then return missing_components end --if in sub editor, you dont have to worry about inventory
|
||
|
||
for _, component in ipairs(components) do
|
||
missing_components[component.item] = (missing_components[component.item] or 0) + 1
|
||
end
|
||
local character = Character.Controlled
|
||
|
||
local fpgacircuit_count = 0
|
||
|
||
--count inventory items already stored inside the box
|
||
if blue_prints.most_recent_circuitbox ~= nil then
|
||
local items_already_in_box = blue_prints.get_components_currently_in_circuitbox(blue_prints
|
||
.most_recent_circuitbox)
|
||
|
||
for resource, count in pairs(items_already_in_box) do
|
||
local identifier = resource
|
||
if identifier == "fpgacircuit" then
|
||
fpgacircuit_count = fpgacircuit_count + count
|
||
elseif missing_components[identifier] and missing_components[identifier] > 0 then
|
||
missing_components[identifier] = missing_components[identifier] - count
|
||
end
|
||
end
|
||
end
|
||
|
||
|
||
|
||
-- First pass: count regular items and fpgacircuits
|
||
for inventory_item in character.Inventory.AllItems do
|
||
local identifier = tostring(inventory_item.Prefab.Identifier)
|
||
if identifier == "fpgacircuit" then
|
||
fpgacircuit_count = fpgacircuit_count + 1
|
||
elseif missing_components[identifier] and missing_components[identifier] > 0 then
|
||
missing_components[identifier] = missing_components[identifier] - 1
|
||
end
|
||
end
|
||
|
||
-- Second pass: use fpgacircuits as wildcards only for remaining missing items
|
||
for identifier, count in pairs(missing_components) do
|
||
if count > 0 and fpgacircuit_count > 0 then
|
||
local used_fpga = math.min(count, fpgacircuit_count)
|
||
missing_components[identifier] = count - used_fpga
|
||
fpgacircuit_count = fpgacircuit_count - used_fpga
|
||
end
|
||
end
|
||
|
||
-- Remove components that are not missing
|
||
for identifier, count in pairs(missing_components) do
|
||
if count <= 0 then
|
||
missing_components[identifier] = nil
|
||
end
|
||
end
|
||
|
||
return missing_components
|
||
end
|
||
|
||
function blue_prints.add_component_to_circuitbox(component, use_fpga)
|
||
if blue_prints.most_recent_circuitbox == nil then
|
||
print("No circuitbox detected")
|
||
return
|
||
end
|
||
|
||
|
||
--due to refactoring I no longer need this, but will keep it for historical compatability with older blueprints
|
||
if component.item == "oscillatorcomponent" then component.item = "oscillator" end --these components are named strangely and break convention
|
||
if component.item == "concatenationcomponent" then component.item = "concatcomponent" end
|
||
if component.item == "exponentiationcomponent" then component.item = "powcomponent" end
|
||
if component.item == "regexfind" then component.item = "regexcomponent" end
|
||
if component.item == "signalcheck" then component.item = "signalcheckcomponent" end
|
||
if component.item == "squareroot" then component.item = "squarerootcomponent" end
|
||
|
||
|
||
local item_to_add = use_fpga and ItemPrefab.GetItemPrefab("fpgacircuit") or ItemPrefab.GetItemPrefab(component.item)
|
||
local component_position = Vector2(component.position.x, component.position.y)
|
||
--print(tostring(component))
|
||
--print(item_to_add)
|
||
--print(blue_prints.most_recent_circuitbox)
|
||
--print(blue_prints.most_recent_circuitbox.GetComponentString("CircuitBox"))
|
||
--print(item_to_add)
|
||
--print(component.name)
|
||
--print(component_position)
|
||
--print(component.item)
|
||
|
||
if item_to_add == nil then
|
||
print("Error: Invalid component data")
|
||
return false
|
||
end
|
||
|
||
blue_prints.most_recent_circuitbox.GetComponentString("CircuitBox").AddComponent(item_to_add, component_position)
|
||
--print(string.format("Added component %s at position (%.2f, %.2f)", use_fpga and "fpgacircuit" or component.item, component_position.x, component_position.y))
|
||
end
|
||
|
||
function blue_prints.add_all_components_to_circuitbox(components, index, inventory_status)
|
||
if blue_prints.most_recent_circuitbox == nil then
|
||
print("No circuitbox detected")
|
||
return
|
||
end
|
||
|
||
index = index or 1 -- Start with the first component if no index is provided
|
||
inventory_status = inventory_status or blue_prints.check_inventory_for_requirements(components)
|
||
|
||
if index <= #components then
|
||
local component = components[index]
|
||
local use_fpga = inventory_status[component.item] and inventory_status[component.item] > 0
|
||
|
||
blue_prints.add_component_to_circuitbox(component, use_fpga)
|
||
|
||
if use_fpga then
|
||
inventory_status[component.item] = inventory_status[component.item] - 1
|
||
if inventory_status[component.item] == 0 then
|
||
inventory_status[component.item] = nil
|
||
end
|
||
end
|
||
|
||
-- Schedule the next addition with a delay
|
||
Timer.Wait(function() blue_prints.add_all_components_to_circuitbox(components, index + 1, inventory_status) end,
|
||
blue_prints.time_delay_between_loops)
|
||
else
|
||
-- If all components are added, print a message
|
||
--print("All components added.")
|
||
has_load_completed_array["add_components_complete"] = true
|
||
end
|
||
end
|
||
|
||
function blue_prints.add_wires_to_circuitbox_recursive(wires, index)
|
||
if blue_prints.most_recent_circuitbox == nil then
|
||
print("no circuitbox detected")
|
||
return
|
||
end
|
||
|
||
local first_connection = nil
|
||
local second_connection = nil
|
||
|
||
local components = blue_prints.most_recent_circuitbox.GetComponentString("CircuitBox").Components
|
||
local input_output_nodes = blue_prints.most_recent_circuitbox.GetComponentString("CircuitBox").InputOutputNodes
|
||
local input_connection_node = blue_prints.getNthValue(input_output_nodes, 1)
|
||
local input_connections = input_connection_node.Connectors
|
||
local output_connection_node = blue_prints.getNthValue(input_output_nodes, 2)
|
||
local output_connections = output_connection_node.Connectors
|
||
|
||
if index > #wires then
|
||
--print("All wires added.")
|
||
has_load_completed_array["add_wires_complete"] = true
|
||
return
|
||
end
|
||
|
||
local wire = wires[index]
|
||
|
||
--select wire color
|
||
local wire_prefab = ItemPrefab.GetItemPrefab(tostring(wire.prefab))
|
||
LuaUserData.MakeMethodAccessible(Descriptors["Barotrauma.CircuitBoxUI"], "SelectWire")
|
||
local circuitbox_ui = blue_prints.most_recent_circuitbox.GetComponentString("CircuitBox").UI.SelectWire(nil,
|
||
wire_prefab)
|
||
|
||
for component_key, component_value in pairs(components) do
|
||
local connectors = component_value.Connectors
|
||
|
||
for i = 0, connectors.length - 1 do
|
||
if tostring(component_value.ID) == tostring(wire.from.target) and tostring(connectors[i].name) == tostring(wire.from.name) then
|
||
first_connection = connectors[i]
|
||
end
|
||
|
||
if tostring(component_value.ID) == tostring(wire.to.target) and tostring(connectors[i].name) == tostring(wire.to.name) then
|
||
second_connection = connectors[i]
|
||
end
|
||
end
|
||
end
|
||
|
||
|
||
if wire.from.target == nil then
|
||
local input_to_target = string.match(tostring(wire.from.name), "%d+")
|
||
first_connection = input_connections[tonumber(input_to_target) - 1]
|
||
end
|
||
|
||
if wire.to.target == nil then
|
||
local input_to_target = string.match(tostring(wire.to.name), "%d+")
|
||
second_connection = output_connections[tonumber(input_to_target) - 1]
|
||
end
|
||
|
||
if first_connection and second_connection then
|
||
blue_prints.most_recent_circuitbox.GetComponentString("CircuitBox").AddWire(first_connection, second_connection)
|
||
end
|
||
|
||
-- Recur to the next wire
|
||
Timer.Wait(function() blue_prints.add_wires_to_circuitbox_recursive(wires, index + 1) end,
|
||
blue_prints.time_delay_between_loops)
|
||
end
|
||
|
||
-- Check if labels have been reset
|
||
local function check_labels_changed(input_dict, output_dict)
|
||
local input_output_nodes = blue_prints.most_recent_circuitbox.GetComponentString("CircuitBox").InputOutputNodes
|
||
local input_connection_node = blue_prints.getNthValue(input_output_nodes, 1)
|
||
local output_connection_node = blue_prints.getNthValue(input_output_nodes, 2)
|
||
|
||
-- Check if any actual inputs/outputs differ from expected
|
||
for key, value in pairs(input_connection_node.ConnectionLabelOverrides) do
|
||
if value ~= (input_dict[key] or "") then
|
||
return false
|
||
end
|
||
end
|
||
|
||
for key, value in pairs(output_connection_node.ConnectionLabelOverrides) do
|
||
if value ~= (output_dict[key] or "") then
|
||
return false
|
||
end
|
||
end
|
||
|
||
return true
|
||
end
|
||
|
||
|
||
function blue_prints.change_input_output_labels(input_dict, output_dict, recursion_count)
|
||
if blue_prints.most_recent_circuitbox == nil then
|
||
print("no circuitbox detected")
|
||
return
|
||
end
|
||
|
||
local input_output_nodes = blue_prints.most_recent_circuitbox.GetComponentString("CircuitBox").InputOutputNodes
|
||
local input_connection_node = blue_prints.getNthValue(input_output_nodes, 1)
|
||
local output_connection_node = blue_prints.getNthValue(input_output_nodes, 2)
|
||
|
||
blue_prints.most_recent_circuitbox.GetComponentString("CircuitBox").SetConnectionLabelOverrides(
|
||
input_connection_node, input_dict)
|
||
blue_prints.most_recent_circuitbox.GetComponentString("CircuitBox").SetConnectionLabelOverrides(
|
||
output_connection_node, output_dict)
|
||
|
||
if check_labels_changed(input_dict, output_dict) then
|
||
--This function gets called twice, once to clear the box, one to change the IO
|
||
if has_load_completed_array["clear_IO_label_complete"] == false then
|
||
has_load_completed_array["clear_IO_label_complete"] = true
|
||
else
|
||
has_load_completed_array["change_input_output_labels_complete"] = true
|
||
end
|
||
else
|
||
if recursion_count < 5 then
|
||
Timer.Wait(function() blue_prints.change_input_output_labels(input_dict, output_dict, recursion_count + 1) end,
|
||
blue_prints.time_delay_between_loops)
|
||
else
|
||
print("Error: Failed to change input/output labels")
|
||
end
|
||
end
|
||
|
||
end
|
||
|
||
function blue_prints.add_advertisement_label(components, labels, inputNodePos, outputNodePos)
|
||
if blue_prints.most_recent_circuitbox == nil then
|
||
print("no circuitbox detected")
|
||
return
|
||
end
|
||
|
||
--just add an extra label to labels table thats to the right of the rightmost component or label
|
||
--dont do this if there is already an advertisement label
|
||
advertisement_header = "Blueprints"
|
||
|
||
for _, label in ipairs(labels) do --if there is already an advertisement, dont add another
|
||
if label.header and label.header == advertisement_header then
|
||
return
|
||
end
|
||
end
|
||
|
||
|
||
local furthestRight = blue_prints.getFurthestRightElement(components, labels, inputNodePos, outputNodePos)
|
||
|
||
--print("Furthest right element type:", furthestRight.type)
|
||
--print("Furthest right x-coordinate:", furthestRight.x)
|
||
--print("Furthest right y-coordinate:", furthestRight.y)
|
||
|
||
|
||
local function addManualLabel(id, color, posX, posY, sizeW, sizeH, header, body)
|
||
table.insert(labels, {
|
||
id = id,
|
||
color = color,
|
||
position = { x = tonumber(posX), y = tonumber(posY) },
|
||
size = { width = tonumber(sizeW), height = tonumber(sizeH) },
|
||
header = header,
|
||
body = body
|
||
})
|
||
end
|
||
|
||
addManualLabel(#labels, "#0082FF", furthestRight.x + 384, furthestRight.y, 512, 256, advertisement_header,
|
||
'Circuit made with Blueprints. \n \n Get it now on the steam workshop!')
|
||
end
|
||
|
||
function blue_prints.add_labels_to_circuitbox_recursive(labels, index)
|
||
if blue_prints.most_recent_circuitbox == nil then
|
||
print("no circuitbox detected")
|
||
return
|
||
end
|
||
|
||
-- Base case: if we've processed all labels, return
|
||
if index > #labels then
|
||
has_load_completed_array["add_labels_complete"] = true
|
||
return
|
||
end
|
||
|
||
-- Process the current label
|
||
local label = labels[index]
|
||
local x_offset_for_resizing = label.position.x - (label.size.width / 2) + 128
|
||
local y_offset_for_resizing = label.position.y + (label.size.height / 2) - 128
|
||
|
||
local label_position = Vector2(x_offset_for_resizing, y_offset_for_resizing)
|
||
blue_prints.most_recent_circuitbox.GetComponentString("CircuitBox").AddLabel(label_position)
|
||
|
||
-- Recursive call to process the next label
|
||
Timer.Wait(function() blue_prints.add_labels_to_circuitbox_recursive(labels, index + 1) end,
|
||
blue_prints.time_delay_between_loops)
|
||
end
|
||
|
||
function blue_prints.rename_all_labels_in_circuitbox(labels)
|
||
if blue_prints.most_recent_circuitbox == nil then
|
||
print("no circuitbox detected")
|
||
return
|
||
end
|
||
|
||
local label_nodes = blue_prints.most_recent_circuitbox.GetComponentString("CircuitBox").Labels
|
||
|
||
for i, label in ipairs(labels) do
|
||
--print(string.format(" Label %d:", i))
|
||
--print(string.format(" ID: %s", label.id))
|
||
--print(string.format(" Color: %s", label.color))
|
||
--print(string.format(" Position: (%.2f, %.2f)", label.position.x, label.position.y))
|
||
--print(string.format(" Size: %.2f x %.2f", label.size.width, label.size.height))
|
||
--print(string.format(" Header: %s", label.header))
|
||
--print(string.format(" Body: %s", label.body))
|
||
|
||
if label.header == nil then label.header = "" end
|
||
if label.body == nil then label.body = "" end
|
||
|
||
local label_node = blue_prints.getNthValue(label_nodes, i)
|
||
local label_header = blue_prints.net_limited_string_type(tostring(label.header))
|
||
local label_body = blue_prints.net_limited_string_type(tostring(label.body))
|
||
local label_color = blue_prints.hexToRGBA(label.color)
|
||
|
||
blue_prints.most_recent_circuitbox.GetComponentString("CircuitBox").RenameLabel(label_node, label_color,
|
||
label_header, label_body)
|
||
end
|
||
|
||
--print("All labels added.")
|
||
has_load_completed_array["rename_labels_complete"] = true
|
||
end
|
||
|
||
local function resize_label(label_node, direction, resize_vector)
|
||
if blue_prints.most_recent_circuitbox == nil then
|
||
print("no circuitbox detected")
|
||
return
|
||
end
|
||
|
||
blue_prints.most_recent_circuitbox.GetComponentString("CircuitBox").ResizeNode(label_node, direction, resize_vector)
|
||
end
|
||
|
||
|
||
function blue_prints.resize_labels(labels_from_blueprint)
|
||
if blue_prints.most_recent_circuitbox == nil then
|
||
print("no circuitbox detected")
|
||
return
|
||
end
|
||
|
||
local label_nodes_in_box = blue_prints.most_recent_circuitbox.GetComponentString("CircuitBox").Labels
|
||
|
||
for i, label_in_blueprint in ipairs(labels_from_blueprint) do
|
||
local label_node = blue_prints.getNthValue(label_nodes_in_box, i)
|
||
|
||
local amount_to_expand_x = label_in_blueprint.size.width - label_node.size.X
|
||
amount_to_expand_x = amount_to_expand_x
|
||
local amount_to_expand_y = label_in_blueprint.size.height - label_node.size.Y
|
||
|
||
local expansion_vector = Vector2(amount_to_expand_x, -amount_to_expand_y)
|
||
|
||
|
||
blue_prints.most_recent_circuitbox.GetComponentString("CircuitBox").ResizeNode(label_node, 2, expansion_vector) --2 is expand right
|
||
|
||
--I dont know why, but if you dont have enough delay here, the labels will not resize properly
|
||
--the second resize will somehow overwrite the other axis with its non-resized version.
|
||
--ie if you were to resize a 256x256 into a 512x512, it would become a 256x512.
|
||
local resize_delay = (blue_prints.time_delay_between_loops * 8)
|
||
|
||
Timer.Wait(function() resize_label(label_node, 1, expansion_vector) end, resize_delay) --the commands override each other if sent too fast. 1 is expand down.
|
||
end
|
||
|
||
has_load_completed_array["resize_labels_complete"] = true
|
||
end
|
||
|
||
function blue_prints.update_values_in_components(components_from_blueprint)
|
||
if blue_prints.most_recent_circuitbox == nil then
|
||
print("no circuitbox detected")
|
||
return
|
||
end
|
||
|
||
local components_in_box = blue_prints.most_recent_circuitbox.GetComponentString("CircuitBox").Components
|
||
|
||
for index, component_in_box in ipairs(components_in_box) do
|
||
local component_to_copy = components_from_blueprint[index]
|
||
|
||
local component_class_to_change = component_in_box.Item.GetComponentString(component_to_copy.class.name)
|
||
if component_class_to_change then
|
||
for attr, value in pairs(component_to_copy.class.attributes) do
|
||
--print(" " .. attr .. ":", value)
|
||
|
||
|
||
--print(component_class_to_change)
|
||
--print(tostring(component_class_to_change[attr]))
|
||
|
||
local success = false
|
||
local result
|
||
|
||
|
||
--print(attr)
|
||
local is_actually_editable = false
|
||
local my_editables = component_in_box.Item.GetInGameEditableProperties(false)
|
||
for tuple in my_editables do
|
||
--print(tuple.Item2.name, ' = ', tuple.Item2.GetValue(tuple.Item1))
|
||
if tostring(tuple.Item2.name) == tostring(attr) then
|
||
is_actually_editable = true
|
||
break
|
||
end
|
||
end
|
||
|
||
|
||
if is_actually_editable then --only attempt load if its actually editable
|
||
-- First attempt (string version)
|
||
if not success then
|
||
success, result = pcall(function()
|
||
component_class_to_change[attr] = value
|
||
return "String operation successful"
|
||
end)
|
||
end
|
||
|
||
-- Second attempt (number version)
|
||
if not success then
|
||
success, result = pcall(function()
|
||
component_class_to_change[attr] = tonumber(value)
|
||
return "Number operation successful"
|
||
end)
|
||
end
|
||
|
||
-- Third attempt (bool version)
|
||
if not success then
|
||
success, result = pcall(function()
|
||
component_class_to_change[attr] = blue_prints.string_to_bool(value)
|
||
return "Boolean operation successful"
|
||
end)
|
||
end
|
||
|
||
|
||
|
||
--oscillator is a special case because it uses enums
|
||
if component_to_copy.class.name == "OscillatorComponent" then
|
||
if tostring(attr) == "OutputType" then
|
||
if value == "Pulse" then component_class_to_change.OutputType = component_class_to_change
|
||
.WaveType.Pulse end
|
||
if value == "Sawtooth" then component_class_to_change.OutputType = component_class_to_change
|
||
.WaveType.Sawtooth end
|
||
if value == "Sine" then component_class_to_change.OutputType = component_class_to_change
|
||
.WaveType.Sine end
|
||
if value == "Square" then component_class_to_change.OutputType = component_class_to_change
|
||
.WaveType.Square end
|
||
if value == "Triangle" then component_class_to_change.OutputType = component_class_to_change
|
||
.WaveType.Triangle end
|
||
end
|
||
if tostring(attr) == "Frequency" then
|
||
component_class_to_change.Frequency = tonumber(value)
|
||
end
|
||
success = true
|
||
end
|
||
|
||
|
||
if success then
|
||
--print("Operation succeeded:", result)
|
||
else
|
||
print("All operations failed. Last error: ", result)
|
||
print("Component type that failed: ", component_class_to_change.name)
|
||
end
|
||
|
||
|
||
--print("Game mode: ", Game.GameSession.GameMode.Name)
|
||
if Game.GameSession ~= nil then --a nil check for the sub editor
|
||
local gameModeName = tostring(Game.GameSession.GameMode.Name)
|
||
if not Game.GameSession.GameMode.IsSinglePlayer then --these dont exist in single player so will cause a crash if not avoided.
|
||
local property = component_class_to_change.SerializableProperties[Identifier(attr)]
|
||
Networking.CreateEntityEvent(component_in_box.Item,
|
||
Item.ChangePropertyEventData(property, component_class_to_change))
|
||
end
|
||
end
|
||
end
|
||
end
|
||
end
|
||
end
|
||
|
||
--print("All values updated inside components.")
|
||
has_load_completed_array["update_values_in_components_complete"] = true
|
||
end
|
||
|
||
|
||
-- Check if input/output nodes have moved to correct positions
|
||
local function check_input_output_positions(expected_input_pos, expected_output_pos)
|
||
local input_output_nodes = blue_prints.most_recent_circuitbox.GetComponentString("CircuitBox").InputOutputNodes
|
||
local input_connection_node = blue_prints.getNthValue(input_output_nodes, 1)
|
||
local output_connection_node = blue_prints.getNthValue(input_output_nodes, 2)
|
||
|
||
local input_pos_str = ""
|
||
local output_pos_str = ""
|
||
local actual_input_pos_str = ""
|
||
local actual_output_pos_str = ""
|
||
|
||
--find the strings for the expected and actual positions
|
||
if input_connection_node and input_connection_node.Position then
|
||
input_pos_str = type(expected_input_pos) == "table" and string.format("{X:%d Y:%d}", expected_input_pos.x, expected_input_pos.y) or tostring(expected_input_pos)
|
||
output_pos_str = type(expected_output_pos) == "table" and string.format("{X:%d Y:%d}", expected_output_pos.x, expected_output_pos.y) or tostring(expected_output_pos)
|
||
actual_input_pos_str = tostring(input_connection_node.Position)
|
||
actual_output_pos_str = tostring(output_connection_node.Position)
|
||
end
|
||
|
||
if actual_input_pos_str == input_pos_str and actual_output_pos_str == output_pos_str then
|
||
--print("Input/output nodes moved to correct positions")
|
||
return true
|
||
else
|
||
--print("Input/output nodes not in correct positions")
|
||
--print("Expected input position: ", input_pos_str)
|
||
--print("Actual input position: ", actual_input_pos_str)
|
||
--print("Expected output position: ", output_pos_str)
|
||
--print("Actual output position: ", actual_output_pos_str)
|
||
end
|
||
return false
|
||
end
|
||
|
||
|
||
|
||
function blue_prints.move_input_output_nodes(inputNodePos, outputNodePos, recursion_count)
|
||
if blue_prints.most_recent_circuitbox == nil then
|
||
print("no circuitbox detected")
|
||
return
|
||
end
|
||
|
||
local input_output_nodes = blue_prints.most_recent_circuitbox.GetComponentString("CircuitBox").InputOutputNodes
|
||
local input_connection_node = blue_prints.getNthValue(input_output_nodes, 1)
|
||
local output_connection_node = blue_prints.getNthValue(input_output_nodes, 2)
|
||
|
||
|
||
|
||
local sacrificial_immutable_array_input = blue_prints.immutable_array_type.Create(input_connection_node)
|
||
local input_connection_node_in_immutable_aray = sacrificial_immutable_array_input.Add(input_connection_node)
|
||
|
||
|
||
local input_delta_x = inputNodePos.x - input_connection_node.Position.X
|
||
local input_delta_y = inputNodePos.y - input_connection_node.Position.Y
|
||
local move_input_vector = Vector2(input_delta_x, input_delta_y)
|
||
|
||
blue_prints.most_recent_circuitbox.GetComponentString("CircuitBox").MoveComponent(move_input_vector,
|
||
input_connection_node_in_immutable_aray)
|
||
|
||
|
||
|
||
local sacrificial_immutable_array_output = blue_prints.immutable_array_type.Create(output_connection_node)
|
||
local output_connection_node_in_immutable_aray = sacrificial_immutable_array_output.Add(output_connection_node)
|
||
|
||
local output_delta_x = outputNodePos.x - output_connection_node.Position.X
|
||
local output_delta_y = outputNodePos.y - output_connection_node.Position.Y
|
||
local move_output_vector = Vector2(output_delta_x, output_delta_y)
|
||
|
||
blue_prints.most_recent_circuitbox.GetComponentString("CircuitBox").MoveComponent(move_output_vector,
|
||
output_connection_node_in_immutable_aray)
|
||
|
||
--this is used by both clear circuitbox and to reposition later
|
||
--clear IO label must be done first, otherwise the increased width will thrown the numbers off
|
||
if check_input_output_positions(inputNodePos, outputNodePos) and has_load_completed_array["clear_IO_label_complete"] then
|
||
if has_load_completed_array["clear_IO_position_complete"] == false then
|
||
has_load_completed_array["clear_IO_position_complete"] = true
|
||
else
|
||
|
||
has_load_completed_array["move_input_output_nodes_complete"] = true
|
||
end
|
||
else
|
||
if recursion_count < 5 then
|
||
local new_recursion_count = recursion_count + 1
|
||
Timer.Wait(function() blue_prints.move_input_output_nodes(inputNodePos, outputNodePos, new_recursion_count) end,
|
||
blue_prints.time_delay_between_loops)
|
||
else
|
||
print("Error: Failed to move input/output nodes")
|
||
end
|
||
end
|
||
end
|
||
|
||
function blue_prints.reset_io()
|
||
if blue_prints.most_recent_circuitbox == nil then
|
||
print("no circuitbox detected")
|
||
return false
|
||
end
|
||
|
||
-- Stage 1: Reset the labels on the input output panels
|
||
local empty_input = {
|
||
signal_in1 = "", signal_in2 = "", signal_in3 = "", signal_in4 = "",
|
||
signal_in5 = "", signal_in6 = "", signal_in7 = "", signal_in8 = ""
|
||
}
|
||
local empty_output = {
|
||
signal_out1 = "", signal_out2 = "", signal_out3 = "", signal_out4 = "",
|
||
signal_out5 = "", signal_out6 = "", signal_out7 = "", signal_out8 = ""
|
||
}
|
||
blue_prints.change_input_output_labels(empty_input, empty_output, 0)
|
||
|
||
-- Stage 2: Move input/output nodes to default positions
|
||
local move_input_vector = Vector2(-512, 0)
|
||
local move_output_vector = Vector2(512, 0)
|
||
local initial_recursion_count = 0
|
||
blue_prints.move_input_output_nodes(move_input_vector, move_output_vector, initial_recursion_count)
|
||
|
||
|
||
end
|
||
|
||
function blue_prints.clear_circuitbox_recursive(batch_size, recursion_count)
|
||
--this function removes all components, but does not change IO
|
||
if blue_prints.most_recent_circuitbox == nil then
|
||
print("no circuitbox detected")
|
||
return
|
||
end
|
||
|
||
batch_size = batch_size or 10 -- Default batch size of 10
|
||
local circuit_box = blue_prints.most_recent_circuitbox.GetComponentString("CircuitBox")
|
||
local something_cleared = false
|
||
|
||
-- Clear components in batches
|
||
local components = circuit_box.Components
|
||
if #components > 0 then
|
||
local batch = blue_prints.immutable_array_type.Create(blue_prints.getNthValue(components, 1))
|
||
local count = 0
|
||
|
||
for _, component in ipairs(components) do
|
||
if count < batch_size then
|
||
batch = batch.Add(component)
|
||
count = count + 1
|
||
something_cleared = true
|
||
else
|
||
break
|
||
end
|
||
end
|
||
|
||
if count > 0 then
|
||
circuit_box.RemoveComponents(batch)
|
||
end
|
||
end
|
||
|
||
-- Clear labels in batches
|
||
local labels = circuit_box.Labels
|
||
if #labels > 0 and not something_cleared then
|
||
local batch = blue_prints.immutable_array_type.Create(blue_prints.getNthValue(labels, 1))
|
||
local count = 0
|
||
|
||
for _, label in ipairs(labels) do
|
||
if count < batch_size then
|
||
batch = batch.Add(label)
|
||
count = count + 1
|
||
something_cleared = true
|
||
else
|
||
break
|
||
end
|
||
end
|
||
|
||
if count > 0 then
|
||
circuit_box.RemoveLabel(batch)
|
||
end
|
||
end
|
||
|
||
-- Clear wires in batches
|
||
local wires = circuit_box.Wires
|
||
if #wires > 0 and not something_cleared then
|
||
local batch = blue_prints.immutable_array_type.Create(blue_prints.getNthValue(wires, 1))
|
||
local count = 0
|
||
|
||
for _, wire in ipairs(wires) do
|
||
if count < batch_size then
|
||
batch = batch.Add(wire)
|
||
count = count + 1
|
||
something_cleared = true
|
||
else
|
||
break
|
||
end
|
||
end
|
||
|
||
if count > 0 then
|
||
circuit_box.RemoveWires(batch)
|
||
end
|
||
end
|
||
|
||
-- If we cleared something, schedule next batch
|
||
if something_cleared and recursion_count < 20 then
|
||
Timer.Wait(function()
|
||
blue_prints.clear_circuitbox_recursive(batch_size, recursion_count + 1)
|
||
end, blue_prints.time_delay_between_loops)
|
||
elseif something_cleared and recursion_count >= 20 then
|
||
print("Recursion limit reached. Clearing circuitbox failed.")
|
||
else
|
||
-- Everything is cleared
|
||
has_load_completed_array["clear_components_complete"] = true
|
||
end
|
||
end
|
||
|
||
-- Update the original clear_circuitbox function to use the recursive version
|
||
function blue_prints.clear_circuitbox()
|
||
-- Reset inputs and outputs to default simultaneously to clearing components
|
||
blue_prints.reset_io()
|
||
|
||
--If you remove too fast it causes baro to have event system problems.
|
||
--without this you get unpredictable results
|
||
blue_prints.clear_circuitbox_recursive(blue_prints.component_batch_size, 0)
|
||
end
|
||
|
||
|
||
|
||
function blue_prints.construct_blueprint_steps(inputs, outputs, components, wires, labels, inputNodePos, outputNodePos)
|
||
-- Reset all completion flags
|
||
for key, _ in pairs(has_load_completed_array) do
|
||
has_load_completed_array[key] = false
|
||
end
|
||
|
||
-- Track which steps have been started
|
||
local steps_started = {}
|
||
|
||
local largest_component_count = math.max(#components, #wires, #labels) --it resets every time, so you can just use largest
|
||
|
||
-- Maximum time to wait for each step (in milliseconds)
|
||
local TIMEOUT_PER_STEP = ((blue_prints.time_delay_between_loops * largest_component_count) / 1000) + 2 -- if wait longer than this, something has gone wrong
|
||
local step_start_time = nil
|
||
|
||
local function check_timeout()
|
||
--if step_start_time then
|
||
-- print(os.time() - step_start_time)
|
||
--end
|
||
|
||
if step_start_time and os.time() - step_start_time > TIMEOUT_PER_STEP then
|
||
return true
|
||
end
|
||
return false
|
||
end
|
||
|
||
local function end_build_testing_and_cleanup()
|
||
blue_prints.delayed_loading_complete_array_check()
|
||
blue_prints.delayed_loading_complete_unit_test()
|
||
end
|
||
|
||
|
||
local function check_progress()
|
||
|
||
-- Check for timeouts
|
||
if check_timeout() then
|
||
print("Step has timed out.")
|
||
end_build_testing_and_cleanup()
|
||
return
|
||
end
|
||
|
||
-- Step 1: Clear circuitbox must complete first
|
||
if not has_load_completed_array["clear_components_complete"] or
|
||
not has_load_completed_array["clear_IO_position_complete"] or
|
||
not has_load_completed_array["clear_IO_label_complete"] then
|
||
if not steps_started["clear"] then
|
||
steps_started["clear"] = true
|
||
step_start_time = os.time()
|
||
blue_prints.clear_circuitbox()
|
||
end
|
||
return Timer.Wait(check_progress, blue_prints.time_delay_between_loops)
|
||
end
|
||
|
||
-- After clear is complete, these steps can run in parallel:
|
||
|
||
|
||
|
||
-- Parallel Step: Add components
|
||
if not has_load_completed_array["add_components_complete"] then
|
||
if not steps_started["components"] then
|
||
steps_started["components"] = true
|
||
step_start_time = os.time()
|
||
blue_prints.add_all_components_to_circuitbox(components)
|
||
end
|
||
end
|
||
|
||
-- Parallel Step: Add labels
|
||
if not has_load_completed_array["add_labels_complete"] then
|
||
if not steps_started["labels"] then
|
||
steps_started["labels"] = true
|
||
step_start_time = os.time()
|
||
blue_prints.add_labels_to_circuitbox_recursive(labels, 1)
|
||
end
|
||
end
|
||
|
||
-- Parallel Step: Change I/O labels
|
||
if not has_load_completed_array["change_input_output_labels_complete"] then
|
||
if not steps_started["io_labels"] then
|
||
steps_started["io_labels"] = true
|
||
step_start_time = os.time()
|
||
blue_prints.change_input_output_labels(inputs, outputs)
|
||
end
|
||
end
|
||
|
||
-- These steps need to wait for their dependencies:
|
||
|
||
-- Add wires (needs components)
|
||
if has_load_completed_array["add_components_complete"] and
|
||
not has_load_completed_array["add_wires_complete"] then
|
||
if not steps_started["wires"] then
|
||
steps_started["wires"] = true
|
||
step_start_time = os.time()
|
||
blue_prints.add_wires_to_circuitbox_recursive(wires, 1)
|
||
end
|
||
end
|
||
|
||
-- Update component values (needs components)
|
||
if has_load_completed_array["add_components_complete"] and
|
||
not has_load_completed_array["update_values_in_components_complete"] then
|
||
if not steps_started["update_values"] then
|
||
steps_started["update_values"] = true
|
||
step_start_time = os.time()
|
||
blue_prints.update_values_in_components(components)
|
||
end
|
||
end
|
||
|
||
-- Rename labels (needs labels)
|
||
if has_load_completed_array["add_labels_complete"] and
|
||
not has_load_completed_array["rename_labels_complete"] then
|
||
if not steps_started["rename"] then
|
||
step_start_time = os.time()
|
||
steps_started["rename"] = true
|
||
blue_prints.rename_all_labels_in_circuitbox(labels)
|
||
end
|
||
end
|
||
|
||
-- Resize labels (needs rename labels)
|
||
if has_load_completed_array["rename_labels_complete"] and
|
||
not has_load_completed_array["resize_labels_complete"] then
|
||
if not steps_started["resize"] then
|
||
step_start_time = os.time()
|
||
steps_started["resize"] = true
|
||
blue_prints.resize_labels(labels)
|
||
end
|
||
end
|
||
|
||
-- Move I/O nodes (needs I/O labels)
|
||
if has_load_completed_array["change_input_output_labels_complete"] and
|
||
not has_load_completed_array["move_input_output_nodes_complete"] then
|
||
if not steps_started["move_nodes"] then
|
||
step_start_time = os.time()
|
||
steps_started["move_nodes"] = true
|
||
local initial_recursion_count = 0
|
||
blue_prints.move_input_output_nodes(inputNodePos, outputNodePos, initial_recursion_count)
|
||
end
|
||
end
|
||
|
||
-- Continue checking progress
|
||
if not (has_load_completed_array["move_input_output_nodes_complete"] and
|
||
has_load_completed_array["resize_labels_complete"] and
|
||
has_load_completed_array["update_values_in_components_complete"] and
|
||
has_load_completed_array["add_wires_complete"])
|
||
then
|
||
return Timer.Wait(check_progress, blue_prints.time_delay_between_loops)
|
||
end
|
||
|
||
-- Final checks when everything is complete
|
||
end_build_testing_and_cleanup()
|
||
end
|
||
|
||
-- Start the process
|
||
check_progress()
|
||
end
|
||
|
||
|
||
|
||
|
||
|
||
|
||
function blue_prints.construct_blueprint(provided_path)
|
||
if Character.Controlled == nil then
|
||
print("you dont have a character")
|
||
return
|
||
end
|
||
if blue_prints.most_recent_circuitbox == nil then
|
||
print("no circuitbox detected")
|
||
return
|
||
end
|
||
|
||
local is_locked = blue_prints.get_circuit_box_lock_status()
|
||
if is_locked then
|
||
print("Circuit box is locked. Wiring is not possible.")
|
||
GUI.AddMessage('Wiring Locked', Color.Red)
|
||
return
|
||
end
|
||
|
||
local isValid, message = blue_prints.validate_blueprint_file(provided_path)
|
||
if isValid then
|
||
--print("Blueprint file is valid")
|
||
else
|
||
print("Blueprint validation failed: " .. message)
|
||
GUI.AddMessage('Blueprint File Invalid', Color.Red)
|
||
return
|
||
end
|
||
|
||
if Game.Paused then --the load will fail if you attempt it while paused. This fixes that.
|
||
print("Unpause the game to complete loading your circuit.")
|
||
Timer.Wait(function() blue_prints.construct_blueprint(provided_path) end, 1000)
|
||
return
|
||
end
|
||
|
||
-- Check if the filename already ends with .txt
|
||
if not string.match(provided_path, "%.txt$") then
|
||
-- Add .txt if it's not already present
|
||
provided_path = provided_path .. ".txt"
|
||
end
|
||
|
||
local file_path = blue_prints.normalizePath(blue_prints.save_path .. "/" .. provided_path)
|
||
path_to_loaded_file = file_path -- Keep track for unit testing
|
||
|
||
-- Use our new read function
|
||
local xmlContent = blue_prints.readFileContents(file_path)
|
||
|
||
if xmlContent then
|
||
-- Parse the XML content
|
||
local inputs, outputs, components, wires, labels, inputNodePos, outputNodePos = blue_prints.parseXML(xmlContent)
|
||
|
||
-- Check inventory for required components
|
||
local missing_components = blue_prints.check_inventory_for_requirements(components)
|
||
|
||
local all_needed_items_are_present = true
|
||
for _, count in pairs(missing_components) do
|
||
if count > 0 then
|
||
all_needed_items_are_present = false
|
||
break
|
||
end
|
||
end
|
||
|
||
if all_needed_items_are_present then
|
||
print("All required components are present! Now loading blueprint...")
|
||
GUI.AddMessage('File Loading...', Color.White)
|
||
|
||
-- Extract folder name if present, otherwise use root
|
||
local folder = "[Root Directory]"
|
||
local folder_path = provided_path:match("^(.-)/")
|
||
if folder_path then
|
||
folder = folder_path
|
||
end
|
||
|
||
--save the folder and filename
|
||
local filename = provided_path:match("([^/\\]+)$") or provided_path -- Get everything after last / or \
|
||
blue_prints.most_recently_used_blueprint_name = filename:gsub("%.txt$", "") -- Remove .txt if present
|
||
blue_prints.most_recent_folder = folder
|
||
|
||
blue_prints.construct_blueprint_steps(inputs, outputs, components, wires, labels, inputNodePos,outputNodePos)
|
||
|
||
else
|
||
print("You are missing: ")
|
||
GUI.AddMessage('Not Enough Components', Color.Red)
|
||
for name, count in pairs(missing_components) do
|
||
if count > 0 then
|
||
print(name .. ": " .. count)
|
||
end
|
||
end
|
||
end
|
||
else
|
||
print("file not found")
|
||
print("saved designs:")
|
||
blue_prints.print_all_saved_files()
|
||
end
|
||
end
|
||
|
||
function blue_prints.delayed_loading_complete_array_check()
|
||
local function allTrue(array)
|
||
for key, value in pairs(array) do
|
||
if value ~= true then
|
||
return false -- If any value is not true, return false
|
||
end
|
||
end
|
||
return true -- If the loop completes, all values are true
|
||
end
|
||
|
||
local result = allTrue(has_load_completed_array)
|
||
if result then
|
||
GUI.AddMessage('Load Complete', Color.White)
|
||
print("Blueprint loading complete")
|
||
else
|
||
GUI.AddMessage('Loading Failed', Color.Red)
|
||
|
||
local message_box = GUI.MessageBox('Load Failed',
|
||
'Your circuit has failed to load. One of the load functions has failed to complete. Hit F3 for more details. \n \nTry loading it again. \n\nBarotrauma circuitbox code is sensitive to sending too many commands too fast. Try slowing things down with the delay slider (above the load button) and try again. This can help on laggy servers. \n \nIf the problem persists please report this bug on the steam workshop page. Include a download link to your saved blueprint file and a screenshot of your console text (you can see that by hitting F3)',
|
||
{ 'OK' })
|
||
|
||
local ok_button = message_box.Buttons[0] or message_box.Buttons[1]
|
||
|
||
ok_button.OnClicked = function()
|
||
message_box.Close()
|
||
end
|
||
|
||
for key, value in pairs(has_load_completed_array) do
|
||
print(tostring(key) .. ": " .. tostring(value))
|
||
end
|
||
end
|
||
end
|
||
|
||
function blue_prints.delayed_loading_complete_unit_test()
|
||
if blue_prints.unit_tests_enabled then
|
||
xml_of_loaded_circuit = blue_prints.prepare_circuitbox_xml_for_saving()
|
||
--run a unit test here to make sure it works
|
||
local load_test_results = blue_prints.loading_complete_unit_test(path_to_loaded_file, xml_of_loaded_circuit)
|
||
print("Passed loading unit test: " .. tostring(load_test_results))
|
||
|
||
if load_test_results then
|
||
--GUI.AddMessage('Load Complete!', Color.White)
|
||
else
|
||
GUI.AddMessage('Load Failed!', Color.Red)
|
||
|
||
local message_box = GUI.MessageBox('Load Failed',
|
||
'Your circuit has failed to load.\n\nYour blueprint file might be from an earlier version of Blueprints and nothing is actually wrong. Try saving it again (overwriting the original) to update your blueprint file to the latest version.\n\nIf you are certain your file is up to date try loading it again. Do not move or change anything during loading: the loaded circuit must match the blueprint file EXACTLY in order for you not to see this message.\n\nThis also means if the inputs change any values in any component the unit test will also fail. Same thing if you have some value that changes over time, like RGB or timing values from an oscillator. So the circuit might still be ok, it just does not match your save exactly.\n\nBarotrauma circuitbox code is sensitive to sending too many commands too fast. Try slowing things down with the delay slider (above the load button) and try again.\n\nIf none of these exceptions apply and the problem persists please report this bug on the steam workshop page or the discord. Include a download link to your saved blueprint file and a screenshot of your console text (you can see that by hitting F3)',
|
||
{ 'OK' })
|
||
|
||
local ok_button = message_box.Buttons[0] or message_box.Buttons[1]
|
||
|
||
ok_button.OnClicked = function()
|
||
message_box.Close()
|
||
end
|
||
|
||
for key, value in pairs(has_load_completed_array) do
|
||
print(tostring(key) .. ": " .. tostring(value))
|
||
end
|
||
|
||
end
|
||
end
|
||
end
|