Compare commits

...

10 Commits

11 changed files with 277 additions and 45 deletions

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<Items>
<Item name="Flip-Flop Component" identifier="flipflopcomponent" category="Electrical" scale="0.5" impactsoundtag="impact_metal_light">
<Item identifier="flipflopcomponent" category="Electrical" scale="0.5" impactsoundtag="impact_metal_light">
<InventoryIcon texture="luacomp_inv.png" sourcerect="0,0,64,52" origin="0.5,0.5" />
<Sprite texture="luacomp_sprite.png" depth="0.8" sourcerect="0,0,32,32" origin="0.5,0.5" />
<Body width="32" height="24" density="30" />
@@ -19,7 +19,26 @@
</ConnectionPanel>
</Item>
<Item name="Counter Component" identifier="countercomponent" category="Electrical" Tags="smallitem,logic" maxstacksize="8" scale="0.5" impactsoundtag="impact_metal_light">
<Item identifier="activeflipflopcomponent" category="Electrical" scale="0.5" impactsoundtag="impact_metal_light">
<InventoryIcon texture="luacomp_inv.png" sourcerect="0,0,64,52" origin="0.5,0.5" />
<Sprite texture="luacomp_sprite.png" depth="0.8" sourcerect="0,0,32,32" origin="0.5,0.5" />
<Body width="32" height="24" density="30" />
<Holdable selectkey="Select" pickkey="Use" aimpos="65,-10" handle1="0,0" attachable="true" aimable="true" PickingTime="5.0" slots="Any,RightHand,LeftHand" msg="ItemMsgDetachWrench">
<RequiredItem items="wrench" type="Equipped" />
<StatusEffect type="Always" target="This" stackable="false">
<LuaHook name="activeflipflopcomponent.update" />
</StatusEffect>
</Holdable>
<MemoryComponent canbeselected="false" MaxValueLength="1" AllowInGameEditing="false" Value="0" />
<ConnectionPanel selectkey="Action" canbeselected="true" msg="ItemMsgRewireScrewdriver" hudpriority="10">
<GuiFrame relativesize="0.2,0.32" minsize="400,350" maxsize="480,420" anchor="Center" style="ConnectionPanel" />
<RequiredItem items="screwdriver" type="Equipped" />
<input name="input" displayname="connection.input" />
<output name="state_out" displayname="connection.state_out" />
</ConnectionPanel>
</Item>
<Item identifier="countercomponent" category="Electrical" Tags="smallitem,logic" maxstacksize="8" scale="0.5" impactsoundtag="impact_metal_light">
<InventoryIcon texture="luacomp_inv.png" sourcerect="0,0,64,52" origin="0.5,0.5" />
<Sprite texture="luacomp_sprite.png" depth="0.8" sourcerect="0,0,32,32" origin="0.5,0.5" />
<Body width="32" height="24" density="30" />
@@ -39,7 +58,27 @@
</ConnectionPanel>
</Item>
<item name="Reactor Controller Component" identifier="reactorcontrollercomponent" category="Electrical" Tags="smallitem,logic" maxstacksize="8" scale="0.5" impactsoundtag="impact_metal_light">
<Item identifier="activecountercomponent" category="Electrical" Tags="smallitem,logic" maxstacksize="8" scale="0.5" impactsoundtag="impact_metal_light">
<InventoryIcon texture="luacomp_inv.png" sourcerect="0,0,64,52" origin="0.5,0.5" />
<Sprite texture="luacomp_sprite.png" depth="0.8" sourcerect="0,0,32,32" origin="0.5,0.5" />
<Body width="32" height="24" density="30" />
<Holdable selectkey="Select" pickkey="Use" aimpos="65,-10" handle1="0,0" attachable="true" aimable="true" PickingTime="5.0" slots="Any,RightHand,LeftHand" msg="ItemMsgDetachWrench">
<RequiredItem items="wrench" type="Equipped" />
<StatusEffect type="Always" target="This" stackable="false">
<LuaHook name="activecountercomponent.update" />
</StatusEffect>
</Holdable>
<MemoryComponent canbeselected="false" MaxValueLength="200" AllowInGameEditing="false" Value="0" />
<AdderComponent canbeselected="false" ClampMin="0" ClampMax="100" />
<ConnectionPanel selectkey="Action" canbeselected="true" msg="ItemMsgRewireScrewdriver" hudpriority="10">
<GuiFrame relativesize="0.2,0.32" minsize="400,350" maxsize="480,420" anchor="Center" style="ConnectionPanel" />
<RequiredItem items="screwdriver" type="Equipped" />
<input name="input" displayname="connection.input" />
<output name="state_out" displayname="connection.state_out" />
</ConnectionPanel>
</Item>
<item identifier="reactorcontrollercomponent" category="Electrical" Tags="smallitem,logic" maxstacksize="8" scale="0.5" impactsoundtag="impact_metal_light">
<InventoryIcon texture="luacomp_inv.png" sourcerect="0,0,64,52" origin="0.5,0.5" />
<Sprite texture="luacomp_sprite.png" depth="0.8" sourcerect="0,0,32,32" origin="0.5,0.5" />
<Body width="32" height="24" density="30" />
@@ -63,4 +102,28 @@
<output name="fuel_low_out" displayname="connection.fuel_low_out" />
</ConnectionPanel>
</item>
<Item identifier="enginecontrollercomponent" category="Electrical" Tags="smallitem,logic" maxstacksize="8" scale="0.5" impactsoundtag="impact_metal_light">
<InventoryIcon texture="luacomp_inv.png" sourcerect="0,0,64,52" origin="0.5,0.5" />
<Sprite texture="luacomp_sprite.png" depth="0.8" sourcerect="0,0,32,32" origin="0.5,0.5" />
<Body width="32" height="24" density="30" />
<Holdable selectkey="Select" pickkey="Use" aimpos="65,-10" handle1="0,0" attachable="true" aimable="true" PickingTime="5.0" slots="Any,RightHand,LeftHand" msg="ItemMsgDetachWrench">
<RequiredItem items="wrench" type="Equipped" />
<StatusEffect type="Always" target="This" stackable="false">
<LuaHook name="enginecontrollercomponent.update" />
</StatusEffect>
</Holdable>
<ConnectionPanel selectkey="Action" canbeselected="true" msg="ItemMsgRewireScrewdriver" hudpriority="10">
<GuiFrame relativesize="0.2,0.32" minsize="400,350" maxsize="480,420" anchor="Center" style="ConnectionPanel" />
<RequiredItem items="screwdriver" type="Equipped" />
<input name="velocity_x_in" displayname="connection.velocity_x_in" />
<input name="current_velocity_x_in" displayname="connection.current_velocity_x_in" />
<input name="set_trm_target" displayname="connection.set_trm_target" />
<input name="set_trm_aggression" displayname="connection.set_trm_aggression" />
<input name="set_mode" displayname="connection.set_mode" />
<input name="set_silent" displayname="connection.set_silent" />
<output name="main_force_out" displayname="connection.force_out" />
<output name="boost_force_out" displayname="connection.boost_force_out" />
</ConnectionPanel>
</Item>
</Items>

View File

@@ -1,10 +1,13 @@
local moduleNames = {
"flipflopcomponent",
-- "activeflipflopcomponent",
"countercomponent",
-- "activecountercomponent",
"reactorcontrollercomponent",
"enginecontrollercomponent",
}
modPath = table.pack(...)[1] .. "/Lua/"
local modPath = table.pack(...)[1] .. "/Lua/"
for _, moduleName in ipairs(moduleNames) do
dofile(modPath .. moduleName .. ".lua")

View File

@@ -0,0 +1,36 @@
local allItems = {}
Hook.Add("item.created", "activecountercomponent.init", function(item)
if item.Prefab.Identifier == "activecountercomponent" then
allItems[item] = true
end
end)
local signalReceived = function(signal, connection)
local this = connection.Item
local mem = this.Components[2]
if signal.value == "" then return end
local input = tonumber(signal.value) or 1
if input > 0 then
if tonumber(mem.value) >= this.Components[3].clampMax then
mem.value = tostring(this.Components[3].clampMin)
else
mem.value = tostring(tonumber(mem.value) + 1)
end
elseif input == 0 then
mem.value = "0"
elseif input < 0 then
mem.value = tostring(-input)
end
end
local think = function()
for component, _ in pairs(allItems) do
component.SendSignal(component.Components[2].value, "state_out")
end
end
Hook.Add("think", "activecountercomponent.think", think)
Hook.Add("signalreceived.activecountercomponent", "activecountercomponent.signalReceived", signalReceived)

View File

@@ -0,0 +1,32 @@
local allItems = {}
Hook.Add("item.created", "activeflipflopcomponent.init", function(item)
if item.Prefab.Identifier == "activeflipflopcomponent" then
allItems[item] = true
end
end)
local signalReceived = function(signal, connection)
local this = connection.Item
local mem = this.Components[2]
if signal.value == "" then return end
local input = tonumber(signal.value) or 1
if input == 1 then
if mem.value == "0" then mem.value = "1" else mem.value = "0" end
elseif input == 0 then
mem.value = "0"
elseif input == -1 then
mem.value = "1"
end
end
local think = function()
for component, _ in pairs(allItems) do
component.SendSignal(component.Components[2].value, "state_out")
end
end
Hook.Add("think", "activeflipflopcomponent.think", think)
Hook.Add("signalreceived.activeflipflopcomponent", "activeflipflopcomponent.signalReceived", signalReceived)

View File

@@ -1,11 +1,3 @@
local allItems = {}
Hook.Add("item.created", "countercomponent.init", function(item)
if item.Prefab.Identifier == "countercomponent" then
allItems[item] = true
end
end)
local signalReceived = function(signal, connection)
local this = connection.Item
local mem = this.Components[2]
@@ -24,13 +16,8 @@ local signalReceived = function(signal, connection)
elseif input < 0 then
mem.value = tostring(-input)
end
this.SendSignal(mem.value, "state_out")
end
local think = function()
for component, _ in pairs(allItems) do
component.SendSignal(component.Components[2].value, "state_out")
end
end
Hook.Add("think", "countercomponent.think", think)
Hook.Add("signalreceived.countercomponent", "countercomponent.signalReceived", signalReceived)

View File

@@ -0,0 +1,90 @@
local allItems = {}
local defaultTable = {
velocity_x_in = 0,
current_velocity_x_in = 0,
set_trm_target = 20,
set_trm_aggression = 200,
set_mode = 1,
set_silent = 0,
previous_velocity_x_in = 0,
acceleration = 0,
}
Hook.Add("item.created", "enginecontrollercomponent.init", function(item)
if item.Prefab.Identifier == "enginecontrollercomponent" then
allItems[item] = {}
for k, v in pairs(defaultTable) do
allItems[item][k] = v
end
end
end)
local signalReceived = function(signal, connection)
local this = connection.Item
local mem = allItems[this]
local signalNum = tonumber(signal.value) or defaultTable[connection.Name]
local set_mode = mem.set_mode
if
mem[connection.Name] == signalNum or
connection.Name == "current_velocity_x_in" and set_mode ~= 0
then
return
end
mem[connection.Name] = signalNum
local main_force_out
local boost_force_out
local velocity_x_in = mem.velocity_x_in
if set_mode == 1 then
main_force_out = velocity_x_in
boost_force_out = 0
elseif set_mode == 2 then
main_force_out = velocity_x_in
boost_force_out = velocity_x_in
elseif set_mode == 0 then
local current_velocity_x_in = mem.current_velocity_x_in
local set_trm_target = mem.set_trm_target
if connection.Name == "current_velocity_x_in" then
mem.acceleration = (mem.previous_velocity_x_in - current_velocity_x_in)
mem.previous_velocity_x_in = current_velocity_x_in
end
local absolute_current_velocity = math.abs(current_velocity_x_in)
if set_trm_target - 0.25 < absolute_current_velocity and velocity_x_in * current_velocity_x_in > 0 then
local set_trm_aggression = mem.set_trm_aggression
local target_acceleration = - (absolute_current_velocity * set_trm_aggression) + (set_trm_target * set_trm_aggression)
if math.abs(velocity_x_in) > math.abs(target_acceleration) then
if current_velocity_x_in > 0 then
main_force_out = target_acceleration
else
main_force_out = -target_acceleration
end
else
main_force_out = velocity_x_in
end
else
main_force_out = velocity_x_in
end
boost_force_out = 0
end
if mem.set_silent == 1 then
main_force_out = main_force_out * 0.2
boost_force_out = boost_force_out * 0.2
end
this.SendSignal(main_force_out, "main_force_out")
this.SendSignal(boost_force_out, "boost_force_out")
end
Hook.Add("signalreceived.enginecontrollercomponent", "enginecontrollercomponent.signalReceived", signalReceived)

View File

@@ -1,11 +1,3 @@
local allItems = {}
Hook.Add("item.created", "flipflopcomponent.init", function(item)
if item.Prefab.Identifier == "flipflopcomponent" then
allItems[item] = true
end
end)
local signalReceived = function(signal, connection)
local this = connection.Item
local mem = this.Components[2]
@@ -20,13 +12,8 @@ local signalReceived = function(signal, connection)
elseif input == -1 then
mem.value = "1"
end
this.sendSignal(mem.value, "state_out")
end
local think = function()
for component, _ in pairs(allItems) do
component.SendSignal(component.Components[2].value, "state_out")
end
end
Hook.Add("think", "flipflopcomponent.think", think)
Hook.Add("signalreceived.flipflopcomponent", "flipflopcomponent.signalReceived", signalReceived)

View File

@@ -3,10 +3,10 @@ local allItems = {}
local defaultTable = {
load_value_in = 0,
fuel_in = 100,
efficiency_in = 100,
fission_efficiency_in = 75,
max_power_in = 20000,
silent_in = 0
set_efficiency = 100,
set_fission_efficiency = 75,
set_max_power = 20000,
set_silent = 0,
}
Hook.Add("item.created", "reactorcontrollercomponent.init", function(item)
@@ -23,12 +23,17 @@ local signalReceived = function(signal, connection)
local mem = allItems[this]
local signalNum = tonumber(signal.value) or defaultTable[connection.Name]
if mem[connection.Name] == signalNum then
return
end
mem[connection.Name] = signalNum
local turbineoutput = (mem.load_value_in / mem.max_power_in) * mem.efficiency_in
local fissionrate = turbineoutput / (mem.fuel_in / mem.fission_efficiency_in)
local turbineoutput = (mem.load_value_in / mem.set_max_power) * mem.set_efficiency
local fissionrate = turbineoutput / (mem.fuel_in / mem.set_fission_efficiency)
if mem.silent_in == 1 then
if mem.set_silent == 1 then
if turbineoutput > 10 then
turbineoutput = 10
end
@@ -37,8 +42,8 @@ local signalReceived = function(signal, connection)
end
end
this.SendSignal(tostring(turbineoutput), "turbine_output_out")
this.SendSignal(tostring(fissionrate), "fission_rate_out")
this.SendSignal(turbineoutput, "turbine_output_out")
this.SendSignal(fissionrate, "fission_rate_out")
end
Hook.Add("signalreceived.reactorcontrollercomponent", "reactorcontrollercomponent.signalReceived", signalReceived)

View File

@@ -2,4 +2,21 @@
Several Lua-based wiring components for the game [Barotrauma](https://barotraumagame.com/). Requires the [Lua for Barotrauma](https://steamcommunity.com/workshop/filedetails/?id=2559634234) mod to be installed.
The components are mainly designed to improve the performance of an advanced custom submarine called Daedalus but can be easily adapted to other submarines.
They are mainly designed to improve the performance of an advanced custom submarine called Daedalus by replacing large collections of vanilla components with a single Lua-based component.
## Design Considerations
You might notice some weird design decisions in the code as well as in-game. These decisions are summarized below.
### Usage of sub-components in item XML
As far as I know, Barotrauma does not have an easy way to store arbitrary variables in items. Instead, most custom component mods use a global Lua table that stores variables indexed by the item IDs they belong to. However, that comes with an important drawback: Lua tables are very slow, especially when accessed 60 times per second.
This is where the sub-components come in. They are used to store arbitrary values in their attributes, so editing them in-game is not recommended.
Specifically, the following sub-components are used depending on the stored variable type:
## Useful Resources
* [Barotrauma Modding Docs](https://regalis11.github.io/BaroModDoc/)
* [Lua For Barotrauma Docs](https://evilfactory.github.io/LuaCsForBarotrauma/lua-docs/)

View File

@@ -3,9 +3,18 @@
<entityname.flipflopcomponent>Flip-Flop Component</entityname.flipflopcomponent>
<entitydescription.flipflopcomponent>Switches state when receiving 1, forces state to X when receiving -X.</entitydescription.flipflopcomponent>
<entityname.countercomponent>Counter Component</entityname.countercomponent>\
<entityname.activeflipflopcomponent>Flip-Flop Component (Active)</entityname.activeflipflopcomponent>
<entitydescription.activeflipflopcomponent>Switches state when receiving 1, forces state to X when receiving -X. Constantly outputs state.</entitydescription.activeflipflopcomponent>
<entityname.countercomponent>Counter Component</entityname.countercomponent>
<entitydescription.countercomponent>Counts up to ClampMax when receiving 1, resets to ClampMin when reached, forces state to X when receiving -X.</entitydescription.countercomponent>
<entityname.activecountercomponent>Counter Component (Active)</entityname.activecountercomponent>
<entitydescription.activecountercomponent>Counts up to ClampMax when receiving 1, resets to ClampMin when reached, forces state to X when receiving -X. Constantly outputs state.</entitydescription.activecountercomponent>
<entityname.reactorcontrollercomponent>Reactor Controller Component</entityname.reactorcontrollercomponent>
<entitydescription.reactorcontrollercomponent>Automatically sets a reactor's Fission Rate and Turbine Output.</entitydescription.reactorcontrollercomponent>
<entityname.enginecontrollercomponent>Engine Controller Component</entityname.enginecontrollercomponent>
<entitydescription.enginecontrollercomponent>Sets an Engine's thrust according to the selected mode.</entitydescription.enginecontrollercomponent>
</infotexts>

View File

@@ -6,6 +6,9 @@
<Other file="%ModDir%/Items/luacomp_inv.png" />
<Other file="%ModDir%/Items/luacomp_sprite.png" />
<Other file="%ModDir%/Lua/flipflopcomponent.lua" />
<Other file="%ModDir%/Lua/activeflipflopcomponent.lua" />
<Other file="%ModDir%/Lua/countercomponent.lua" />
<Other file="%ModDir%/Lua/activecountercomponent.lua" />
<Other file="%ModDir%/Lua/reactorcontrollercomponent.lua" />
<Other file="%ModDir%/Lua/enginecontrollercomponent.lua" />
</contentpackage>