summaryrefslogtreecommitdiff
path: root/pipeworks
diff options
context:
space:
mode:
authorVanessa Ezekowitz <vanessaezekowitz@gmail.com>2016-04-01 20:02:19 -0400
committerVanessa Ezekowitz <vanessaezekowitz@gmail.com>2016-04-01 21:09:33 -0400
commitda66780a569712c23ae4f2996cfb4608a9f9d69d (patch)
tree217556029a78bc23ad4564720afc86de97228a04 /pipeworks
parent615b22df4d423aded3613db7716943a2f389b047 (diff)
downloaddreambuilder_modpack-da66780a569712c23ae4f2996cfb4608a9f9d69d.tar
dreambuilder_modpack-da66780a569712c23ae4f2996cfb4608a9f9d69d.tar.gz
dreambuilder_modpack-da66780a569712c23ae4f2996cfb4608a9f9d69d.tar.bz2
dreambuilder_modpack-da66780a569712c23ae4f2996cfb4608a9f9d69d.tar.xz
dreambuilder_modpack-da66780a569712c23ae4f2996cfb4608a9f9d69d.zip
copy all standard Dreambuilder mods in from the old subgame
(exactly as last supplied there, updates to these mods will follow later)
Diffstat (limited to 'pipeworks')
-rw-r--r--pipeworks/LICENSE17
-rw-r--r--pipeworks/README22
-rw-r--r--pipeworks/autocrafter.lua368
-rw-r--r--pipeworks/autoplace_pipes.lua200
-rw-r--r--pipeworks/autoplace_tubes.lua122
-rw-r--r--pipeworks/changelog.txt93
-rw-r--r--pipeworks/common.lua157
-rw-r--r--pipeworks/compat.lua145
-rw-r--r--pipeworks/crafts.lua151
-rw-r--r--pipeworks/decorative_tubes.lua83
-rw-r--r--pipeworks/default_settings.txt22
-rw-r--r--pipeworks/depends.txt3
-rw-r--r--pipeworks/devices.lua572
-rw-r--r--pipeworks/filter-injector.lua239
-rw-r--r--pipeworks/flowing_logic.lua121
-rw-r--r--pipeworks/init.lua115
-rw-r--r--pipeworks/item_transport.lua286
-rw-r--r--pipeworks/legacy.lua59
-rw-r--r--pipeworks/luaentity.lua351
-rw-r--r--pipeworks/models.lua49
-rw-r--r--pipeworks/models/pipeworks_entry_panel.obj390
-rw-r--r--pipeworks/models/pipeworks_flow_sensor.obj390
-rw-r--r--pipeworks/models/pipeworks_fountainhead.obj352
-rw-r--r--pipeworks/models/pipeworks_pipe_10.obj891
-rw-r--r--pipeworks/models/pipeworks_pipe_2.obj392
-rw-r--r--pipeworks/models/pipeworks_pipe_3.obj354
-rw-r--r--pipeworks/models/pipeworks_pipe_4.obj478
-rw-r--r--pipeworks/models/pipeworks_pipe_5.obj542
-rw-r--r--pipeworks/models/pipeworks_pipe_6.obj499
-rw-r--r--pipeworks/models/pipeworks_pipe_7.obj629
-rw-r--r--pipeworks/models/pipeworks_pipe_8.obj631
-rw-r--r--pipeworks/models/pipeworks_pipe_9.obj759
-rw-r--r--pipeworks/models/pipeworks_pump.obj282
-rw-r--r--pipeworks/models/pipeworks_spigot.obj512
-rw-r--r--pipeworks/models/pipeworks_spigot_pouring.obj634
-rw-r--r--pipeworks/models/pipeworks_valve_off.obj458
-rw-r--r--pipeworks/models/pipeworks_valve_on.obj458
-rw-r--r--pipeworks/pipes.lua222
-rw-r--r--pipeworks/routing_tubes.lua119
-rw-r--r--pipeworks/signal_tubes.lua111
-rw-r--r--pipeworks/sorting_tubes.lua148
-rw-r--r--pipeworks/teleport_tube.lua242
-rw-r--r--pipeworks/textures/homedecor_oil_extract.pngbin0 -> 285 bytes
-rw-r--r--pipeworks/textures/homedecor_paraffin.pngbin0 -> 345 bytes
-rw-r--r--pipeworks/textures/homedecor_plastic_sheeting.pngbin0 -> 290 bytes
-rw-r--r--pipeworks/textures/pipeworks_accelerator_tube_end.pngbin0 -> 1229 bytes
-rw-r--r--pipeworks/textures/pipeworks_accelerator_tube_inv.pngbin0 -> 665 bytes
-rw-r--r--pipeworks/textures/pipeworks_accelerator_tube_noctr.pngbin0 -> 1032 bytes
-rw-r--r--pipeworks/textures/pipeworks_accelerator_tube_plain.pngbin0 -> 1195 bytes
-rw-r--r--pipeworks/textures/pipeworks_accelerator_tube_short.pngbin0 -> 661 bytes
-rw-r--r--pipeworks/textures/pipeworks_autocrafter.pngbin0 -> 140 bytes
-rw-r--r--pipeworks/textures/pipeworks_black.pngbin0 -> 83 bytes
-rw-r--r--pipeworks/textures/pipeworks_blue.pngbin0 -> 83 bytes
-rw-r--r--pipeworks/textures/pipeworks_button_interm.pngbin0 -> 5409 bytes
-rw-r--r--pipeworks/textures/pipeworks_button_off.pngbin0 -> 5979 bytes
-rw-r--r--pipeworks/textures/pipeworks_button_on.pngbin0 -> 6064 bytes
-rw-r--r--pipeworks/textures/pipeworks_conductor_tube_end.pngbin0 -> 2022 bytes
-rw-r--r--pipeworks/textures/pipeworks_conductor_tube_inv.pngbin0 -> 1239 bytes
-rw-r--r--pipeworks/textures/pipeworks_conductor_tube_noctr.pngbin0 -> 1630 bytes
-rw-r--r--pipeworks/textures/pipeworks_conductor_tube_on_end.pngbin0 -> 2188 bytes
-rw-r--r--pipeworks/textures/pipeworks_conductor_tube_on_noctr.pngbin0 -> 1739 bytes
-rw-r--r--pipeworks/textures/pipeworks_conductor_tube_on_plain.pngbin0 -> 2167 bytes
-rw-r--r--pipeworks/textures/pipeworks_conductor_tube_plain.pngbin0 -> 2169 bytes
-rw-r--r--pipeworks/textures/pipeworks_conductor_tube_short.pngbin0 -> 839 bytes
-rw-r--r--pipeworks/textures/pipeworks_crossing_tube_end.pngbin0 -> 1195 bytes
-rw-r--r--pipeworks/textures/pipeworks_crossing_tube_inv.pngbin0 -> 535 bytes
-rw-r--r--pipeworks/textures/pipeworks_crossing_tube_noctr.pngbin0 -> 1005 bytes
-rw-r--r--pipeworks/textures/pipeworks_crossing_tube_plain.pngbin0 -> 1219 bytes
-rw-r--r--pipeworks/textures/pipeworks_crossing_tube_short.pngbin0 -> 575 bytes
-rw-r--r--pipeworks/textures/pipeworks_deployer_back.pngbin0 -> 275 bytes
-rw-r--r--pipeworks/textures/pipeworks_deployer_bottom.pngbin0 -> 801 bytes
-rw-r--r--pipeworks/textures/pipeworks_deployer_front_off.pngbin0 -> 669 bytes
-rw-r--r--pipeworks/textures/pipeworks_deployer_front_on.pngbin0 -> 543 bytes
-rw-r--r--pipeworks/textures/pipeworks_deployer_side.pngbin0 -> 823 bytes
-rw-r--r--pipeworks/textures/pipeworks_deployer_side1.pngbin0 -> 823 bytes
-rw-r--r--pipeworks/textures/pipeworks_deployer_side2.pngbin0 -> 823 bytes
-rw-r--r--pipeworks/textures/pipeworks_deployer_top.pngbin0 -> 800 bytes
-rw-r--r--pipeworks/textures/pipeworks_detector_tube_end.pngbin0 -> 1068 bytes
-rw-r--r--pipeworks/textures/pipeworks_detector_tube_inv.pngbin0 -> 795 bytes
-rw-r--r--pipeworks/textures/pipeworks_detector_tube_noctr.pngbin0 -> 892 bytes
-rw-r--r--pipeworks/textures/pipeworks_detector_tube_plain.pngbin0 -> 1551 bytes
-rw-r--r--pipeworks/textures/pipeworks_detector_tube_short.pngbin0 -> 526 bytes
-rw-r--r--pipeworks/textures/pipeworks_dispenser_back.pngbin0 -> 1744 bytes
-rw-r--r--pipeworks/textures/pipeworks_dispenser_bottom.pngbin0 -> 1600 bytes
-rw-r--r--pipeworks/textures/pipeworks_dispenser_front_off.pngbin0 -> 1989 bytes
-rw-r--r--pipeworks/textures/pipeworks_dispenser_front_on.pngbin0 -> 1932 bytes
-rw-r--r--pipeworks/textures/pipeworks_dispenser_side1.pngbin0 -> 1587 bytes
-rw-r--r--pipeworks/textures/pipeworks_dispenser_side2.pngbin0 -> 1597 bytes
-rw-r--r--pipeworks/textures/pipeworks_dispenser_top.pngbin0 -> 1575 bytes
-rw-r--r--pipeworks/textures/pipeworks_entry_panel.pngbin0 -> 4915 bytes
-rw-r--r--pipeworks/textures/pipeworks_filter_input.pngbin0 -> 190 bytes
-rw-r--r--pipeworks/textures/pipeworks_filter_output.pngbin0 -> 175 bytes
-rw-r--r--pipeworks/textures/pipeworks_filter_side.pngbin0 -> 190 bytes
-rw-r--r--pipeworks/textures/pipeworks_filter_top.pngbin0 -> 195 bytes
-rw-r--r--pipeworks/textures/pipeworks_flow_sensor_off.pngbin0 -> 3759 bytes
-rw-r--r--pipeworks/textures/pipeworks_flow_sensor_on.pngbin0 -> 4484 bytes
-rw-r--r--pipeworks/textures/pipeworks_fountainhead.pngbin0 -> 3218 bytes
-rw-r--r--pipeworks/textures/pipeworks_grating_sides.pngbin0 -> 4433 bytes
-rw-r--r--pipeworks/textures/pipeworks_grating_top.pngbin0 -> 4376 bytes
-rw-r--r--pipeworks/textures/pipeworks_green.pngbin0 -> 83 bytes
-rw-r--r--pipeworks/textures/pipeworks_mese_filter_input.pngbin0 -> 190 bytes
-rw-r--r--pipeworks/textures/pipeworks_mese_filter_output.pngbin0 -> 175 bytes
-rw-r--r--pipeworks/textures/pipeworks_mese_filter_side.pngbin0 -> 190 bytes
-rw-r--r--pipeworks/textures/pipeworks_mese_filter_top.pngbin0 -> 195 bytes
-rw-r--r--pipeworks/textures/pipeworks_mese_sand_tube_end.pngbin0 -> 1104 bytes
-rw-r--r--pipeworks/textures/pipeworks_mese_sand_tube_inv.pngbin0 -> 595 bytes
-rw-r--r--pipeworks/textures/pipeworks_mese_sand_tube_noctr.pngbin0 -> 912 bytes
-rw-r--r--pipeworks/textures/pipeworks_mese_sand_tube_plain.pngbin0 -> 1091 bytes
-rw-r--r--pipeworks/textures/pipeworks_mese_sand_tube_short.pngbin0 -> 554 bytes
-rw-r--r--pipeworks/textures/pipeworks_mese_tube_end.pngbin0 -> 1229 bytes
-rw-r--r--pipeworks/textures/pipeworks_mese_tube_inv.pngbin0 -> 665 bytes
-rw-r--r--pipeworks/textures/pipeworks_mese_tube_noctr_1.pngbin0 -> 1098 bytes
-rw-r--r--pipeworks/textures/pipeworks_mese_tube_noctr_2.pngbin0 -> 1102 bytes
-rw-r--r--pipeworks/textures/pipeworks_mese_tube_noctr_3.pngbin0 -> 1102 bytes
-rw-r--r--pipeworks/textures/pipeworks_mese_tube_noctr_4.pngbin0 -> 1102 bytes
-rw-r--r--pipeworks/textures/pipeworks_mese_tube_noctr_5.pngbin0 -> 1102 bytes
-rw-r--r--pipeworks/textures/pipeworks_mese_tube_noctr_6.pngbin0 -> 1102 bytes
-rw-r--r--pipeworks/textures/pipeworks_mese_tube_plain_1.pngbin0 -> 1269 bytes
-rw-r--r--pipeworks/textures/pipeworks_mese_tube_plain_2.pngbin0 -> 1273 bytes
-rw-r--r--pipeworks/textures/pipeworks_mese_tube_plain_3.pngbin0 -> 1274 bytes
-rw-r--r--pipeworks/textures/pipeworks_mese_tube_plain_4.pngbin0 -> 1269 bytes
-rw-r--r--pipeworks/textures/pipeworks_mese_tube_plain_5.pngbin0 -> 1269 bytes
-rw-r--r--pipeworks/textures/pipeworks_mese_tube_plain_6.pngbin0 -> 1274 bytes
-rw-r--r--pipeworks/textures/pipeworks_mese_tube_short.pngbin0 -> 661 bytes
-rw-r--r--pipeworks/textures/pipeworks_nodebreaker_back.pngbin0 -> 632 bytes
-rw-r--r--pipeworks/textures/pipeworks_nodebreaker_bottom_off.pngbin0 -> 637 bytes
-rw-r--r--pipeworks/textures/pipeworks_nodebreaker_bottom_on.pngbin0 -> 640 bytes
-rw-r--r--pipeworks/textures/pipeworks_nodebreaker_front_off.pngbin0 -> 587 bytes
-rw-r--r--pipeworks/textures/pipeworks_nodebreaker_front_on.pngbin0 -> 544 bytes
-rw-r--r--pipeworks/textures/pipeworks_nodebreaker_side1_off.pngbin0 -> 581 bytes
-rw-r--r--pipeworks/textures/pipeworks_nodebreaker_side1_on.pngbin0 -> 589 bytes
-rw-r--r--pipeworks/textures/pipeworks_nodebreaker_side2_off.pngbin0 -> 581 bytes
-rw-r--r--pipeworks/textures/pipeworks_nodebreaker_side2_on.pngbin0 -> 589 bytes
-rw-r--r--pipeworks/textures/pipeworks_nodebreaker_top_off.pngbin0 -> 637 bytes
-rw-r--r--pipeworks/textures/pipeworks_nodebreaker_top_on.pngbin0 -> 640 bytes
-rw-r--r--pipeworks/textures/pipeworks_one_way_tube_input.pngbin0 -> 349 bytes
-rw-r--r--pipeworks/textures/pipeworks_one_way_tube_output.pngbin0 -> 349 bytes
-rw-r--r--pipeworks/textures/pipeworks_one_way_tube_side.pngbin0 -> 859 bytes
-rw-r--r--pipeworks/textures/pipeworks_one_way_tube_top.pngbin0 -> 860 bytes
-rw-r--r--pipeworks/textures/pipeworks_pane_embedded_tube_ends.pngbin0 -> 1005 bytes
-rw-r--r--pipeworks/textures/pipeworks_pane_embedded_tube_sides.pngbin0 -> 1031 bytes
-rw-r--r--pipeworks/textures/pipeworks_pipe_3_empty.pngbin0 -> 2351 bytes
-rw-r--r--pipeworks/textures/pipeworks_pipe_3_loaded.pngbin0 -> 2389 bytes
-rw-r--r--pipeworks/textures/pipeworks_pipe_inv.pngbin0 -> 4104 bytes
-rw-r--r--pipeworks/textures/pipeworks_pipe_plain.pngbin0 -> 2343 bytes
-rw-r--r--pipeworks/textures/pipeworks_plastic_sheeting.pngbin0 -> 152 bytes
-rw-r--r--pipeworks/textures/pipeworks_pump_off.pngbin0 -> 25829 bytes
-rw-r--r--pipeworks/textures/pipeworks_pump_on.pngbin0 -> 26842 bytes
-rw-r--r--pipeworks/textures/pipeworks_red.pngbin0 -> 83 bytes
-rw-r--r--pipeworks/textures/pipeworks_sand_tube_end.pngbin0 -> 1158 bytes
-rw-r--r--pipeworks/textures/pipeworks_sand_tube_inv.pngbin0 -> 632 bytes
-rw-r--r--pipeworks/textures/pipeworks_sand_tube_noctr.pngbin0 -> 971 bytes
-rw-r--r--pipeworks/textures/pipeworks_sand_tube_plain.pngbin0 -> 1129 bytes
-rw-r--r--pipeworks/textures/pipeworks_sand_tube_short.pngbin0 -> 602 bytes
-rw-r--r--pipeworks/textures/pipeworks_spigot.pngbin0 -> 2463 bytes
-rw-r--r--pipeworks/textures/pipeworks_storage_tank_back.pngbin0 -> 248 bytes
-rw-r--r--pipeworks/textures/pipeworks_storage_tank_fittings.pngbin0 -> 285 bytes
-rw-r--r--pipeworks/textures/pipeworks_storage_tank_front_0.pngbin0 -> 3770 bytes
-rw-r--r--pipeworks/textures/pipeworks_storage_tank_front_1.pngbin0 -> 723 bytes
-rw-r--r--pipeworks/textures/pipeworks_storage_tank_front_10.pngbin0 -> 270 bytes
-rw-r--r--pipeworks/textures/pipeworks_storage_tank_front_2.pngbin0 -> 710 bytes
-rw-r--r--pipeworks/textures/pipeworks_storage_tank_front_3.pngbin0 -> 700 bytes
-rw-r--r--pipeworks/textures/pipeworks_storage_tank_front_4.pngbin0 -> 701 bytes
-rw-r--r--pipeworks/textures/pipeworks_storage_tank_front_5.pngbin0 -> 281 bytes
-rw-r--r--pipeworks/textures/pipeworks_storage_tank_front_6.pngbin0 -> 266 bytes
-rw-r--r--pipeworks/textures/pipeworks_storage_tank_front_7.pngbin0 -> 265 bytes
-rw-r--r--pipeworks/textures/pipeworks_storage_tank_front_8.pngbin0 -> 266 bytes
-rw-r--r--pipeworks/textures/pipeworks_storage_tank_front_9.pngbin0 -> 264 bytes
-rw-r--r--pipeworks/textures/pipeworks_teleport_tube_end.pngbin0 -> 1694 bytes
-rw-r--r--pipeworks/textures/pipeworks_teleport_tube_inv.pngbin0 -> 842 bytes
-rw-r--r--pipeworks/textures/pipeworks_teleport_tube_noctr.pngbin0 -> 1455 bytes
-rw-r--r--pipeworks/textures/pipeworks_teleport_tube_plain.pngbin0 -> 1682 bytes
-rw-r--r--pipeworks/textures/pipeworks_teleport_tube_short.pngbin0 -> 967 bytes
-rw-r--r--pipeworks/textures/pipeworks_testobject.pngbin0 -> 4012 bytes
-rw-r--r--pipeworks/textures/pipeworks_trashcan_bottom.pngbin0 -> 119 bytes
-rw-r--r--pipeworks/textures/pipeworks_trashcan_side.pngbin0 -> 89 bytes
-rw-r--r--pipeworks/textures/pipeworks_tube_connection_metallic.pngbin0 -> 161 bytes
-rw-r--r--pipeworks/textures/pipeworks_tube_connection_stony.pngbin0 -> 170 bytes
-rw-r--r--pipeworks/textures/pipeworks_tube_connection_wooden.pngbin0 -> 152 bytes
-rw-r--r--pipeworks/textures/pipeworks_tube_end.pngbin0 -> 1068 bytes
-rw-r--r--pipeworks/textures/pipeworks_tube_inv.pngbin0 -> 523 bytes
-rw-r--r--pipeworks/textures/pipeworks_tube_noctr.pngbin0 -> 892 bytes
-rw-r--r--pipeworks/textures/pipeworks_tube_plain.pngbin0 -> 1073 bytes
-rw-r--r--pipeworks/textures/pipeworks_tube_short.pngbin0 -> 526 bytes
-rw-r--r--pipeworks/textures/pipeworks_tube_transparent.pngbin0 -> 95 bytes
-rw-r--r--pipeworks/textures/pipeworks_valve.pngbin0 -> 5043 bytes
-rw-r--r--pipeworks/textures/pipeworks_white.pngbin0 -> 83 bytes
-rw-r--r--pipeworks/textures/pipeworks_yellow.pngbin0 -> 83 bytes
-rw-r--r--pipeworks/trashcan.lua49
-rw-r--r--pipeworks/tube_registration.lua240
-rw-r--r--pipeworks/vacuum_tubes.lua122
-rw-r--r--pipeworks/wielder.lua456
192 files changed, 13535 insertions, 0 deletions
diff --git a/pipeworks/LICENSE b/pipeworks/LICENSE
new file mode 100644
index 0000000..eb930e9
--- /dev/null
+++ b/pipeworks/LICENSE
@@ -0,0 +1,17 @@
+ DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
+ Version 2, December 2004
+
+ Copyright (C) 2004 Sam Hocevar <sam@hocevar.net>
+
+ Everyone is permitted to copy and distribute verbatim or modified
+ copies of this license document, and changing it is allowed as long
+ as the name is changed.
+
+ DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. You just DO WHAT THE FUCK YOU WANT TO.
+
+----------
+
+This license is commonly known as "WTFPL".
diff --git a/pipeworks/README b/pipeworks/README
new file mode 100644
index 0000000..7a34618
--- /dev/null
+++ b/pipeworks/README
@@ -0,0 +1,22 @@
+This mod uses nodeboxes to supply a complete set of 3D pipes and tubes,
+along devices that work with them.
+
+See https://github.com/VanessaE/pipeworks/wiki/ for detailed information about usage of this mod.
+
+Unlike the previous version of this mod, these pipes are rounded, and when
+placed, they'll automatically join together as needed. Pipes can go vertically
+or horizontally, and there are enough nodes defined to allow for all possible
+connections. Valves and pumps can only be placed horizontally, and will
+automatically rotate and join with neighboring pipes as objects are added, as
+well as joining with each other under certain circumstances.
+
+Pipes come in two variants: one type bears one or more dark windows on each
+pipe, suggesting they're empty, while the other type bears green-tinted
+windows, as if full (the two colors should also be easy to select if you want
+to change them in a paint program). These windows only appear on straight
+lengths and on certain junctions.
+
+This mod is a work in progress.
+
+Please note that owing to the nature of this mod, I have opted to use 64px
+textures. Anything less just looks terrible.
diff --git a/pipeworks/autocrafter.lua b/pipeworks/autocrafter.lua
new file mode 100644
index 0000000..6d00a7c
--- /dev/null
+++ b/pipeworks/autocrafter.lua
@@ -0,0 +1,368 @@
+local autocrafterCache = {} -- caches some recipe data to avoid to call the slow function minetest.get_craft_result() every second
+
+local craft_time = 1
+
+local function count_index(invlist)
+ local index = {}
+ for _, stack in pairs(invlist) do
+ if not stack:is_empty() then
+ local stack_name = stack:get_name()
+ index[stack_name] = (index[stack_name] or 0) + stack:get_count()
+ end
+ end
+ return index
+end
+
+local function get_item_info(stack)
+ local name = stack:get_name()
+ local def = minetest.registered_items[name]
+ local description = def and def.description or "Unknown item"
+ return description, name
+end
+
+local function get_craft(pos, inventory, hash)
+ local hash = hash or minetest.hash_node_position(pos)
+ local craft = autocrafterCache[hash]
+ if not craft then
+ local recipe = inventory:get_list("recipe")
+ local output, decremented_input = minetest.get_craft_result({method = "normal", width = 3, items = recipe})
+ craft = {recipe = recipe, consumption=count_index(recipe), output = output, decremented_input = decremented_input}
+ autocrafterCache[hash] = craft
+ end
+ return craft
+end
+
+local function autocraft(inventory, craft)
+ if not craft then return false end
+ local output_item = craft.output.item
+
+ -- check if we have enough room in dst
+ if not inventory:room_for_item("dst", output_item) then return false end
+ local consumption = craft.consumption
+ local inv_index = count_index(inventory:get_list("src"))
+ -- check if we have enough material available
+ for itemname, number in pairs(consumption) do
+ if (not inv_index[itemname]) or inv_index[itemname] < number then return false end
+ end
+ -- consume material
+ for itemname, number in pairs(consumption) do
+ for i = 1, number do -- We have to do that since remove_item does not work if count > stack_max
+ inventory:remove_item("src", ItemStack(itemname))
+ end
+ end
+
+ -- craft the result into the dst inventory and add any "replacements" as well
+ inventory:add_item("dst", output_item)
+ for i = 1, 9 do
+ inventory:add_item("dst", craft.decremented_input.items[i])
+ end
+ return true
+end
+
+-- returns false to stop the timer, true to continue running
+-- is started only from start_autocrafter(pos) after sanity checks and cached recipe
+local function run_autocrafter(pos, elapsed)
+ local meta = minetest.get_meta(pos)
+ local inventory = meta:get_inventory()
+ local craft = get_craft(pos, inventory)
+ local output_item = craft.output.item
+ -- only use crafts that have an actual result
+ if output_item:is_empty() then
+ meta:set_string("infotext", "unconfigured Autocrafter: unknown recipe")
+ return false
+ end
+
+ for step = 1, math.floor(elapsed/craft_time) do
+ local continue = autocraft(inventory, craft)
+ if not continue then return false end
+ end
+ return true
+end
+
+local function start_crafter(pos)
+ local meta = minetest.get_meta(pos)
+ if meta:get_int("enabled") == 1 then
+ local timer = minetest.get_node_timer(pos)
+ if not timer:is_started() then
+ timer:start(craft_time)
+ end
+ end
+end
+
+local function after_inventory_change(pos)
+ start_crafter(pos)
+end
+
+-- note, that this function assumes allready being updated to virtual items
+-- and doesn't handle recipes with stacksizes > 1
+local function after_recipe_change(pos, inventory)
+ local meta = minetest.get_meta(pos)
+ -- if we emptied the grid, there's no point in keeping it running or cached
+ if inventory:is_empty("recipe") then
+ minetest.get_node_timer(pos):stop()
+ autocrafterCache[minetest.hash_node_position(pos)] = nil
+ meta:set_string("infotext", "unconfigured Autocrafter")
+ return
+ end
+ local recipe_changed = false
+ local recipe = inventory:get_list("recipe")
+
+ local hash = minetest.hash_node_position(pos)
+ local craft = autocrafterCache[hash]
+
+ if craft then
+ -- check if it changed
+ local cached_recipe = craft.recipe
+ for i = 1, 9 do
+ if recipe[i]:get_name() ~= cached_recipe[i]:get_name() then
+ autocrafterCache[hash] = nil -- invalidate recipe
+ craft = nil
+ break
+ end
+ end
+ end
+
+ craft = craft or get_craft(pos, inventory, hash)
+ local output_item = craft.output.item
+ local description, name = get_item_info(output_item)
+ meta:set_string("infotext", string.format("'%s' Autocrafter (%s)", description, name))
+ inventory:set_stack("output", 1, output_item)
+
+ after_inventory_change(pos)
+end
+
+-- clean out unknown items and groups, which would be handled like unknown items in the crafting grid
+-- if minetest supports query by group one day, this might replace them
+-- with a canonical version instead
+local function normalize(item_list)
+ for i = 1, #item_list do
+ local name = item_list[i]
+ if not minetest.registered_items[name] then
+ item_list[i] = ""
+ end
+ end
+ return item_list
+end
+
+local function on_output_change(pos, inventory, stack)
+ if not stack then
+ inventory:set_list("output", {})
+ inventory:set_list("recipe", {})
+ else
+ local input = minetest.get_craft_recipe(stack:get_name())
+ if not input.items or input.type ~= "normal" then return end
+ local items, width = normalize(input.items), input.width
+ local item_idx, width_idx = 1, 1
+ for i = 1, 9 do
+ if width_idx <= width then
+ inventory:set_stack("recipe", i, items[item_idx])
+ item_idx = item_idx + 1
+ else
+ inventory:set_stack("recipe", i, ItemStack(""))
+ end
+ width_idx = (width_idx < 3) and (width_idx + 1) or 1
+ end
+ -- we'll set the output slot in after_recipe_change to the actual result of the new recipe
+ end
+ after_recipe_change(pos, inventory)
+end
+
+-- returns false if we shouldn't bother attempting to start the timer again after this
+local function update_meta(meta, enabled)
+ local state = enabled and "on" or "off"
+ meta:set_int("enabled", enabled and 1 or 0)
+ meta:set_string("formspec",
+ "size[8,11]"..
+ "list[context;recipe;0,0;3,3;]"..
+ "image[3,1;1,1;gui_hb_bg.png^[colorize:#141318:255]"..
+ "list[context;output;3,1;1,1;]"..
+ "image_button[3,2;1,1;pipeworks_button_" .. state .. ".png;" .. state .. ";;;false;pipeworks_button_interm.png]" ..
+ "list[context;src;0,3.5;8,3;]"..
+ "list[context;dst;4,0;4,3;]"..
+ default.gui_bg..
+ default.gui_bg_img..
+ default.gui_slots..
+ default.get_hotbar_bg(0,7) ..
+ "list[current_player;main;0,7;8,4;]")
+
+ -- toggling the button doesn't quite call for running a recipe change check
+ -- so instead we run a minimal version for infotext setting only
+ -- this might be more written code, but actually executes less
+ local output = meta:get_inventory():get_stack("output", 1)
+ if output:is_empty() then -- doesn't matter if paused or not
+ meta:set_string("infotext", "unconfigured Autocrafter")
+ return false
+ end
+
+ local description, name = get_item_info(output)
+ local infotext = enabled and string.format("'%s' Autocrafter (%s)", description, name)
+ or string.format("paused '%s' Autocrafter", description)
+
+ meta:set_string("infotext", infotext)
+ return enabled
+end
+
+-- 1st version of the autocrafter had actual items in the crafting grid
+-- the 2nd replaced these with virtual items, dropped the content on update and set "virtual_items" to string "1"
+-- the third added an output inventory, changed the formspec and added a button for enabling/disabling
+-- so we work out way backwards on this history and update each single case to the newest version
+local function upgrade_autocrafter(pos, meta)
+ local meta = meta or minetest.get_meta(pos)
+ local inv = meta:get_inventory()
+
+ if inv:get_size("output") == 0 then -- we are version 2 or 1
+ inv:set_size("output", 1)
+ -- migrate the old autocrafters into an "enabled" state
+ update_meta(meta, true)
+
+ if meta:get_string("virtual_items") == "1" then -- we are version 2
+ -- we allready dropped stuff, so lets remove the metadatasetting (we are not being called again for this node)
+ meta:set_string("virtual_items", "")
+ else -- we are version 1
+ local recipe = inv:get_list("recipe")
+ if not recipe then return end
+ for idx, stack in ipairs(recipe) do
+ if not stack:is_empty() then
+ minetest.item_drop(stack, nil, pos)
+ stack:set_count(1)
+ stack:set_wear(0)
+ inv:set_stack("recipe", idx, stack)
+ end
+ end
+ end
+
+ -- update the recipe, cache, and start the crafter
+ autocrafterCache[minetest.hash_node_position(pos)] = nil
+ after_recipe_change(pos, inv)
+ end
+end
+
+minetest.register_node("pipeworks:autocrafter", {
+ description = "Autocrafter",
+ drawtype = "normal",
+ tiles = {"pipeworks_autocrafter.png"},
+ groups = {snappy = 3, tubedevice = 1, tubedevice_receiver = 1},
+ tube = {insert_object = function(pos, node, stack, direction)
+ local meta = minetest.get_meta(pos)
+ local inv = meta:get_inventory()
+ local added = inv:add_item("src", stack)
+ after_inventory_change(pos)
+ return added
+ end,
+ can_insert = function(pos, node, stack, direction)
+ local meta = minetest.get_meta(pos)
+ local inv = meta:get_inventory()
+ return inv:room_for_item("src", stack)
+ end,
+ input_inventory = "dst",
+ connect_sides = {left = 1, right = 1, front = 1, back = 1, top = 1, bottom = 1}},
+ on_construct = function(pos)
+ local meta = minetest.get_meta(pos)
+ local inv = meta:get_inventory()
+ inv:set_size("src", 3*8)
+ inv:set_size("recipe", 3*3)
+ inv:set_size("dst", 4*3)
+ inv:set_size("output", 1)
+ update_meta(meta, false)
+ end,
+ on_receive_fields = function(pos, formname, fields, sender)
+ if not pipeworks.may_configure(pos, sender) then return end
+ local meta = minetest.get_meta(pos)
+ if fields.on then
+ update_meta(meta, false)
+ minetest.get_node_timer(pos):stop()
+ elseif fields.off then
+ if update_meta(meta, true) then
+ start_crafter(pos)
+ end
+ end
+ end,
+ can_dig = function(pos, player)
+ upgrade_autocrafter(pos)
+ local meta = minetest.get_meta(pos)
+ local inv = meta:get_inventory()
+ return (inv:is_empty("src") and inv:is_empty("dst"))
+ end,
+ after_place_node = pipeworks.scan_for_tube_objects,
+ after_dig_node = function(pos)
+ pipeworks.scan_for_tube_objects(pos)
+ end,
+ on_destruct = function(pos)
+ autocrafterCache[minetest.hash_node_position(pos)] = nil
+ end,
+ allow_metadata_inventory_put = function(pos, listname, index, stack, player)
+ if not pipeworks.may_configure(pos, player) then return 0 end
+ upgrade_autocrafter(pos)
+ local inv = minetest.get_meta(pos):get_inventory()
+ if listname == "recipe" then
+ stack:set_count(1)
+ inv:set_stack(listname, index, stack)
+ after_recipe_change(pos, inv)
+ return 0
+ elseif listname == "output" then
+ on_output_change(pos, inv, stack)
+ return 0
+ end
+ after_inventory_change(pos)
+ return stack:get_count()
+ end,
+ allow_metadata_inventory_take = function(pos, listname, index, stack, player)
+ if not pipeworks.may_configure(pos, player) then
+ minetest.log("action", string.format("%s attempted to take from autocrafter at %s", player:get_player_name(), minetest.pos_to_string(pos)))
+ return 0
+ end
+ upgrade_autocrafter(pos)
+ local inv = minetest.get_meta(pos):get_inventory()
+ if listname == "recipe" then
+ inv:set_stack(listname, index, ItemStack(""))
+ after_recipe_change(pos, inv)
+ return 0
+ elseif listname == "output" then
+ on_output_change(pos, inv, nil)
+ return 0
+ end
+ after_inventory_change(pos)
+ return stack:get_count()
+ end,
+ allow_metadata_inventory_move = function(pos, from_list, from_index, to_list, to_index, count, player)
+ if not pipeworks.may_configure(pos, player) then return 0 end
+ upgrade_autocrafter(pos)
+ local inv = minetest.get_meta(pos):get_inventory()
+ local stack = inv:get_stack(from_list, from_index)
+
+ if to_list == "output" then
+ on_output_change(pos, inv, stack)
+ return 0
+ elseif from_list == "output" then
+ on_output_change(pos, inv, nil)
+ if to_list ~= "recipe" then
+ return 0
+ end -- else fall through to recipe list handling
+ end
+
+ if from_list == "recipe" or to_list == "recipe" then
+ if from_list == "recipe" then
+ inv:set_stack(from_list, from_index, ItemStack(""))
+ end
+ if to_list == "recipe" then
+ stack:set_count(1)
+ inv:set_stack(to_list, to_index, stack)
+ end
+ after_recipe_change(pos, inv)
+ return 0
+ end
+
+ after_inventory_change(pos)
+ return count
+ end,
+ on_timer = run_autocrafter
+})
+
+minetest.register_craft( {
+ output = "pipeworks:autocrafter 2",
+ recipe = {
+ { "default:steel_ingot", "default:mese_crystal", "default:steel_ingot" },
+ { "homedecor:plastic_sheeting", "default:steel_ingot", "homedecor:plastic_sheeting" },
+ { "default:steel_ingot", "default:mese_crystal", "default:steel_ingot" }
+ },
+})
diff --git a/pipeworks/autoplace_pipes.lua b/pipeworks/autoplace_pipes.lua
new file mode 100644
index 0000000..4fc3665
--- /dev/null
+++ b/pipeworks/autoplace_pipes.lua
@@ -0,0 +1,200 @@
+-- autorouting for pipes
+local tube_table = {[0] = 1, 2, 2, 4, 2, 4, 4, 5, 2, 3, 4, 6, 4, 6, 5, 7, 2, 4, 3, 6, 4, 5, 6, 7, 4, 6, 6, 8, 5, 7, 7, 9, 2, 4, 4, 5, 3, 6, 6, 7, 4, 6, 5, 7, 6, 8, 7, 9, 4, 5, 6, 7, 6, 7, 8, 9, 5, 7, 7, 9, 7, 9, 9, 10}
+local tube_table_facedirs = {[0] = 0, 0, 5, 0, 3, 4, 3, 0, 2, 0, 2, 0, 6, 4, 3, 0, 7, 12, 5, 12, 7, 4, 5, 5, 18, 20, 16, 0, 7, 4, 7, 0, 1, 8, 1, 1, 1, 13, 1, 1, 10, 8, 2, 2, 17, 4, 3, 6, 9, 9, 9, 9, 21, 13, 1, 1, 10, 10, 11, 2, 19, 4, 3, 0}
+local function autoroute_pipes(pos)
+ local nctr = minetest.get_node(pos)
+ local state = "_empty"
+ if (string.find(nctr.name, "pipeworks:pipe_") == nil) then return end
+ if (string.find(nctr.name, "_loaded") ~= nil) then state = "_loaded" end
+ local nsurround = pipeworks.scan_pipe_surroundings(pos)
+
+ if nsurround == 0 then nsurround = 9 end
+ minetest.swap_node(pos, {name = "pipeworks:pipe_"..tube_table[nsurround]..state,
+ param2 = tube_table_facedirs[nsurround]})
+end
+
+function pipeworks.scan_for_pipe_objects(pos)
+ autoroute_pipes({ x=pos.x-1, y=pos.y , z=pos.z })
+ autoroute_pipes({ x=pos.x+1, y=pos.y , z=pos.z })
+ autoroute_pipes({ x=pos.x , y=pos.y-1, z=pos.z })
+ autoroute_pipes({ x=pos.x , y=pos.y+1, z=pos.z })
+ autoroute_pipes({ x=pos.x , y=pos.y , z=pos.z-1 })
+ autoroute_pipes({ x=pos.x , y=pos.y , z=pos.z+1 })
+ autoroute_pipes(pos)
+end
+
+-- auto-rotation code for various devices the tubes attach to
+
+function pipeworks.scan_pipe_surroundings(pos)
+ local pxm=0
+ local pxp=0
+ local pym=0
+ local pyp=0
+ local pzm=0
+ local pzp=0
+
+ local nxm = minetest.get_node({ x=pos.x-1, y=pos.y , z=pos.z })
+ local nxp = minetest.get_node({ x=pos.x+1, y=pos.y , z=pos.z })
+ local nym = minetest.get_node({ x=pos.x , y=pos.y-1, z=pos.z })
+ local nyp = minetest.get_node({ x=pos.x , y=pos.y+1, z=pos.z })
+ local nzm = minetest.get_node({ x=pos.x , y=pos.y , z=pos.z-1 })
+ local nzp = minetest.get_node({ x=pos.x , y=pos.y , z=pos.z+1 })
+
+ if (string.find(nxm.name, "pipeworks:pipe_") ~= nil) then pxm=1 end
+ if (string.find(nxp.name, "pipeworks:pipe_") ~= nil) then pxp=1 end
+ if (string.find(nym.name, "pipeworks:pipe_") ~= nil) then pym=1 end
+ if (string.find(nyp.name, "pipeworks:pipe_") ~= nil) then pyp=1 end
+ if (string.find(nzm.name, "pipeworks:pipe_") ~= nil) then pzm=1 end
+ if (string.find(nzp.name, "pipeworks:pipe_") ~= nil) then pzp=1 end
+
+-- Special handling for valves...
+
+ if (string.find(nxm.name, "pipeworks:valve") ~= nil)
+ and (nxm.param2 == 0 or nxm.param2 == 2) then
+ pxm=1
+ end
+
+ if (string.find(nxp.name, "pipeworks:valve") ~= nil)
+ and (nxp.param2 == 0 or nxp.param2 == 2) then
+ pxp=1
+ end
+
+ if (string.find(nzm.name, "pipeworks:valve") ~= nil)
+ and (nzm.param2 == 1 or nzm.param2 == 3) then
+ pzm=1
+ end
+
+ if (string.find(nzp.name, "pipeworks:valve") ~= nil)
+ and (nzp.param2 == 1 or nzp.param2 == 3) then
+ pzp=1
+ end
+
+-- ...flow sensors...
+
+ if (string.find(nxm.name, "pipeworks:flow_sensor") ~= nil)
+ and (nxm.param2 == 0 or nxm.param2 == 2) then
+ pxm=1
+ end
+
+ if (string.find(nxp.name, "pipeworks:flow_sensor") ~= nil)
+ and (nxp.param2 == 0 or nxp.param2 == 2) then
+ pxp=1
+ end
+
+ if (string.find(nzm.name, "pipeworks:flow_sensor") ~= nil)
+ and (nzm.param2 == 1 or nzm.param2 == 3) then
+ pzm=1
+ end
+
+ if (string.find(nzp.name, "pipeworks:flow_sensor") ~= nil)
+ and (nzp.param2 == 1 or nzp.param2 == 3) then
+ pzp=1
+ end
+
+-- ...spigots...
+
+ if (string.find(nxm.name, "pipeworks:spigot") ~= nil)
+ and nxm.param2 == 1 then
+ pxm=1
+ end
+
+ if (string.find(nxp.name, "pipeworks:spigot") ~= nil)
+ and nxp.param2 == 3 then
+ pxp=1
+ end
+
+ if (string.find(nzm.name, "pipeworks:spigot") ~= nil)
+ and nzm.param2 == 0 then
+ pzm=1
+ end
+
+ if (string.find(nzp.name, "pipeworks:spigot") ~= nil)
+ and nzp.param2 == 2 then
+ pzp=1
+ end
+
+-- ...sealed pipe entry/exit...
+
+ if (string.find(nxm.name, "pipeworks:entry_panel") ~= nil)
+ and (nxm.param2 == 1 or nxm.param2 == 3) then
+ pxm=1
+ end
+
+ if (string.find(nxp.name, "pipeworks:entry_panel") ~= nil)
+ and (nxp.param2 == 1 or nxp.param2 == 3) then
+ pxp=1
+ end
+
+ if (string.find(nzm.name, "pipeworks:entry_panel") ~= nil)
+ and (nzm.param2 == 0 or nzm.param2 == 2) then
+ pzm=1
+ end
+
+ if (string.find(nzp.name, "pipeworks:entry_panel") ~= nil)
+ and (nzp.param2 == 0 or nzp.param2 == 2) then
+ pzp=1
+ end
+
+ if (string.find(nym.name, "pipeworks:entry_panel") ~= nil)
+ and nym.param2 == 13 then
+ pym=1
+ end
+
+ if (string.find(nyp.name, "pipeworks:entry_panel") ~= nil)
+ and nyp.param2 == 13 then
+ pyp=1
+ end
+
+
+-- ...pumps, grates...
+
+ if (string.find(nym.name, "pipeworks:grating") ~= nil) or
+ (string.find(nym.name, "pipeworks:pump") ~= nil) then
+ pym=1
+ end
+
+-- ...fountainheads...
+
+ if (string.find(nyp.name, "pipeworks:fountainhead") ~= nil) then
+ pyp=1
+ end
+
+-- ... and storage tanks.
+
+ if (string.find(nym.name, "pipeworks:storage_tank_") ~= nil) then
+ pym=1
+ end
+
+ if (string.find(nyp.name, "pipeworks:storage_tank_") ~= nil) then
+ pyp=1
+ end
+
+-- ...extra devices specified via the function's parameters
+-- ...except that this part is not implemented yet
+--
+-- xxx = nxm, nxp, nym, nyp, nzm, or nzp depending on the direction to check
+-- yyy = pxm, pxp, pym, pyp, pzm, or pzp accordingly.
+--
+-- if string.find(xxx.name, "modname:nodename") ~= nil then
+-- yyy = 1
+-- end
+--
+-- for example:
+--
+-- if string.find(nym.name, "aero:outlet") ~= nil then
+-- pym = 1
+-- end
+--
+
+ return pxm+8*pxp+2*pym+16*pyp+4*pzm+32*pzp
+end
+
+function pipeworks.look_for_stackable_tanks(pos)
+ local tym = minetest.get_node({ x=pos.x , y=pos.y-1, z=pos.z })
+
+ if string.find(tym.name, "pipeworks:storage_tank_") ~= nil or
+ string.find(tym.name, "pipeworks:expansion_tank_") ~= nil then
+ minetest.add_node(pos, { name = "pipeworks:expansion_tank_0", param2 = tym.param2})
+ end
+end
+
diff --git a/pipeworks/autoplace_tubes.lua b/pipeworks/autoplace_tubes.lua
new file mode 100644
index 0000000..280bd60
--- /dev/null
+++ b/pipeworks/autoplace_tubes.lua
@@ -0,0 +1,122 @@
+-- autorouting for pneumatic tubes
+
+local function is_tube(nodename)
+ return table.contains(pipeworks.tubenodes, nodename)
+end
+
+--a function for determining which side of the node we are on
+local function nodeside(node, tubedir)
+ if node.param2 < 0 or node.param2 > 23 then
+ node.param2 = 0
+ end
+
+ local backdir = minetest.facedir_to_dir(node.param2)
+ local back = vector.dot(backdir, tubedir)
+ if back == 1 then
+ return "back"
+ elseif back == -1 then
+ return "front"
+ end
+
+ local topdir = minetest.facedir_to_top_dir(node.param2)
+ local top = vector.dot(topdir, tubedir)
+ if top == 1 then
+ return "top"
+ elseif top == -1 then
+ return "bottom"
+ end
+
+ local rightdir = minetest.facedir_to_right_dir(node.param2)
+ local right = vector.dot(rightdir, tubedir)
+ if right == 1 then
+ return "right"
+ else
+ return "left"
+ end
+end
+
+local vts = {0, 3, 1, 4, 2, 5}
+local tube_table = {[0] = 1, 2, 2, 4, 2, 4, 4, 5, 2, 3, 4, 6, 4, 6, 5, 7, 2, 4, 3, 6, 4, 5, 6, 7, 4, 6, 6, 8, 5, 7, 7, 9, 2, 4, 4, 5, 3, 6, 6, 7, 4, 6, 5, 7, 6, 8, 7, 9, 4, 5, 6, 7, 6, 7, 8, 9, 5, 7, 7, 9, 7, 9, 9, 10}
+local tube_table_facedirs = {[0] = 0, 0, 5, 0, 3, 4, 3, 0, 2, 0, 2, 0, 6, 4, 3, 0, 7, 12, 5, 12, 7, 4, 5, 5, 18, 20, 16, 0, 7, 4, 7, 0, 1, 8, 1, 1, 1, 13, 1, 1, 10, 8, 2, 2, 17, 4, 3, 6, 9, 9, 9, 9, 21, 13, 1, 1, 10, 10, 11, 2, 19, 4, 3, 0}
+local function tube_autoroute(pos)
+ local active = {0, 0, 0, 0, 0, 0}
+ local nctr = minetest.get_node(pos)
+ if not is_tube(nctr.name) then return end
+
+ local adjustments = {
+ {x = -1, y = 0, z = 0},
+ {x = 1, y = 0, z = 0},
+ {x = 0, y = -1, z = 0},
+ {x = 0, y = 1, z = 0},
+ {x = 0, y = 0, z = -1},
+ {x = 0, y = 0, z = 1}
+ }
+ -- xm = 1, xp = 2, ym = 3, yp = 4, zm = 5, zp = 6
+
+ local positions = {}
+ local nodes = {}
+ for i, adj in ipairs(adjustments) do
+ positions[i] = vector.add(pos, adj)
+ nodes[i] = minetest.get_node(positions[i])
+ end
+
+ for i, node in ipairs(nodes) do
+ local idef = minetest.registered_nodes[node.name]
+ -- handle the tubes themselves
+ if is_tube(node.name) then
+ active[i] = 1
+ -- handle new style connectors
+ elseif idef and idef.tube and idef.tube.connect_sides then
+ local dir = adjustments[i]
+ if idef.tube.connect_sides[nodeside(node, vector.multiply(dir, -1))] then
+ active[i] = 1
+ end
+ end
+ end
+
+ -- all sides checked, now figure which tube to use.
+
+ local nodedef = minetest.registered_nodes[nctr.name]
+ local basename = nodedef.basename
+ if nodedef.style == "old" then
+ local nsurround = ""
+ for i, n in ipairs(active) do
+ nsurround = nsurround..n
+ end
+ nctr.name = basename.."_"..nsurround
+ elseif nodedef.style == "6d" then
+ local s = 0
+ for i, n in ipairs(active) do
+ if n == 1 then
+ s = s + 2^vts[i]
+ end
+ end
+ nctr.name = basename.."_"..tube_table[s]
+ nctr.param2 = tube_table_facedirs[s]
+ end
+ minetest.swap_node(pos, nctr)
+end
+
+function pipeworks.scan_for_tube_objects(pos)
+ for side = 0, 6 do
+ tube_autoroute(vector.add(pos, directions.side_to_dir(side)))
+ end
+end
+
+function pipeworks.after_place(pos)
+ pipeworks.scan_for_tube_objects(pos)
+end
+
+function pipeworks.after_dig(pos)
+ pipeworks.scan_for_tube_objects(pos)
+end
+
+if minetest.get_modpath("mesecons_mvps") then
+ mesecon.register_on_mvps_move(function(moved_nodes)
+ for _, n in ipairs(moved_nodes) do
+ pipeworks.scan_for_tube_objects(n.pos)
+ pipeworks.scan_for_tube_objects(n.oldpos)
+ end
+ end)
+end
+
diff --git a/pipeworks/changelog.txt b/pipeworks/changelog.txt
new file mode 100644
index 0000000..251df29
--- /dev/null
+++ b/pipeworks/changelog.txt
@@ -0,0 +1,93 @@
+Changelog
+---------
+
+2013-01-13: Tubes can transport items now! Namely, I added Novatux/Nore's item
+transport mod as a default part of this mod, to make tubes do something useful!
+Thanks to Nore and RealBadAngel for the code contributions!
+
+2013-01-05: made storage tanks connect from top/bottom, made storage tank and
+pipe textures use the ^ combine operator so they can show the actual liquid
+going through the pipes/tanks.
+
+2013-01-04 (a bit later): Made pipes able to carry water! It was just a minor
+logic error resulting from moving the water flowing code into it's own file
+when I originally imported it. Many thanks to Mauvebic for writing it!
+
+2013-01-04: First stage of integrating Mauvebic's water flowing code. This is
+experimental and doesn't move water yet - but at least it doesn't break
+anything :-)
+
+2013-01-01: Various minor tweaks to textures, facedir settings, some other
+stuff. Changed crafting recipes to account for revamped pumps, valves, etc.
+Now requires the moreores mod and most recent git (for mese crystal fragments)
+to craft a pump. Added a "sealed" entry/exit panel (really just a horizontal
+pipe with a metal panel overlayed into the middle). Also, tweaked pipes to
+always drop the empty ones. Revamped pumps so that now they should sit in/on
+liquid and be connected only from the top, relegated grates to decorational-
+only, added outlet spigot. Got rid of a few obsolete textures. Got rid of
+that whole _x and _z naming thing - now all directional devices (pumps, valves,
+spigots, tanks) use facedir. Valves, spigots no longer auto-rotate to find
+nearby pipes.
+
+2012-09-17: Added test object for pneumatic tube autorouting code, made tubes
+connect to it and any object that bears groups={tubedevice=1} (connects to any
+side)
+
+2012-09-05: All recipes doubled except for junglegrass -> plastic sheet (since
+that is derived from home decor)
+
+2012-09-02: Fixed plastic sheeting recipe. Added crafting recipes for various
+objects, with options: If homedecor is installed, use the plastic sheeting
+therein. If not, we define it manually. If the Technic mod is installed,
+don't define any recipes at all. Also removed the extra "loaded!" messages and
+tweaked the default pipe alias to point to something that is actually visible
+:-)
+
+2012-09-01: flattened wielded pipe segment.
+
+2012-08-24: Added square-ish pneumatic tubes with their own autoplace code
+(does not connect to steel pipes or pipe-oriented devices), then revised their
+textures shortly after. Fixed a recursion bug that sometimes caused a stack
+overflow. Old pipes were overriding the pipeworks:pipe defintion that belongs
+with the new pipes.
+
+2012-08-22: Added outlet grate, made it participate in autoplace algorithm.
+Extended storage tank to show fill level in 10% steps (0% to 100%). Added
+"expansion tank" that appears if the user stacks tanks upwards. (Downwards is
+not checked).
+
+2012-08-21: Made storage tank participate in autoplace algorithm. Tuned API a
+little to allow for more flexible placement. Re-organized code a bit to allow
+for some upcoming rules changes. Made storage tanks' upper/lower fittins and
+intake grate participate in autoplace algorithm.
+
+2012-08-20: Added temporary nodes for storage tank and intake grating, but
+without autoplace.
+
+2012-08-19: Pumps and valves now fully participate in the
+auto-rotate/auto-place algorithm.
+
+2012-08-18: Total rewrite again. All pipes are now nice and round-looking, and
+they auto-connect! Also added temporary nodes for pump and valve (each with an
+on/off setting - punch to change). No crafting recipes yet and the pipes still
+don't do anything useful yet. Soon.
+
+2012-08-06: Moved this changelog off the forum post and into a separate file.
+
+2012-08-05 (multiple updates): Rewrote pipeworks to use loops and tables to
+create the nodes. Requires far less code now. Added -X, +X, -Y, +Y, -Z, +Z
+capped stubs and a short centered horizontal segment. Changed node definitions
+so that the aforementioned "short centered" segment is given on dig/drop.
+Renamed it to just "pipeworks:pipe" (and pipe_loaded). Added empty/loaded
+indicator images to the capped ends, removed some redundant comments. Made the
+empty/loaded indication at the capped end more prominent.
+
+2012-07-21: Added screenshot showing pipes as they look now that nodebox
+texture rotation is fixed.
+
+2012-07-18: Changed the mod name and all internals to 'pipeworks' instead of
+'pipes'... after a couple of mistakes :-)
+
+2012-07-12: moved project to github.
+
+2012-06-23: Initial release, followed by reworking the textures a bit.
diff --git a/pipeworks/common.lua b/pipeworks/common.lua
new file mode 100644
index 0000000..1ee734f
--- /dev/null
+++ b/pipeworks/common.lua
@@ -0,0 +1,157 @@
+----------------------
+-- Vector functions --
+----------------------
+
+function vector.cross(a, b)
+ return {
+ x = a.y * b.z - a.z * b.y,
+ y = a.z * b.x - a.x * b.z,
+ z = a.x * b.y - a.y * b.x
+ }
+end
+
+function vector.dot(a, b)
+ return a.x * b.x + a.y * b.y + a.z * b.z
+end
+
+-----------------------
+-- Facedir functions --
+-----------------------
+
+function minetest.facedir_to_top_dir(facedir)
+ return ({[0] = {x = 0, y = 1, z = 0},
+ {x = 0, y = 0, z = 1},
+ {x = 0, y = 0, z = -1},
+ {x = 1, y = 0, z = 0},
+ {x = -1, y = 0, z = 0},
+ {x = 0, y = -1, z = 0}})
+ [math.floor(facedir / 4)]
+end
+
+function minetest.facedir_to_right_dir(facedir)
+ return vector.cross(
+ minetest.facedir_to_top_dir(facedir),
+ minetest.facedir_to_dir(facedir)
+ )
+end
+
+directions = {}
+function directions.side_to_dir(side)
+ return ({[0] = vector.new(),
+ vector.new( 0, 1, 0),
+ vector.new( 0, -1, 0),
+ vector.new( 1, 0, 0),
+ vector.new(-1, 0, 0),
+ vector.new( 0, 0, 1),
+ vector.new( 0, 0, -1)
+ })[side]
+end
+
+function directions.dir_to_side(dir)
+ local c = vector.dot(dir, vector.new(1, 2, 3)) + 4
+ return ({6, 2, 4, 0, 3, 1, 5})[c]
+end
+
+----------------------
+-- String functions --
+----------------------
+
+--[[function string.split(str, sep)
+ local fields = {}
+ local index = 1
+ local expr = "([^"..sep.."])+"
+ string.gsub(str, expr, function(substring)
+ fields[index] = substring
+ index = index + 1
+ end)
+ return fields
+end]]
+
+function string.startswith(str, substr)
+ return str:sub(1, substr:len()) == substr
+end
+
+---------------------
+-- Table functions --
+---------------------
+
+function table.contains(tbl, element)
+ for _, elt in pairs(tbl) do
+ if elt == element then
+ return true
+ end
+ end
+ return false
+end
+
+function table.extend(tbl, tbl2)
+ local index = #tbl + 1
+ for _, elt in ipairs(tbl2) do
+ tbl[index] = elt
+ index = index + 1
+ end
+end
+
+function table.recursive_replace(tbl, pattern, replace_with)
+ if type(tbl) == "table" then
+ local tbl2 = {}
+ for key, value in pairs(tbl) do
+ tbl2[key] = table.recursive_replace(value, pattern, replace_with)
+ end
+ return tbl2
+ elseif type(tbl) == "string" then
+ return tbl:gsub(pattern, replace_with)
+ else
+ return tbl
+ end
+end
+
+------------------------
+-- Formspec functions --
+------------------------
+
+fs_helpers = {}
+function fs_helpers.on_receive_fields(pos, fields)
+ local meta = minetest.get_meta(pos)
+ for field, value in pairs(fields) do
+ if field:startswith("fs_helpers_cycling:") then
+ local l = field:split(":")
+ local new_value = tonumber(l[2])
+ local meta_name = l[3]
+ meta:set_int(meta_name, new_value)
+ end
+ end
+end
+
+function fs_helpers.cycling_button(meta, base, meta_name, values)
+ local current_value = meta:get_int(meta_name)
+ local new_value = (current_value + 1) % (#values)
+ local val = values[current_value + 1]
+ local text
+ local texture_name = nil
+ local addopts = nil
+ --when we get a table, we know the caller wants an image_button
+ if type(val) == "table" then
+ text = val["text"]
+ texture_name = val["texture"]
+ addopts = val["addopts"]
+ else
+ text = val
+ end
+ local field = "fs_helpers_cycling:"..new_value..":"..meta_name
+ return base..";"..(texture_name and texture_name..";" or "")..field..";"..minetest.formspec_escape(text)..(addopts and ";"..addopts or "").."]"
+end
+
+---------
+-- Env --
+---------
+
+function minetest.load_position(pos)
+ if pos.x < -30912 or pos.y < -30912 or pos.z < -30912 or
+ pos.x > 30927 or pos.y > 30927 or pos.z > 30927 then return end
+ if minetest.get_node_or_nil(pos) then
+ return
+ end
+ local vm = minetest.get_voxel_manip()
+ vm:read_from_map(pos, pos)
+end
diff --git a/pipeworks/compat.lua b/pipeworks/compat.lua
new file mode 100644
index 0000000..c89e492
--- /dev/null
+++ b/pipeworks/compat.lua
@@ -0,0 +1,145 @@
+-- this bit of code modifies the default chests and furnaces to be compatible
+-- with pipeworks.
+
+minetest.override_item("default:furnace", {
+ tiles = {
+ "default_furnace_top.png^pipeworks_tube_connection_stony.png",
+ "default_furnace_bottom.png^pipeworks_tube_connection_stony.png",
+ "default_furnace_side.png^pipeworks_tube_connection_stony.png",
+ "default_furnace_side.png^pipeworks_tube_connection_stony.png",
+ "default_furnace_side.png^pipeworks_tube_connection_stony.png",
+ "default_furnace_front.png"
+ },
+ groups = {cracky = 2, tubedevice = 1, tubedevice_receiver = 1},
+ tube = {
+ insert_object = function(pos, node, stack, direction)
+ local meta = minetest.get_meta(pos)
+ local inv = meta:get_inventory()
+ if direction.y == 1 then
+ return inv:add_item("fuel",stack)
+ else
+ return inv:add_item("src",stack)
+ end
+ end,
+ can_insert = function(pos,node,stack,direction)
+ local meta = minetest.get_meta(pos)
+ local inv = meta:get_inventory()
+ if direction.y == 1 then
+ return inv:room_for_item("fuel", stack)
+ else
+ return inv:room_for_item("src", stack)
+ end
+ end,
+ input_inventory = "dst",
+ connect_sides = {left = 1, right = 1, back = 1, front = 1, bottom = 1, top = 1}
+ },
+ after_place_node = pipeworks.after_place,
+ after_dig_node = pipeworks.after_dig
+})
+
+minetest.override_item("default:furnace_active", {
+ tiles = {
+ "default_furnace_top.png^pipeworks_tube_connection_stony.png",
+ "default_furnace_bottom.png^pipeworks_tube_connection_stony.png",
+ "default_furnace_side.png^pipeworks_tube_connection_stony.png",
+ "default_furnace_side.png^pipeworks_tube_connection_stony.png",
+ "default_furnace_side.png^pipeworks_tube_connection_stony.png",
+ {
+ image = "default_furnace_front_active.png",
+ backface_culling = false,
+ animation = {
+ type = "vertical_frames",
+ aspect_w = 16,
+ aspect_h = 16,
+ length = 1.5
+ },
+ }
+ },
+ groups = {cracky = 2, tubedevice = 1, tubedevice_receiver = 1, not_in_creative_inventory = 1},
+ tube = {
+ insert_object = function(pos,node,stack,direction)
+ local meta = minetest.get_meta(pos)
+ local inv = meta:get_inventory()
+ if direction.y == 1 then
+ return inv:add_item("fuel", stack)
+ else
+ return inv:add_item("src", stack)
+ end
+ end,
+ can_insert = function(pos, node, stack, direction)
+ local meta = minetest.get_meta(pos)
+ local inv = meta:get_inventory()
+ if direction.y == 1 then
+ return inv:room_for_item("fuel", stack)
+ else
+ return inv:room_for_item("src", stack)
+ end
+ end,
+ input_inventory = "dst",
+ connect_sides = {left = 1, right = 1, back = 1, front = 1, bottom = 1, top = 1}
+ },
+ after_place_node = pipeworks.after_place,
+ after_dig_node = pipeworks.after_dig
+})
+
+minetest.override_item("default:chest", {
+ tiles = {
+ "default_chest_top.png^pipeworks_tube_connection_wooden.png",
+ "default_chest_top.png^pipeworks_tube_connection_wooden.png",
+ "default_chest_side.png^pipeworks_tube_connection_wooden.png",
+ "default_chest_side.png^pipeworks_tube_connection_wooden.png",
+ "default_chest_side.png^pipeworks_tube_connection_wooden.png",
+ "default_chest_front.png"
+ },
+ groups = {choppy = 2, oddly_breakable_by_hand = 2, tubedevice = 1, tubedevice_receiver = 1},
+ tube = {
+ insert_object = function(pos, node, stack, direction)
+ local meta = minetest.get_meta(pos)
+ local inv = meta:get_inventory()
+ return inv:add_item("main", stack)
+ end,
+ can_insert = function(pos, node, stack, direction)
+ local meta = minetest.get_meta(pos)
+ local inv = meta:get_inventory()
+ return inv:room_for_item("main", stack)
+ end,
+ input_inventory = "main",
+ connect_sides = {left = 1, right = 1, back = 1, front = 1, bottom = 1, top = 1}
+ },
+ after_place_node = pipeworks.after_place,
+ after_dig_node = pipeworks.after_dig
+})
+
+minetest.override_item("default:chest_locked", {
+ tiles = {
+ "default_chest_top.png^pipeworks_tube_connection_wooden.png",
+ "default_chest_top.png^pipeworks_tube_connection_wooden.png",
+ "default_chest_side.png^pipeworks_tube_connection_wooden.png",
+ "default_chest_side.png^pipeworks_tube_connection_wooden.png",
+ "default_chest_side.png^pipeworks_tube_connection_wooden.png",
+ "default_chest_lock.png"
+ },
+ groups = {choppy = 2, oddly_breakable_by_hand = 2, tubedevice = 1, tubedevice_receiver = 1},
+ tube = {
+ insert_object = function(pos, node, stack, direction)
+ local meta = minetest.get_meta(pos)
+ local inv = meta:get_inventory()
+ return inv:add_item("main", stack)
+ end,
+ can_insert = function(pos, node, stack, direction)
+ local meta = minetest.get_meta(pos)
+ local inv = meta:get_inventory()
+ return inv:room_for_item("main", stack)
+ end,
+ connect_sides = {left = 1, right = 1, back = 1, front = 1, bottom = 1, top = 1}
+ },
+ after_place_node = function (pos, placer)
+ local meta = minetest.get_meta(pos)
+ meta:set_string("owner", placer:get_player_name() or "")
+ meta:set_string("infotext", "Locked Chest (owned by "..
+ meta:get_string("owner")..")")
+ pipeworks.after_place(pos)
+ end,
+ after_dig_node = pipeworks.after_dig
+})
+
diff --git a/pipeworks/crafts.lua b/pipeworks/crafts.lua
new file mode 100644
index 0000000..63a04b7
--- /dev/null
+++ b/pipeworks/crafts.lua
@@ -0,0 +1,151 @@
+-- Crafting recipes for pipes
+
+minetest.register_craft( {
+ output = "pipeworks:pipe_1_empty 12",
+ recipe = {
+ { "default:steel_ingot", "default:steel_ingot", "default:steel_ingot" },
+ { "", "", "" },
+ { "default:steel_ingot", "default:steel_ingot", "default:steel_ingot" }
+ },
+})
+
+minetest.register_craft( {
+ output = "pipeworks:spigot 3",
+ recipe = {
+ { "pipeworks:pipe_1_empty", "" },
+ { "", "pipeworks:pipe_1_empty" },
+ },
+})
+
+minetest.register_craft( {
+ output = "pipeworks:entry_panel_empty 2",
+ recipe = {
+ { "", "default:steel_ingot", "" },
+ { "", "pipeworks:pipe_1_empty", "" },
+ { "", "default:steel_ingot", "" },
+ },
+})
+
+-- Various ancillary pipe devices
+
+minetest.register_craft( {
+ output = "pipeworks:pump_off 2",
+ recipe = {
+ { "default:stone", "default:steel_ingot", "default:stone" },
+ { "default:copper_ingot", "default:mese_crystal_fragment", "default:copper_ingot" },
+ { "default:steel_ingot", "default:steel_ingot", "default:steel_ingot" }
+ },
+})
+
+minetest.register_craft( {
+ output = "pipeworks:valve_off_empty 2",
+ recipe = {
+ { "", "group:stick", "" },
+ { "default:steel_ingot", "default:steel_ingot", "default:steel_ingot" },
+ { "", "default:steel_ingot", "" }
+ },
+})
+
+minetest.register_craft( {
+ output = "pipeworks:storage_tank_0 2",
+ recipe = {
+ { "", "default:steel_ingot", "default:steel_ingot" },
+ { "default:steel_ingot", "default:glass", "default:steel_ingot" },
+ { "default:steel_ingot", "default:steel_ingot", "" }
+ },
+})
+
+minetest.register_craft( {
+ output = "pipeworks:grating 2",
+ recipe = {
+ { "default:steel_ingot", "", "default:steel_ingot" },
+ { "", "pipeworks:pipe_1_empty", "" },
+ { "default:steel_ingot", "", "default:steel_ingot" }
+ },
+})
+
+minetest.register_craft( {
+ output = "pipeworks:flow_sensor_empty 2",
+ recipe = {
+ { "pipeworks:pipe_1_empty", "mesecons:mesecon", "pipeworks:pipe_1_empty" },
+ },
+})
+
+minetest.register_craft( {
+ output = "pipeworks:fountainhead 2",
+ recipe = {
+ { "pipeworks:pipe_1_empty" },
+ { "pipeworks:pipe_1_empty" }
+ },
+})
+
+
+-- Crafting recipes for pneumatic tubes
+
+-- If homedecor is not installed, we need to register its crafting chain for
+-- plastic sheeting so that pipeworks remains compatible with it.
+
+if minetest.get_modpath("homedecor") == nil then
+
+ minetest.register_craftitem(":homedecor:oil_extract", {
+ description = "Oil extract",
+ inventory_image = "homedecor_oil_extract.png",
+ })
+
+ minetest.register_craftitem(":homedecor:paraffin", {
+ description = "Unprocessed paraffin",
+ inventory_image = "homedecor_paraffin.png",
+ })
+
+ minetest.register_alias("homedecor:plastic_base", "homedecor:paraffin")
+
+ minetest.register_craftitem(":homedecor:plastic_sheeting", {
+ description = "Plastic sheet",
+ inventory_image = "homedecor_plastic_sheeting.png",
+ })
+
+ minetest.register_craft({
+ type = "shapeless",
+ output = "homedecor:oil_extract 4",
+ recipe = {
+ "group:leaves",
+ "group:leaves",
+ "group:leaves",
+ "group:leaves",
+ "group:leaves",
+ "group:leaves"
+ }
+ })
+
+ minetest.register_craft({
+ type = "cooking",
+ output = "homedecor:paraffin",
+ recipe = "homedecor:oil_extract",
+ })
+
+ minetest.register_craft({
+ type = "cooking",
+ output = "homedecor:plastic_sheeting",
+ recipe = "homedecor:paraffin",
+ })
+
+ minetest.register_craft({
+ type = "fuel",
+ recipe = "homedecor:oil_extract",
+ burntime = 30,
+ })
+
+ minetest.register_craft({
+ type = "fuel",
+ recipe = "homedecor:paraffin",
+ burntime = 30,
+ })
+
+ minetest.register_craft({
+ type = "fuel",
+ recipe = "homedecor:plastic_sheeting",
+ burntime = 30,
+ })
+end
+
+
diff --git a/pipeworks/decorative_tubes.lua b/pipeworks/decorative_tubes.lua
new file mode 100644
index 0000000..39ba8f3
--- /dev/null
+++ b/pipeworks/decorative_tubes.lua
@@ -0,0 +1,83 @@
+local straight = function(pos, node, velocity, stack) return {velocity} end
+
+minetest.register_node("pipeworks:steel_block_embedded_tube", {
+ description = "Airtight steelblock embedded tube",
+ tiles = {
+ "default_steel_block.png", "default_steel_block.png",
+ "default_steel_block.png", "default_steel_block.png",
+ "default_steel_block.png^pipeworks_tube_connection_metallic.png",
+ "default_steel_block.png^pipeworks_tube_connection_metallic.png",
+ },
+ paramtype = "light",
+ paramtype2 = "facedir",
+ groups = {cracky=1, oddly_breakable_by_hand = 1, tubedevice = 1},
+ legacy_facedir_simple = true,
+ sounds = default.node_sound_stone_defaults(),
+ tube = {
+ connect_sides = {front = 1, back = 1,},
+ priority = 50,
+ can_go = straight,
+ can_insert = function(pos, node, stack, direction)
+ local dir = minetest.facedir_to_dir(node.param2)
+ return vector.equals(dir, direction) or vector.equals(vector.multiply(dir, -1), direction)
+ end,
+ },
+ after_place_node = pipeworks.after_place,
+ after_dig_node = pipeworks.after_dig,
+})
+
+minetest.register_craft( {
+ output = "pipeworks:steel_block_embedded_tube 1",
+ recipe = {
+ { "default:steel_ingot", "default:steel_ingot", "default:steel_ingot" },
+ { "default:steel_ingot", "pipeworks:tube_1", "default:steel_ingot" },
+ { "default:steel_ingot", "default:steel_ingot", "default:steel_ingot" }
+ },
+})
+
+local pane_box = {
+ type = "fixed",
+ fixed = {
+ { -9/64, -9/64, -8/16, 9/64, 9/64, 8/16 }, -- tube
+ { -8/16, -8/16, -1/16, 8/16, 8/16, 1/16 } -- pane
+ }
+}
+minetest.register_node("pipeworks:steel_pane_embedded_tube", {
+ drawtype = "nodebox",
+ description = "Airtight panel embedded tube ",
+ tiles = {
+ "pipeworks_pane_embedded_tube_sides.png^[transformR90",
+ "pipeworks_pane_embedded_tube_sides.png^[transformR90",
+ "pipeworks_pane_embedded_tube_sides.png",
+ "pipeworks_pane_embedded_tube_sides.png",
+ "pipeworks_pane_embedded_tube_ends.png", "pipeworks_pane_embedded_tube_ends.png",
+ },
+ node_box = pane_box,
+ selection_box = pane_box,
+ collision_box = pane_box,
+ paramtype = "light",
+ paramtype2 = "facedir",
+ groups = {cracky=1, oddly_breakable_by_hand = 1, tubedevice = 1},
+ legacy_facedir_simple = true,
+ sounds = default.node_sound_stone_defaults(),
+ tube = {
+ connect_sides = {front = 1, back = 1,},
+ priority = 50,
+ can_go = straight,
+ can_insert = function(pos, node, stack, direction)
+ local dir = minetest.facedir_to_dir(node.param2)
+ return vector.equals(dir, direction) or vector.equals(vector.multiply(dir, -1), direction)
+ end,
+ },
+ after_place_node = pipeworks.after_place,
+ after_dig_node = pipeworks.after_dig,
+})
+
+minetest.register_craft( {
+ output = "pipeworks:steel_pane_embedded_tube 1",
+ recipe = {
+ { "", "default:steel_ingot", "" },
+ { "", "pipeworks:tube_1", "" },
+ { "", "default:steel_ingot", "" }
+ },
+})
diff --git a/pipeworks/default_settings.txt b/pipeworks/default_settings.txt
new file mode 100644
index 0000000..bbf02ce
--- /dev/null
+++ b/pipeworks/default_settings.txt
@@ -0,0 +1,22 @@
+-- Various settings
+
+pipeworks.enable_pipes = true
+pipeworks.enable_autocrafter = true
+pipeworks.enable_deployer = true
+pipeworks.enable_dispenser = true
+pipeworks.enable_node_breaker = true
+pipeworks.enable_teleport_tube = true
+pipeworks.enable_pipe_devices = true
+pipeworks.enable_redefines = true
+pipeworks.enable_mese_tube = true
+pipeworks.enable_detector_tube = true
+pipeworks.enable_conductor_tube = true
+pipeworks.enable_accelerator_tube = true
+pipeworks.enable_crossing_tube = true
+pipeworks.enable_sand_tube = true
+pipeworks.enable_mese_sand_tube = true
+pipeworks.enable_one_way_tube = true
+pipeworks.enable_priority_tube = true
+pipeworks.enable_cyclic_mode = true
+
+pipeworks.delete_item_on_clearobject = true \ No newline at end of file
diff --git a/pipeworks/depends.txt b/pipeworks/depends.txt
new file mode 100644
index 0000000..02a542c
--- /dev/null
+++ b/pipeworks/depends.txt
@@ -0,0 +1,3 @@
+default
+mesecons?
+mesecons_mvps?
diff --git a/pipeworks/devices.lua b/pipeworks/devices.lua
new file mode 100644
index 0000000..52f3002
--- /dev/null
+++ b/pipeworks/devices.lua
@@ -0,0 +1,572 @@
+-- List of devices that should participate in the autoplace algorithm
+
+local pipereceptor_on = nil
+local pipereceptor_off = nil
+
+if mesecon then
+ pipereceptor_on = {
+ receptor = {
+ state = mesecon.state.on,
+ rules = pipeworks.mesecons_rules
+ }
+ }
+
+ pipereceptor_off = {
+ receptor = {
+ state = mesecon.state.off,
+ rules = pipeworks.mesecons_rules
+ }
+ }
+end
+
+local pipes_devicelist = {
+ "pump",
+ "valve",
+ "storage_tank_0",
+ "storage_tank_1",
+ "storage_tank_2",
+ "storage_tank_3",
+ "storage_tank_4",
+ "storage_tank_5",
+ "storage_tank_6",
+ "storage_tank_7",
+ "storage_tank_8",
+ "storage_tank_9",
+ "storage_tank_10"
+}
+
+-- Now define the nodes.
+
+local states = { "on", "off" }
+local dgroups = ""
+
+for s in ipairs(states) do
+
+ if states[s] == "off" then
+ dgroups = {snappy=3, pipe=1}
+ else
+ dgroups = {snappy=3, pipe=1, not_in_creative_inventory=1}
+ end
+
+ minetest.register_node("pipeworks:pump_"..states[s], {
+ description = "Pump/Intake Module",
+ drawtype = "mesh",
+ mesh = "pipeworks_pump.obj",
+ tiles = { "pipeworks_pump_"..states[s]..".png" },
+ paramtype = "light",
+ paramtype2 = "facedir",
+ groups = dgroups,
+ sounds = default.node_sound_wood_defaults(),
+ walkable = true,
+ after_place_node = function(pos)
+ pipeworks.scan_for_pipe_objects(pos)
+ end,
+ after_dig_node = function(pos)
+ pipeworks.scan_for_pipe_objects(pos)
+ end,
+ drop = "pipeworks:pump_off",
+ mesecons = {effector = {
+ action_on = function (pos, node)
+ minetest.add_node(pos,{name="pipeworks:pump_on", param2 = node.param2})
+ end,
+ action_off = function (pos, node)
+ minetest.add_node(pos,{name="pipeworks:pump_off", param2 = node.param2})
+ end
+ }},
+ on_punch = function(pos, node, puncher)
+ local fdir = minetest.get_node(pos).param2
+ minetest.add_node(pos, { name = "pipeworks:pump_"..states[3-s], param2 = fdir })
+ end
+ })
+
+ minetest.register_node("pipeworks:valve_"..states[s].."_empty", {
+ description = "Valve",
+ drawtype = "mesh",
+ mesh = "pipeworks_valve_"..states[s]..".obj",
+ tiles = { "pipeworks_valve.png" },
+ sunlight_propagates = true,
+ paramtype = "light",
+ paramtype2 = "facedir",
+ selection_box = {
+ type = "fixed",
+ fixed = { -8/16, -4/16, -5/16, 8/16, 5/16, 5/16 }
+ },
+ collision_box = {
+ type = "fixed",
+ fixed = { -8/16, -4/16, -5/16, 8/16, 5/16, 5/16 }
+ },
+ groups = dgroups,
+ sounds = default.node_sound_wood_defaults(),
+ walkable = true,
+ after_place_node = function(pos)
+ pipeworks.scan_for_pipe_objects(pos)
+ end,
+ after_dig_node = function(pos)
+ pipeworks.scan_for_pipe_objects(pos)
+ end,
+ drop = "pipeworks:valve_off_empty",
+ mesecons = {effector = {
+ action_on = function (pos, node)
+ minetest.add_node(pos,{name="pipeworks:valve_on_empty", param2 = node.param2})
+ end,
+ action_off = function (pos, node)
+ minetest.add_node(pos,{name="pipeworks:valve_off_empty", param2 = node.param2})
+ end
+ }},
+ on_punch = function(pos, node, puncher)
+ local fdir = minetest.get_node(pos).param2
+ minetest.add_node(pos, { name = "pipeworks:valve_"..states[3-s].."_empty", param2 = fdir })
+ end
+ })
+end
+
+minetest.register_node("pipeworks:valve_on_loaded", {
+ description = "Valve",
+ drawtype = "mesh",
+ mesh = "pipeworks_valve_on.obj",
+ tiles = { "pipeworks_valve.png" },
+ sunlight_propagates = true,
+ paramtype = "light",
+ paramtype2 = "facedir",
+ selection_box = {
+ type = "fixed",
+ fixed = { -8/16, -4/16, -5/16, 8/16, 5/16, 5/16 }
+ },
+ collision_box = {
+ type = "fixed",
+ fixed = { -8/16, -4/16, -5/16, 8/16, 5/16, 5/16 }
+ },
+ groups = {snappy=3, pipe=1, not_in_creative_inventory=1},
+ sounds = default.node_sound_wood_defaults(),
+ walkable = true,
+ after_place_node = function(pos)
+ pipeworks.scan_for_pipe_objects(pos)
+ end,
+ after_dig_node = function(pos)
+ pipeworks.scan_for_pipe_objects(pos)
+ end,
+ drop = "pipeworks:valve_off_empty",
+ mesecons = {effector = {
+ action_on = function (pos, node)
+ minetest.add_node(pos,{name="pipeworks:valve_on_empty", param2 = node.param2})
+ end,
+ action_off = function (pos, node)
+ minetest.add_node(pos,{name="pipeworks:valve_off_empty", param2 = node.param2})
+ end
+ }},
+ on_punch = function(pos, node, puncher)
+ local fdir = minetest.get_node(pos).param2
+ minetest.add_node(pos, { name = "pipeworks:valve_off_empty", param2 = fdir })
+ end
+})
+
+-- grating
+
+minetest.register_node("pipeworks:grating", {
+ description = "Decorative grating",
+ tiles = {
+ "pipeworks_grating_top.png",
+ "pipeworks_grating_sides.png",
+ "pipeworks_grating_sides.png",
+ "pipeworks_grating_sides.png",
+ "pipeworks_grating_sides.png",
+ "pipeworks_grating_sides.png"
+ },
+ sunlight_propagates = true,
+ paramtype = "light",
+ groups = {snappy=3, pipe=1},
+ sounds = default.node_sound_wood_defaults(),
+ walkable = true,
+ after_place_node = function(pos)
+ pipeworks.scan_for_pipe_objects(pos)
+ end,
+ after_dig_node = function(pos)
+ pipeworks.scan_for_pipe_objects(pos)
+ end,
+})
+
+-- outlet spigot
+
+minetest.register_node("pipeworks:spigot", {
+ description = "Spigot outlet",
+ drawtype = "mesh",
+ mesh = "pipeworks_spigot.obj",
+ tiles = { "pipeworks_spigot.png" },
+ sunlight_propagates = true,
+ paramtype = "light",
+ paramtype2 = "facedir",
+ groups = {snappy=3, pipe=1},
+ sounds = default.node_sound_wood_defaults(),
+ walkable = true,
+ after_place_node = function(pos)
+ pipeworks.scan_for_pipe_objects(pos)
+ end,
+ after_dig_node = function(pos)
+ pipeworks.scan_for_pipe_objects(pos)
+ end,
+ selection_box = {
+ type = "fixed",
+ fixed = { -2/16, -6/16, -2/16, 2/16, 2/16, 8/16 }
+ },
+ collision_box = {
+ type = "fixed",
+ fixed = { -2/16, -6/16, -2/16, 2/16, 2/16, 8/16 }
+ }
+})
+
+minetest.register_node("pipeworks:spigot_pouring", {
+ description = "Spigot outlet",
+ drawtype = "mesh",
+ mesh = "pipeworks_spigot_pouring.obj",
+ tiles = {
+ {
+ name = "default_water_flowing_animated.png",
+ animation = {
+ type = "vertical_frames",
+ aspect_w = 16,
+ aspect_h = 16,
+ length = 0.8,
+ },
+ },
+ { name = "pipeworks_spigot.png" }
+ },
+ sunlight_propagates = true,
+ paramtype = "light",
+ paramtype2 = "facedir",
+ groups = {snappy=3, pipe=1, not_in_creative_inventory=1},
+ sounds = default.node_sound_wood_defaults(),
+ walkable = true,
+ after_place_node = function(pos)
+ pipeworks.scan_for_pipe_objects(pos)
+ end,
+ after_dig_node = function(pos)
+ pipeworks.scan_for_pipe_objects(pos)
+ end,
+ selection_box = {
+ type = "fixed",
+ fixed = { -2/16, -6/16, -2/16, 2/16, 2/16, 8/16 }
+ },
+ collision_box = {
+ type = "fixed",
+ fixed = { -2/16, -6/16, -2/16, 2/16, 2/16, 8/16 }
+ },
+ drop = "pipeworks:spigot",
+})
+
+-- sealed pipe entry/exit (horizontal pipe passing through a metal
+-- wall, for use in places where walls should look like they're airtight)
+
+local panel_cbox = {
+ type = "fixed",
+ fixed = {
+ { -2/16, -2/16, -8/16, 2/16, 2/16, 8/16 },
+ { -8/16, -8/16, -1/16, 8/16, 8/16, 1/16 }
+ }
+}
+
+minetest.register_node("pipeworks:entry_panel_empty", {
+ description = "Airtight Pipe entry/exit",
+ drawtype = "mesh",
+ mesh = "pipeworks_entry_panel.obj",
+ tiles = { "pipeworks_entry_panel.png" },
+ paramtype = "light",
+ paramtype2 = "facedir",
+ groups = {snappy=3, pipe=1},
+ sounds = default.node_sound_wood_defaults(),
+ walkable = true,
+ after_place_node = function(pos)
+ pipeworks.scan_for_pipe_objects(pos)
+ end,
+ after_dig_node = function(pos)
+ pipeworks.scan_for_pipe_objects(pos)
+ end,
+ selection_box = panel_cbox,
+ collision_box = panel_cbox,
+ on_place = function(itemstack, placer, pointed_thing)
+ local playername = placer:get_player_name()
+ if not minetest.is_protected(pointed_thing.under, playername)
+ and not minetest.is_protected(pointed_thing.above, playername) then
+ local node = minetest.get_node(pointed_thing.under)
+
+ if not minetest.registered_nodes[node.name]
+ or not minetest.registered_nodes[node.name].on_rightclick then
+ local pitch = placer:get_look_pitch()
+ local above = pointed_thing.above
+ local under = pointed_thing.under
+ local fdir = minetest.dir_to_facedir(placer:get_look_dir())
+ local undernode = minetest.get_node(under)
+ local abovenode = minetest.get_node(above)
+ local uname = undernode.name
+ local aname = abovenode.name
+ local isabove = (above.x == under.x) and (above.z == under.z) and (pitch > 0)
+ local pos1 = above
+
+ if above.x == under.x
+ and above.z == under.z
+ and ( string.find(uname, "pipeworks:pipe_")
+ or string.find(uname, "pipeworks:storage_")
+ or string.find(uname, "pipeworks:expansion_")
+ or ( string.find(uname, "pipeworks:grating") and not isabove )
+ or ( string.find(uname, "pipeworks:pump_") and not isabove )
+ or ( string.find(uname, "pipeworks:entry_panel")
+ and undernode.param2 == 13 )
+ )
+ then
+ fdir = 13
+ end
+
+ if minetest.registered_nodes[uname]["buildable_to"] then
+ pos1 = under
+ end
+
+ if not minetest.registered_nodes[minetest.get_node(pos1).name]["buildable_to"] then return end
+
+ minetest.add_node(pos1, {name = "pipeworks:entry_panel_empty", param2 = fdir })
+ pipeworks.scan_for_pipe_objects(pos1)
+
+ if not pipeworks.expect_infinite_stacks then
+ itemstack:take_item()
+ end
+
+ else
+ minetest.registered_nodes[node.name].on_rightclick(pointed_thing.under, node, placer, itemstack)
+ end
+ end
+ return itemstack
+ end
+})
+
+minetest.register_node("pipeworks:entry_panel_loaded", {
+ description = "Airtight Pipe entry/exit",
+ drawtype = "mesh",
+ mesh = "pipeworks_entry_panel.obj",
+ tiles = { "pipeworks_entry_panel.png" },
+ paramtype = "light",
+ paramtype2 = "facedir",
+ groups = {snappy=3, pipe=1, not_in_creative_inventory=1},
+ sounds = default.node_sound_wood_defaults(),
+ walkable = true,
+ after_place_node = function(pos)
+ pipeworks.scan_for_pipe_objects(pos)
+ end,
+ after_dig_node = function(pos)
+ pipeworks.scan_for_pipe_objects(pos)
+ end,
+ selection_box = panel_cbox,
+ collision_box = panel_cbox,
+ drop = "pipeworks:entry_panel_empty"
+})
+
+minetest.register_node("pipeworks:flow_sensor_empty", {
+ description = "Flow Sensor",
+ drawtype = "mesh",
+ mesh = "pipeworks_flow_sensor.obj",
+ tiles = { "pipeworks_flow_sensor_off.png" },
+ sunlight_propagates = true,
+ paramtype = "light",
+ paramtype2 = "facedir",
+ groups = {snappy=3, pipe=1},
+ sounds = default.node_sound_wood_defaults(),
+ walkable = true,
+ after_place_node = function(pos)
+ pipeworks.scan_for_pipe_objects(pos)
+ end,
+ after_dig_node = function(pos)
+ pipeworks.scan_for_pipe_objects(pos)
+ end,
+ on_construct = function(pos)
+ if mesecon then
+ mesecon.receptor_off(pos, rules)
+ end
+ end,
+ selection_box = {
+ type = "fixed",
+ fixed = {
+ { -8/16, -2/16, -2/16, 8/16, 2/16, 2/16 },
+ { -4/16, -3/16, -3/16, 4/16, 3/16, 3/16 },
+ }
+ },
+ collision_box = {
+ type = "fixed",
+ fixed = {
+ { -8/16, -2/16, -2/16, 8/16, 2/16, 2/16 },
+ { -4/16, -3/16, -3/16, 4/16, 3/16, 3/16 },
+ }
+ },
+ mesecons = pipereceptor_off
+})
+
+minetest.register_node("pipeworks:flow_sensor_loaded", {
+ description = "Flow sensor (on)",
+ drawtype = "mesh",
+ mesh = "pipeworks_flow_sensor.obj",
+ tiles = { "pipeworks_flow_sensor_on.png" },
+ sunlight_propagates = true,
+ paramtype = "light",
+ paramtype2 = "facedir",
+ groups = {snappy=3, pipe=1, not_in_creative_inventory=1},
+ sounds = default.node_sound_wood_defaults(),
+ walkable = true,
+ after_place_node = function(pos)
+ pipeworks.scan_for_pipe_objects(pos)
+ end,
+ after_dig_node = function(pos)
+ pipeworks.scan_for_pipe_objects(pos)
+ end,
+ on_construct = function(pos)
+ if mesecon then
+ mesecon.receptor_on(pos, rules)
+ end
+ end,
+ selection_box = {
+ type = "fixed",
+ fixed = {
+ { -8/16, -2/16, -2/16, 8/16, 2/16, 2/16 },
+ { -4/16, -3/16, -3/16, 4/16, 3/16, 3/16 },
+ }
+ },
+ collision_box = {
+ type = "fixed",
+ fixed = {
+ { -8/16, -2/16, -2/16, 8/16, 2/16, 2/16 },
+ { -4/16, -3/16, -3/16, 4/16, 3/16, 3/16 },
+ }
+ },
+ drop = "pipeworks:flow_sensor_empty",
+ mesecons = pipereceptor_on
+})
+
+-- tanks
+
+for fill = 0, 10 do
+ local filldesc="empty"
+ local sgroups = {snappy=3, pipe=1, tankfill=fill+1}
+ local image = nil
+
+ if fill ~= 0 then
+ filldesc=fill.."0% full"
+ sgroups = {snappy=3, pipe=1, tankfill=fill+1, not_in_creative_inventory=1}
+ image = "pipeworks_storage_tank_fittings.png"
+ end
+
+ minetest.register_node("pipeworks:expansion_tank_"..fill, {
+ description = "Expansion Tank ("..filldesc..")... You hacker, you.",
+ tiles = {
+ "pipeworks_storage_tank_fittings.png",
+ "pipeworks_storage_tank_fittings.png",
+ "pipeworks_storage_tank_back.png",
+ "pipeworks_storage_tank_back.png",
+ "pipeworks_storage_tank_back.png",
+ pipeworks.liquid_texture.."^pipeworks_storage_tank_front_"..fill..".png"
+ },
+ inventory_image = image,
+ paramtype = "light",
+ paramtype2 = "facedir",
+ groups = {snappy=3, pipe=1, tankfill=fill+1, not_in_creative_inventory=1},
+ sounds = default.node_sound_wood_defaults(),
+ walkable = true,
+ drop = "pipeworks:storage_tank_0",
+ after_place_node = function(pos)
+ pipeworks.look_for_stackable_tanks(pos)
+ pipeworks.scan_for_pipe_objects(pos)
+ end,
+ after_dig_node = function(pos)
+ pipeworks.scan_for_pipe_objects(pos)
+ end,
+ })
+
+ minetest.register_node("pipeworks:storage_tank_"..fill, {
+ description = "Fluid Storage Tank ("..filldesc..")",
+ tiles = {
+ "pipeworks_storage_tank_fittings.png",
+ "pipeworks_storage_tank_fittings.png",
+ "pipeworks_storage_tank_back.png",
+ "pipeworks_storage_tank_back.png",
+ "pipeworks_storage_tank_back.png",
+ pipeworks.liquid_texture.."^pipeworks_storage_tank_front_"..fill..".png"
+ },
+ inventory_image = image,
+ paramtype = "light",
+ paramtype2 = "facedir",
+ groups = sgroups,
+ sounds = default.node_sound_wood_defaults(),
+ walkable = true,
+ drop = "pipeworks:storage_tank_0",
+ after_place_node = function(pos)
+ pipeworks.look_for_stackable_tanks(pos)
+ pipeworks.scan_for_pipe_objects(pos)
+ end,
+ after_dig_node = function(pos)
+ pipeworks.scan_for_pipe_objects(pos)
+ end,
+ })
+end
+
+-- fountainhead
+
+minetest.register_node("pipeworks:fountainhead", {
+ description = "Fountainhead",
+ drawtype = "mesh",
+ mesh = "pipeworks_fountainhead.obj",
+ tiles = { "pipeworks_fountainhead.png" },
+ sunlight_propagates = true,
+ paramtype = "light",
+ groups = {snappy=3, pipe=1},
+ sounds = default.node_sound_wood_defaults(),
+ walkable = true,
+ after_place_node = function(pos)
+ pipeworks.scan_for_pipe_objects(pos)
+ end,
+ after_dig_node = function(pos)
+ pipeworks.scan_for_pipe_objects(pos)
+ end,
+ on_construct = function(pos)
+ if mesecon then
+ mesecon.receptor_on(pos, rules)
+ end
+ end,
+ selection_box = {
+ type = "fixed",
+ fixed = { -2/16, -8/16, -2/16, 2/16, 8/16, 2/16 }
+ },
+ collision_box = {
+ type = "fixed",
+ fixed = { -2/16, -8/16, -2/16, 2/16, 8/16, 2/16 }
+ },
+})
+
+minetest.register_node("pipeworks:fountainhead_pouring", {
+ description = "Fountainhead",
+ drawtype = "mesh",
+ mesh = "pipeworks_fountainhead.obj",
+ tiles = { "pipeworks_fountainhead.png" },
+ sunlight_propagates = true,
+ paramtype = "light",
+ groups = {snappy=3, pipe=1, not_in_creative_inventory=1},
+ sounds = default.node_sound_wood_defaults(),
+ walkable = true,
+ after_place_node = function(pos)
+ pipeworks.scan_for_pipe_objects(pos)
+ end,
+ after_dig_node = function(pos)
+ pipeworks.scan_for_pipe_objects(pos)
+ end,
+ on_construct = function(pos)
+ if mesecon then
+ mesecon.receptor_on(pos, rules)
+ end
+ end,
+ selection_box = {
+ type = "fixed",
+ fixed = { -2/16, -8/16, -2/16, 2/16, 8/16, 2/16 }
+ },
+ collision_box = {
+ type = "fixed",
+ fixed = { -2/16, -8/16, -2/16, 2/16, 8/16, 2/16 }
+ },
+ drop = "pipeworks:fountainhead"
+})
+
+minetest.register_alias("pipeworks:valve_off_loaded", "pipeworks:valve_off_empty")
+minetest.register_alias("pipeworks:entry_panel", "pipeworks:entry_panel_empty")
+
diff --git a/pipeworks/filter-injector.lua b/pipeworks/filter-injector.lua
new file mode 100644
index 0000000..bcfcbc9
--- /dev/null
+++ b/pipeworks/filter-injector.lua
@@ -0,0 +1,239 @@
+local function delay(x)
+ return (function() return x end)
+end
+
+local function set_filter_infotext(data, meta)
+ local infotext = data.wise_desc.." Filter-Injector"
+ if meta:get_int("slotseq_mode") == 2 then
+ infotext = infotext .. " (slot #"..meta:get_int("slotseq_index").." next)"
+ end
+ meta:set_string("infotext", infotext)
+end
+
+local function set_filter_formspec(data, meta)
+ local itemname = data.wise_desc.." Filter-Injector"
+ local formspec = "size[8,8.5]"..
+ "item_image[0,0;1,1;pipeworks:"..data.name.."]"..
+ "label[1,0;"..minetest.formspec_escape(itemname).."]"..
+ "label[0,1;Prefer item types:]"..
+ "list[context;main;0,1.5;8,2;]"..
+ fs_helpers.cycling_button(meta, "button[0,3.5;4,1", "slotseq_mode",
+ {"Sequence slots by Priority",
+ "Sequence slots Randomly",
+ "Sequence slots by Rotation"})..
+ "list[current_player;main;0,4.5;8,4;]"
+ meta:set_string("formspec", formspec)
+end
+
+-- todo SOON: this function has *way too many* parameters
+local function grabAndFire(data,slotseq_mode,filtmeta,frominv,frominvname,frompos,fromnode,filterfor,fromtube,fromdef,dir,fakePlayer,all)
+ local sposes = {}
+ for spos,stack in ipairs(frominv:get_list(frominvname)) do
+ local matches
+ if filterfor == "" then
+ matches = stack:get_name() ~= ""
+ else
+ matches = stack:get_name() == filterfor.name
+ end
+ if matches then table.insert(sposes, spos) end
+ end
+ if #sposes == 0 then return false end
+ if slotseq_mode == 1 then
+ for i = #sposes, 2, -1 do
+ local j = math.random(i)
+ local t = sposes[j]
+ sposes[j] = sposes[i]
+ sposes[i] = t
+ end
+ elseif slotseq_mode == 2 then
+ local headpos = filtmeta:get_int("slotseq_index")
+ table.sort(sposes, function (a, b)
+ if a >= headpos then
+ if b < headpos then return true end
+ else
+ if b >= headpos then return false end
+ end
+ return a < b
+ end)
+ end
+ for _, spos in ipairs(sposes) do
+ local stack = frominv:get_stack(frominvname, spos)
+ local doRemove = stack:get_count()
+ if fromtube.can_remove then
+ doRemove = fromtube.can_remove(frompos, fromnode, stack, dir)
+ elseif fromdef.allow_metadata_inventory_take then
+ doRemove = fromdef.allow_metadata_inventory_take(frompos, frominvname,spos, stack, fakePlayer)
+ end
+ -- stupid lack of continue statements grumble
+ if doRemove > 0 then
+ if slotseq_mode == 2 then
+ local nextpos = spos + 1
+ if nextpos > frominv:get_size(frominvname) then
+ nextpos = 1
+ end
+ filtmeta:set_int("slotseq_index", nextpos)
+ set_filter_infotext(data, filtmeta)
+ end
+ local item
+ local count
+ if all then
+ count = math.min(stack:get_count(), doRemove)
+ if filterfor.count and filterfor.count > 1 then
+ count = math.min(filterfor.count, count)
+ end
+ else
+ count = 1
+ end
+ if fromtube.remove_items then
+ -- it could be the entire stack...
+ item = fromtube.remove_items(frompos, fromnode, stack, dir, count)
+ else
+ item = stack:take_item(count)
+ frominv:set_stack(frominvname, spos, stack)
+ if fromdef.on_metadata_inventory_take then
+ fromdef.on_metadata_inventory_take(frompos, frominvname, spos, item, fakePlayer)
+ end
+ end
+ local pos = vector.add(frompos, vector.multiply(dir, 1.4))
+ local start_pos = vector.add(frompos, dir)
+ local item1 = pipeworks.tube_inject_item(pos, start_pos, dir, item)
+ return true-- only fire one item, please
+ end
+ end
+ return false
+end
+
+local function punch_filter(data, filtpos, filtnode)
+ local filtmeta = minetest.get_meta(filtpos)
+ local filtinv = filtmeta:get_inventory()
+ local owner = filtmeta:get_string("owner")
+ local fakePlayer = {
+ get_player_name = delay(owner),
+ is_fake_player = ":pipeworks",
+ } -- TODO: use a mechanism as the wielder one
+ local dir = minetest.facedir_to_right_dir(filtnode.param2)
+ local frompos = vector.subtract(filtpos, dir)
+ local fromnode = minetest.get_node(frompos)
+ if not fromnode then return end
+ local fromdef = minetest.registered_nodes[fromnode.name]
+ if not fromdef then return end
+ local fromtube = fromdef.tube
+ if not (fromtube and fromtube.input_inventory) then return end
+ local filters = {}
+ for _, filterstack in ipairs(filtinv:get_list("main")) do
+ local filtername = filterstack:get_name()
+ local filtercount = filterstack:get_count()
+ if filtername ~= "" then table.insert(filters, {name = filtername, count = filtercount}) end
+ end
+ if #filters == 0 then table.insert(filters, "") end
+ local slotseq_mode = filtmeta:get_int("slotseq_mode")
+ local frommeta = minetest.get_meta(frompos)
+ local frominv = frommeta:get_inventory()
+ if fromtube.before_filter then fromtube.before_filter(frompos) end
+ for _, frominvname in ipairs(type(fromtube.input_inventory) == "table" and fromtube.input_inventory or {fromtube.input_inventory}) do
+ local done = false
+ for _, filterfor in ipairs(filters) do
+ if grabAndFire(data, slotseq_mode, filtmeta, frominv, frominvname, frompos, fromnode, filterfor, fromtube, fromdef, dir, fakePlayer, data.stackwise) then
+ done = true
+ break
+ end
+ end
+ if done then break end
+ end
+ if fromtube.after_filter then fromtube.after_filter(frompos) end
+end
+
+for _, data in ipairs({
+ {
+ name = "filter",
+ wise_desc = "Itemwise",
+ stackwise = false,
+ },
+ {
+ name = "mese_filter",
+ wise_desc = "Stackwise",
+ stackwise = true,
+ },
+}) do
+ minetest.register_node("pipeworks:"..data.name, {
+ description = data.wise_desc.." Filter-Injector",
+ tiles = {
+ "pipeworks_"..data.name.."_top.png",
+ "pipeworks_"..data.name.."_top.png",
+ "pipeworks_"..data.name.."_output.png",
+ "pipeworks_"..data.name.."_input.png",
+ "pipeworks_"..data.name.."_side.png",
+ "pipeworks_"..data.name.."_top.png",
+ },
+ paramtype2 = "facedir",
+ groups = {snappy = 2, choppy = 2, oddly_breakable_by_hand = 2, mesecon = 2},
+ legacy_facedir_simple = true,
+ sounds = default.node_sound_wood_defaults(),
+ on_construct = function(pos)
+ local meta = minetest.get_meta(pos)
+ set_filter_formspec(data, meta)
+ set_filter_infotext(data, meta)
+ local inv = meta:get_inventory()
+ inv:set_size("main", 8*2)
+ end,
+ after_place_node = function (pos, placer)
+ minetest.get_meta(pos):set_string("owner", placer:get_player_name())
+ pipeworks.after_place(pos)
+ end,
+ after_dig_node = pipeworks.after_dig,
+ on_receive_fields = function(pos, formname, fields, sender)
+ if not pipeworks.may_configure(pos, sender) then return end
+ fs_helpers.on_receive_fields(pos, fields)
+ local meta = minetest.get_meta(pos)
+ meta:set_int("slotseq_index", 1)
+ set_filter_formspec(data, meta)
+ set_filter_infotext(data, meta)
+ end,
+ allow_metadata_inventory_put = function(pos, listname, index, stack, player)
+ if not pipeworks.may_configure(pos, player) then return 0 end
+ return stack:get_count()
+ end,
+ allow_metadata_inventory_take = function(pos, listname, index, stack, player)
+ if not pipeworks.may_configure(pos, player) then return 0 end
+ return stack:get_count()
+ end,
+ allow_metadata_inventory_move = function(pos, from_list, from_index, to_list, to_index, count, player)
+ if not pipeworks.may_configure(pos, player) then return 0 end
+ return count
+ end,
+ can_dig = function(pos, player)
+ local meta = minetest.get_meta(pos)
+ local inv = meta:get_inventory()
+ return inv:is_empty("main")
+ end,
+ mesecons = {
+ effector = {
+ action_on = function(pos, node)
+ punch_filter(data, pos, node)
+ end,
+ },
+ },
+ tube = {connect_sides = {right = 1}},
+ on_punch = function (pos, node, puncher)
+ punch_filter(data, pos, node)
+ end,
+ })
+end
+
+minetest.register_craft( {
+ output = "pipeworks:filter 2",
+ recipe = {
+ { "default:steel_ingot", "default:steel_ingot", "homedecor:plastic_sheeting" },
+ { "group:stick", "default:mese_crystal", "homedecor:plastic_sheeting" },
+ { "default:steel_ingot", "default:steel_ingot", "homedecor:plastic_sheeting" }
+ },
+})
+
+minetest.register_craft( {
+ output = "pipeworks:mese_filter 2",
+ recipe = {
+ { "default:steel_ingot", "default:steel_ingot", "homedecor:plastic_sheeting" },
+ { "group:stick", "default:mese", "homedecor:plastic_sheeting" },
+ { "default:steel_ingot", "default:steel_ingot", "homedecor:plastic_sheeting" }
+ },
+})
diff --git a/pipeworks/flowing_logic.lua b/pipeworks/flowing_logic.lua
new file mode 100644
index 0000000..e0a6236
--- /dev/null
+++ b/pipeworks/flowing_logic.lua
@@ -0,0 +1,121 @@
+-- This file provides the actual flow and pathfinding logic that makes water
+-- move through the pipes.
+--
+-- Contributed by mauvebic, 2013-01-03, rewritten a bit by Vanessa Ezekowitz
+--
+
+local finitewater = minetest.setting_getbool("liquid_finite")
+
+pipeworks.check_for_liquids = function(pos)
+ local coords = {
+ {x=pos.x,y=pos.y-1,z=pos.z},
+ {x=pos.x,y=pos.y+1,z=pos.z},
+ {x=pos.x-1,y=pos.y,z=pos.z},
+ {x=pos.x+1,y=pos.y,z=pos.z},
+ {x=pos.x,y=pos.y,z=pos.z-1},
+ {x=pos.x,y=pos.y,z=pos.z+1}, }
+ for i =1,6 do
+ local name = minetest.get_node(coords[i]).name
+ if name and string.find(name,"water") then
+ if finitewater then minetest.remove_node(coords[i]) end
+ return true
+ end
+ end
+ return false
+end
+
+pipeworks.check_for_inflows = function(pos,node)
+ local coords = {
+ {x=pos.x,y=pos.y-1,z=pos.z},
+ {x=pos.x,y=pos.y+1,z=pos.z},
+ {x=pos.x-1,y=pos.y,z=pos.z},
+ {x=pos.x+1,y=pos.y,z=pos.z},
+ {x=pos.x,y=pos.y,z=pos.z-1},
+ {x=pos.x,y=pos.y,z=pos.z+1}, }
+ local newnode = false
+ local source = false
+ for i =1,6 do
+ if newnode then break end
+ local name = minetest.get_node(coords[i]).name
+ if name and (name == "pipeworks:pump_on" and pipeworks.check_for_liquids(coords[i])) or string.find(name,"_loaded") then
+ if string.find(name,"_loaded") then
+ source = minetest.get_meta(coords[i]):get_string("source")
+ if source == minetest.pos_to_string(pos) then break end
+ end
+ newnode = string.gsub(node.name,"empty","loaded")
+ source = {x=coords[i].x,y=coords[i].y,z=coords[i].z}
+ end
+ end
+ if newnode then
+ minetest.add_node(pos,{name=newnode, param2 = node.param2})
+ minetest.get_meta(pos):set_string("source",minetest.pos_to_string(source))
+ end
+end
+
+pipeworks.check_sources = function(pos,node)
+ local sourcepos = minetest.string_to_pos(minetest.get_meta(pos):get_string("source"))
+ if not sourcepos then return end
+ local source = minetest.get_node(sourcepos).name
+ local newnode = false
+ if source and not ((source == "pipeworks:pump_on" and pipeworks.check_for_liquids(sourcepos)) or string.find(source,"_loaded") or source == "ignore" ) then
+ newnode = string.gsub(node.name,"loaded","empty")
+ end
+
+ if newnode then
+ minetest.add_node(pos,{name=newnode, param2 = node.param2})
+ minetest.get_meta(pos):set_string("source","")
+ end
+end
+
+pipeworks.spigot_check = function(pos, node)
+ local belowname = minetest.get_node({x=pos.x,y=pos.y-1,z=pos.z}).name
+ if belowname and (belowname == "air" or belowname == "default:water_flowing" or belowname == "default:water_source") then
+ local spigotname = minetest.get_node(pos).name
+ local fdir=node.param2
+ local check = {
+ {x=pos.x,y=pos.y,z=pos.z+1},
+ {x=pos.x+1,y=pos.y,z=pos.z},
+ {x=pos.x,y=pos.y,z=pos.z-1},
+ {x=pos.x-1,y=pos.y,z=pos.z}
+ }
+ local near_node = minetest.get_node(check[fdir+1])
+ if near_node and string.find(near_node.name, "_loaded") then
+ if spigotname and spigotname == "pipeworks:spigot" then
+ minetest.add_node(pos,{name = "pipeworks:spigot_pouring", param2 = fdir})
+ if finitewater or belowname ~= "default:water_source" then
+ minetest.add_node({x=pos.x,y=pos.y-1,z=pos.z},{name = "default:water_source"})
+ end
+ end
+ else
+ if spigotname == "pipeworks:spigot_pouring" then
+ minetest.add_node({x=pos.x,y=pos.y,z=pos.z},{name = "pipeworks:spigot", param2 = fdir})
+ if belowname == "default:water_source" and not finitewater then
+ minetest.remove_node({x=pos.x,y=pos.y-1,z=pos.z})
+ end
+ end
+ end
+ end
+end
+
+pipeworks.fountainhead_check = function(pos, node)
+ local abovename = minetest.get_node({x=pos.x,y=pos.y+1,z=pos.z}).name
+ if abovename and (abovename == "air" or abovename == "default:water_flowing" or abovename == "default:water_source") then
+ local fountainhead_name = minetest.get_node(pos).name
+ local near_node = minetest.get_node({x=pos.x,y=pos.y-1,z=pos.z})
+ if near_node and string.find(near_node.name, "_loaded") then
+ if fountainhead_name and fountainhead_name == "pipeworks:fountainhead" then
+ minetest.add_node(pos,{name = "pipeworks:fountainhead_pouring"})
+ if finitewater or abovename ~= "default:water_source" then
+ minetest.add_node({x=pos.x,y=pos.y+1,z=pos.z},{name = "default:water_source"})
+ end
+ end
+ else
+ if fountainhead_name == "pipeworks:fountainhead_pouring" then
+ minetest.add_node({x=pos.x,y=pos.y,z=pos.z},{name = "pipeworks:fountainhead"})
+ if abovename == "default:water_source" and not finitewater then
+ minetest.remove_node({x=pos.x,y=pos.y+1,z=pos.z})
+ end
+ end
+ end
+ end
+end
diff --git a/pipeworks/init.lua b/pipeworks/init.lua
new file mode 100644
index 0000000..92ce02c
--- /dev/null
+++ b/pipeworks/init.lua
@@ -0,0 +1,115 @@
+-- Pipeworks mod by Vanessa Ezekowitz - 2013-07-13
+--
+-- This mod supplies various steel pipes and plastic pneumatic tubes
+-- and devices that they can connect to.
+--
+-- License: WTFPL
+--
+
+pipeworks = {}
+
+local DEBUG = false
+
+pipeworks.worldpath = minetest.get_worldpath()
+pipeworks.modpath = minetest.get_modpath("pipeworks")
+
+dofile(pipeworks.modpath.."/default_settings.txt")
+
+-- Read the external config file if it exists.
+if io.open(pipeworks.worldpath.."/pipeworks_settings.txt","r") then
+ dofile(pipeworks.worldpath.."/pipeworks_settings.txt")
+ io.close()
+end
+
+-- Random variables
+
+pipeworks.expect_infinite_stacks = true
+if minetest.get_modpath("unified_inventory") or not minetest.setting_getbool("creative_mode") then
+ pipeworks.expect_infinite_stacks = false
+end
+
+pipeworks.meseadjlist={{x=0,y=0,z=1},{x=0,y=0,z=-1},{x=0,y=1,z=0},{x=0,y=-1,z=0},{x=1,y=0,z=0},{x=-1,y=0,z=0}}
+
+pipeworks.rules_all = {{x=0, y=0, z=1},{x=0, y=0, z=-1},{x=1, y=0, z=0},{x=-1, y=0, z=0},
+ {x=0, y=1, z=1},{x=0, y=1, z=-1},{x=1, y=1, z=0},{x=-1, y=1, z=0},
+ {x=0, y=-1, z=1},{x=0, y=-1, z=-1},{x=1, y=-1, z=0},{x=-1, y=-1, z=0},
+ {x=0, y=1, z=0}, {x=0, y=-1, z=0}}
+
+pipeworks.mesecons_rules={{x=0,y=0,z=1},{x=0,y=0,z=-1},{x=1,y=0,z=0},{x=-1,y=0,z=0},{x=0,y=1,z=0},{x=0,y=-1,z=0}}
+
+pipeworks.liquid_texture = "default_water.png"
+
+-- Helper functions
+
+function pipeworks.fix_image_names(table, replacement)
+ local outtable={}
+ for i in ipairs(table) do
+ outtable[i]=string.gsub(table[i], "_XXXXX", replacement)
+ end
+
+ return outtable
+end
+
+function pipeworks.add_node_box(t, b)
+ if not t or not b then return end
+ for i in ipairs(b)
+ do table.insert(t, b[i])
+ end
+end
+
+function pipeworks.may_configure(pos, player)
+ local name = player:get_player_name()
+ local meta = minetest.get_meta(pos)
+ local owner = meta:get_string("owner")
+
+ if owner ~= "" then -- wielders and filters
+ return owner == name
+ end
+ return not minetest.is_protected(pos, name)
+end
+
+function pipeworks.replace_name(tbl,tr,name)
+ local ntbl={}
+ for key,i in pairs(tbl) do
+ if type(i)=="string" then
+ ntbl[key]=string.gsub(i,tr,name)
+ elseif type(i)=="table" then
+ ntbl[key]=pipeworks.replace_name(i,tr,name)
+ else
+ ntbl[key]=i
+ end
+ end
+ return ntbl
+end
+
+-------------------------------------------
+-- Load the various other parts of the mod
+
+dofile(pipeworks.modpath.."/common.lua")
+dofile(pipeworks.modpath.."/models.lua")
+dofile(pipeworks.modpath.."/autoplace_pipes.lua")
+dofile(pipeworks.modpath.."/autoplace_tubes.lua")
+dofile(pipeworks.modpath.."/luaentity.lua")
+dofile(pipeworks.modpath.."/item_transport.lua")
+dofile(pipeworks.modpath.."/flowing_logic.lua")
+dofile(pipeworks.modpath.."/crafts.lua")
+dofile(pipeworks.modpath.."/tube_registration.lua")
+dofile(pipeworks.modpath.."/routing_tubes.lua")
+dofile(pipeworks.modpath.."/sorting_tubes.lua")
+dofile(pipeworks.modpath.."/vacuum_tubes.lua")
+dofile(pipeworks.modpath.."/signal_tubes.lua")
+dofile(pipeworks.modpath.."/decorative_tubes.lua")
+dofile(pipeworks.modpath.."/filter-injector.lua")
+dofile(pipeworks.modpath.."/trashcan.lua")
+dofile(pipeworks.modpath.."/wielder.lua")
+
+if pipeworks.enable_pipes then dofile(pipeworks.modpath.."/pipes.lua") end
+if pipeworks.enable_teleport_tube then dofile(pipeworks.modpath.."/teleport_tube.lua") end
+if pipeworks.enable_pipe_devices then dofile(pipeworks.modpath.."/devices.lua") end
+if pipeworks.enable_redefines then dofile(pipeworks.modpath.."/compat.lua") end
+if pipeworks.enable_autocrafter then dofile(pipeworks.modpath.."/autocrafter.lua") end
+
+minetest.register_alias("pipeworks:pipe", "pipeworks:pipe_110000_empty")
+
+print("Pipeworks loaded!")
+
diff --git a/pipeworks/item_transport.lua b/pipeworks/item_transport.lua
new file mode 100644
index 0000000..e38125d
--- /dev/null
+++ b/pipeworks/item_transport.lua
@@ -0,0 +1,286 @@
+function pipeworks.tube_item(pos, item)
+ error("obsolete pipeworks.tube_item() called; change caller to use pipeworks.tube_inject_item() instead")
+end
+
+function pipeworks.tube_inject_item(pos, start_pos, velocity, item)
+ -- Take item in any format
+ local stack = ItemStack(item)
+ local obj = luaentity.add_entity(pos, "pipeworks:tubed_item")
+ obj:set_item(stack:to_string())
+ obj.start_pos = vector.new(start_pos)
+ obj:setvelocity(velocity)
+ --obj:set_color("red") -- todo: this is test-only code
+ return obj
+end
+
+-- adding two tube functions
+-- can_remove(pos,node,stack,dir) returns the maximum number of items of that stack that can be removed
+-- remove_items(pos,node,stack,dir,count) removes count items and returns them
+-- both optional w/ sensible defaults and fallback to normal allow_* function
+-- XXX: possibly change insert_object to insert_item
+
+local adjlist={{x=0,y=0,z=1},{x=0,y=0,z=-1},{x=0,y=1,z=0},{x=0,y=-1,z=0},{x=1,y=0,z=0},{x=-1,y=0,z=0}}
+
+function pipeworks.notvel(tbl, vel)
+ local tbl2={}
+ for _,val in ipairs(tbl) do
+ if val.x ~= -vel.x or val.y ~= -vel.y or val.z ~= -vel.z then table.insert(tbl2, val) end
+ end
+ return tbl2
+end
+
+local function go_next(pos, velocity, stack)
+ local next_positions = {}
+ local max_priority = 0
+ local cnode = minetest.get_node(pos)
+ local cmeta = minetest.get_meta(pos)
+ local can_go
+ local speed = math.abs(velocity.x + velocity.y + velocity.z)
+ if speed == 0 then
+ speed = 1
+ end
+ local vel = {x = velocity.x/speed, y = velocity.y/speed, z = velocity.z/speed,speed=speed}
+ if speed >= 4.1 then
+ speed = 4
+ elseif speed >= 1.1 then
+ speed = speed - 0.1
+ else
+ speed = 1
+ end
+ vel.speed = speed
+ if minetest.registered_nodes[cnode.name] and minetest.registered_nodes[cnode.name].tube and minetest.registered_nodes[cnode.name].tube.can_go then
+ can_go = minetest.registered_nodes[cnode.name].tube.can_go(pos, cnode, vel, stack)
+ else
+ can_go = pipeworks.notvel(adjlist, vel)
+ end
+ for _, vect in ipairs(can_go) do
+ local npos = vector.add(pos, vect)
+ minetest.load_position(npos)
+ local node = minetest.get_node(npos)
+ local reg_node = minetest.registered_nodes[node.name]
+ if reg_node then
+ local tube_def = reg_node.tube
+ local tubedevice = minetest.get_item_group(node.name, "tubedevice")
+ local tube_priority = (tube_def and tube_def.priority) or 100
+ if tubedevice > 0 and tube_priority >= max_priority then
+ if not tube_def or not tube_def.can_insert or
+ tube_def.can_insert(npos, node, stack, vect) then
+ if tube_priority > max_priority then
+ max_priority = tube_priority
+ next_positions = {}
+ end
+ next_positions[#next_positions + 1] = {pos = npos, vect = vect}
+ end
+ end
+ end
+ end
+
+ if not next_positions[1] then
+ return false, nil
+ end
+
+ local n = (cmeta:get_int("tubedir") % (#next_positions)) + 1
+ if pipeworks.enable_cyclic_mode then
+ cmeta:set_int("tubedir", n)
+ end
+ local new_velocity = vector.multiply(next_positions[n].vect, vel.speed)
+ return true, new_velocity
+end
+
+minetest.register_entity("pipeworks:tubed_item", {
+ initial_properties = {
+ hp_max = 1,
+ physical = false,
+ collisionbox = {0.1, 0.1, 0.1, 0.1, 0.1, 0.1},
+ visual = "wielditem",
+ visual_size = {x = 0.15, y = 0.15},
+ textures = {""},
+ spritediv = {x = 1, y = 1},
+ initial_sprite_basepos = {x = 0, y = 0},
+ is_visible = false,
+ },
+
+ physical_state = false,
+
+ from_data = function(self, itemstring)
+ local stack = ItemStack(itemstring)
+ local itemtable = stack:to_table()
+ local itemname = nil
+ if itemtable then
+ itemname = stack:to_table().name
+ end
+ local item_texture = nil
+ local item_type = ""
+ if minetest.registered_items[itemname] then
+ item_texture = minetest.registered_items[itemname].inventory_image
+ item_type = minetest.registered_items[itemname].type
+ end
+ self.object:set_properties({
+ is_visible = true,
+ textures = {stack:get_name()}
+ })
+ local def = stack:get_definition()
+ self.object:setyaw((def and def.type == "node") and 0 or math.pi * 0.25)
+ end,
+
+ get_staticdata = luaentity.get_staticdata,
+ on_activate = function(self, staticdata) -- Legacy code, should be replaced later by luaentity.on_activate
+ if staticdata == "" or staticdata == nil then
+ return
+ end
+ if staticdata == "toremove" then
+ self.object:remove()
+ return
+ end
+ local item = minetest.deserialize(staticdata)
+ pipeworks.tube_inject_item(self.object:getpos(), item.start_pos, item.velocity, item.itemstring)
+ self.object:remove()
+ end,
+})
+
+minetest.register_entity("pipeworks:color_entity", {
+ initial_properties = {
+ hp_max = 1,
+ physical = false,
+ collisionbox = {0.1, 0.1, 0.1, 0.1, 0.1, 0.1},
+ visual = "cube",
+ visual_size = {x = 3.5, y = 3.5, z = 3.5}, -- todo: find correct size
+ textures = {""},
+ is_visible = false,
+ },
+
+ physical_state = false,
+
+ from_data = function(self, color)
+ local t = "pipeworks_color_"..color..".png"
+ local prop = {
+ is_visible = true,
+ visual = "cube",
+ textures = {t, t, t, t, t, t} -- todo: textures
+ }
+ self.object:set_properties(prop)
+ end,
+
+ get_staticdata = luaentity.get_staticdata,
+ on_activate = luaentity.on_activate,
+})
+
+luaentity.register_entity("pipeworks:tubed_item", {
+ itemstring = '',
+ item_entity = nil,
+ color_entity = nil,
+ color = nil,
+ start_pos = nil,
+
+ set_item = function(self, item)
+ local itemstring = ItemStack(item):to_string() -- Accept any input format
+ if self.itemstring == itemstring then
+ return
+ end
+ if self.item_entity then
+ self:remove_attached_entity(self.item_entity)
+ end
+ self.itemstring = itemstring
+ self.item_entity = self:add_attached_entity("pipeworks:tubed_item", itemstring)
+ end,
+
+ set_color = function(self, color)
+ if self.color == color then
+ return
+ end
+ self.color = color
+ if self.color_entity then
+ self:remove_attached_entity(self.color_entity)
+ end
+ if color then
+ self.color_entity = self:add_attached_entity("pipeworks:color_entity", color)
+ else
+ self.color_entity = nil
+ end
+ end,
+
+ on_step = function(self, dtime)
+ if self.start_pos == nil then
+ local pos = self:getpos()
+ self.start_pos = vector.round(pos)
+ self:setpos(pos)
+ end
+
+ local pos = self:getpos()
+ local stack = ItemStack(self.itemstring)
+ local drop_pos
+
+ local velocity = self:getvelocity()
+
+ local moved = false
+ local speed = math.abs(velocity.x + velocity.y + velocity.z)
+ if speed == 0 then
+ speed = 1
+ moved = true
+ end
+ local vel = {x = velocity.x / speed, y = velocity.y / speed, z = velocity.z / speed, speed = speed}
+
+ if vector.distance(pos, self.start_pos) >= 1 then
+ self.start_pos = vector.add(self.start_pos, vel)
+ moved = true
+ end
+
+ minetest.load_position(self.start_pos)
+ local node = minetest.get_node(self.start_pos)
+ if moved and minetest.get_item_group(node.name, "tubedevice_receiver") == 1 then
+ local leftover
+ if minetest.registered_nodes[node.name].tube and minetest.registered_nodes[node.name].tube.insert_object then
+ leftover = minetest.registered_nodes[node.name].tube.insert_object(self.start_pos, node, stack, vel)
+ else
+ leftover = stack
+ end
+ if leftover:is_empty() then
+ self:remove()
+ return
+ end
+ velocity = vector.multiply(velocity, -1)
+ self:setvelocity(velocity)
+ self:set_item(leftover:to_string())
+ return
+ end
+
+ if moved then
+ local found_next, new_velocity = go_next(self.start_pos, velocity, stack) -- todo: color
+ if not found_next then
+ drop_pos = minetest.find_node_near(vector.add(self.start_pos, velocity), 1, "air")
+ if drop_pos then
+ minetest.item_drop(stack, nil, drop_pos)
+ self:remove()
+ return
+ end
+ end
+
+ if new_velocity and not vector.equals(velocity, new_velocity) then
+ self:setpos(self.start_pos)
+ self:setvelocity(new_velocity)
+ end
+ end
+ end
+})
+
+if minetest.get_modpath("mesecons_mvps") then
+ mesecon.register_mvps_unmov("pipeworks:tubed_item")
+ mesecon.register_mvps_unmov("pipeworks:color_entity")
+ mesecon.register_on_mvps_move(function(moved_nodes)
+ local moved = {}
+ for _, n in ipairs(moved_nodes) do
+ moved[minetest.hash_node_position(n.oldpos)] = vector.subtract(n.pos, n.oldpos)
+ end
+ for id, entity in pairs(luaentity.entities) do
+ if entity.name == "pipeworks:tubed_item" then
+ local pos = entity:getpos()
+ local rpos = vector.round(pos)
+ local dir = moved[minetest.hash_node_position(rpos)]
+ if dir then
+ entity:setpos(vector.add(pos, dir))
+ entity.start_pos = vector.add(entity.start_pos, dir)
+ end
+ end
+ end
+ end)
+end
diff --git a/pipeworks/legacy.lua b/pipeworks/legacy.lua
new file mode 100644
index 0000000..b36cded
--- /dev/null
+++ b/pipeworks/legacy.lua
@@ -0,0 +1,59 @@
+
+if not minetest.get_modpath("auto_tree_tap") and
+ minetest.get_modpath("technic") then
+
+ minetest.register_abm({
+ nodenames = { "auto_tree_tap:off", "auto_tree_tap:on" },
+ chance = 1,
+ interval = 1,
+ action = function(pos, node, active_object_count, active_object_count_wider)
+ local fdir = node.param2
+ local meta = minetest.get_meta(pos)
+ local inv = meta:get_inventory()
+ inv:set_size("pick", 1)
+ inv:set_size("ghost_pick", 1)
+ inv:set_size("main", 100)
+ minetest.set_node(pos, {name = "pipeworks:nodebreaker_off", param2 = fdir})
+ minetest.registered_nodes["pipeworks:nodebreaker_off"].on_punch(pos, node)
+ inv:set_stack("pick", 1, ItemStack("technic:treetap"))
+ end
+ })
+
+ minetest.register_node(":auto_tree_tap:off", {
+ description = "Auto-Tap",
+ tiles = {"pipeworks_nodebreaker_top_off.png","pipeworks_nodebreaker_bottom_off.png","pipeworks_nodebreaker_side2_off.png","pipeworks_nodebreaker_side1_off.png",
+ "pipeworks_nodebreaker_back.png","pipeworks_nodebreaker_front_off.png"},
+ is_ground_content = true,
+ paramtype2 = "facedir",
+ groups = {snappy=2,choppy=2,oddly_breakable_by_hand=2, mesecon = 2,tubedevice=1, not_in_creative_inventory=1 },
+ sounds = default.node_sound_stone_defaults(),
+ tube = {connect_sides={back=1}},
+ on_construct = function(pos)
+ local meta = minetest.get_meta(pos)
+ local inv = meta:get_inventory()
+ inv:set_size("pick", 1)
+ inv:set_stack("pick", 1, ItemStack("default:pick_mese"))
+ end,
+ after_place_node = function (pos, placer)
+ pipeworks.scan_for_tube_objects(pos, placer)
+ local placer_pos = placer:getpos()
+
+ --correct for the player's height
+ if placer:is_player() then placer_pos.y = placer_pos.y + 1.5 end
+
+ --correct for 6d facedir
+ if placer_pos then
+ local dir = {
+ x = pos.x - placer_pos.x,
+ y = pos.y - placer_pos.y,
+ z = pos.z - placer_pos.z
+ }
+ local node = minetest.get_node(pos)
+ node.param2 = minetest.dir_to_facedir(dir, true)
+ minetest.set_node(pos, node)
+ minetest.log("action", "real (6d) facedir: " .. node.param2)
+ end
+ end,
+ after_dig_node = pipeworks.scan_for_tube_objects,
+ })
+end
diff --git a/pipeworks/luaentity.lua b/pipeworks/luaentity.lua
new file mode 100644
index 0000000..665e055
--- /dev/null
+++ b/pipeworks/luaentity.lua
@@ -0,0 +1,351 @@
+local max_entity_id = 1000000000000 -- If you need more, there's a problem with your code
+
+luaentity = {}
+
+luaentity.registered_entities = {}
+
+local filename = minetest.get_worldpath().."/luaentities"
+local function read_file()
+ local f = io.open(filename, "r")
+ if f == nil then return {} end
+ local t = f:read("*all")
+ f:close()
+ if t == "" or t == nil then return {} end
+ return minetest.deserialize(t) or {}
+end
+
+local function write_file(tbl)
+ local f = io.open(filename, "w")
+ f:write(minetest.serialize(tbl))
+ f:close()
+end
+
+local function read_entities()
+ local t = read_file()
+ for _, entity in pairs(t) do
+ setmetatable(entity, luaentity.registered_entities[entity.name])
+ end
+ return t
+end
+
+local function write_entities()
+ for _, entity in pairs(luaentity.entities) do
+ setmetatable(entity, nil)
+ for _, attached in pairs(entity._attached_entities) do
+ if attached.entity then
+ attached.entity:remove()
+ attached.entity = nil
+ end
+ end
+ entity._attached_entities_master = nil
+ end
+ write_file(luaentity.entities)
+end
+
+minetest.register_on_shutdown(write_entities)
+luaentity.entities_index = 0
+
+local function get_blockpos(pos)
+ return {x = math.floor(pos.x / 16),
+ y = math.floor(pos.y / 16),
+ z = math.floor(pos.z / 16)}
+end
+
+local active_blocks = {} -- These only contain active blocks near players (i.e., not forceloaded ones)
+local handle_active_blocks_step = 2
+local handle_active_blocks_timer = 0
+minetest.register_globalstep(function(dtime)
+ handle_active_blocks_timer = handle_active_blocks_timer + dtime
+ if handle_active_blocks_timer >= handle_active_blocks_step then
+ handle_active_blocks_timer = handle_active_blocks_timer - handle_active_blocks_step
+ local active_block_range = tonumber(minetest.setting_get("active_block_range")) or 2
+ local new_active_blocks = {}
+ for _, player in ipairs(minetest.get_connected_players()) do
+ local blockpos = get_blockpos(player:getpos())
+ local minp = vector.subtract(blockpos, active_block_range)
+ local maxp = vector.add(blockpos, active_block_range)
+
+ for x = minp.x, maxp.x do
+ for y = minp.y, maxp.y do
+ for z = minp.z, maxp.z do
+ local pos = {x = x, y = y, z = z}
+ new_active_blocks[minetest.hash_node_position(pos)] = pos
+ end
+ end
+ end
+ end
+ active_blocks = new_active_blocks
+ -- todo: callbacks on block load/unload
+ end
+end)
+
+local function is_active(pos)
+ return active_blocks[minetest.hash_node_position(get_blockpos(pos))] ~= nil
+end
+
+local entitydef_default = {
+ _attach = function(self, attached, attach_to)
+ local attached_def = self._attached_entities[attached]
+ local attach_to_def = self._attached_entities[attach_to]
+ attached_def.entity:set_attach(
+ attach_to_def.entity, "",
+ vector.subtract(attached_def.offset, attach_to_def.offset), -- todo: Does not work because is object space
+ vector.new(0, 0, 0)
+ )
+ end,
+ _set_master = function(self, index)
+ self._attached_entities_master = index
+ if not index then
+ return
+ end
+ local def = self._attached_entities[index]
+ if not def.entity then
+ return
+ end
+ def.entity:setpos(vector.add(self._pos, def.offset))
+ def.entity:setvelocity(self._velocity)
+ def.entity:setacceleration(self._acceleration)
+ end,
+ _attach_all = function(self)
+ local master = self._attached_entities_master
+ if not master then
+ return
+ end
+ for id, entity in pairs(self._attached_entities) do
+ if id ~= master and entity.entity then
+ self:_attach(id, master)
+ end
+ end
+ end,
+ _detach_all = function(self)
+ local master = self._attached_entities_master
+ for id, entity in pairs(self._attached_entities) do
+ if id ~= master and entity.entity then
+ entity.entity:set_detach()
+ end
+ end
+ end,
+ _add_attached = function(self, index)
+ local entity = self._attached_entities[index]
+ if entity.entity then
+ return
+ end
+ local entity_pos = vector.add(self._pos, entity.offset)
+ if not is_active(entity_pos) then
+ return
+ end
+ local ent = minetest.add_entity(entity_pos, entity.name):get_luaentity()
+ ent:from_data(entity.data)
+ ent.parent_id = self._id
+ ent.attached_id = index
+ entity.entity = ent.object
+ local master = self._attached_entities_master
+ if master then
+ self:_attach(index, master)
+ else
+ self:_set_master(index)
+ end
+ end,
+ _remove_attached = function(self, index)
+ local master = self._attached_entities_master
+ local entity = self._attached_entities[index]
+ local ent = entity and entity.entity
+ if entity then entity.entity = nil end
+ if index == master then
+ self:_detach_all()
+ local newmaster
+ for id, attached in pairs(self._attached_entities) do
+ if id ~= master and attached.entity then
+ newmaster = id
+ break
+ end
+ end
+ self:_set_master(newmaster)
+ self:_attach_all()
+ elseif master and ent then
+ ent:set_detach()
+ end
+ if ent then
+ ent:remove()
+ end
+ end,
+ _add_loaded = function(self)
+ for id, _ in pairs(self._attached_entities) do
+ self:_add_attached(id)
+ end
+ end,
+ getid = function(self)
+ return self._id
+ end,
+ getpos = function(self)
+ return vector.new(self._pos)
+ end,
+ setpos = function(self, pos)
+ self._pos = vector.new(pos)
+ --for _, entity in pairs(self._attached_entities) do
+ -- if entity.entity then
+ -- entity.entity:setpos(vector.add(self._pos, entity.offset))
+ -- end
+ --end
+ local master = self._attached_entities_master
+ if master then
+ local master_def = self._attached_entities[master]
+ master_def.entity:setpos(vector.add(self._pos, master_def.offset))
+ end
+ end,
+ getvelocity = function(self)
+ return vector.new(self._velocity)
+ end,
+ setvelocity = function(self, velocity)
+ self._velocity = vector.new(velocity)
+ local master = self._attached_entities_master
+ if master then
+ self._attached_entities[master].entity:setvelocity(self._velocity)
+ end
+ end,
+ getacceleration = function(self)
+ return vector.new(self._acceleration)
+ end,
+ setacceleration = function(self, acceleration)
+ self._acceleration = vector.new(acceleration)
+ local master = self._attached_entities_master
+ if master then
+ self._attached_entities[master].entity:setacceleration(self._acceleration)
+ end
+ end,
+ remove = function(self)
+ self:_detach_all()
+ for _, entity in pairs(self._attached_entities) do
+ if entity.entity then
+ entity.entity:remove()
+ end
+ end
+ luaentity.entities[self._id] = nil
+ end,
+ add_attached_entity = function(self, name, data, offset)
+ local index = #self._attached_entities + 1
+ self._attached_entities[index] = {
+ name = name,
+ data = data,
+ offset = vector.new(offset),
+ }
+ self:_add_attached(index)
+ return index
+ end,
+ remove_attached_entity = function(self, index)
+ self:_remove_attached(index)
+ self._attached_entities[index] = nil
+ end,
+}
+
+function luaentity.register_entity(name, prototype)
+ -- name = check_modname_prefix(name)
+ prototype.name = name
+ setmetatable(prototype, {__index = entitydef_default})
+ prototype.__index = prototype -- Make it possible to use it as metatable
+ luaentity.registered_entities[name] = prototype
+end
+
+-- function luaentity.get_entity_definition(entity)
+-- return luaentity.registered_entities[entity.name]
+-- end
+
+function luaentity.add_entity(pos, name)
+ if not luaentity.entities then
+ minetest.after(0, luaentity.add_entity, vector.new(pos), name)
+ return
+ end
+ local index = luaentity.entities_index
+ while luaentity.entities[index] do
+ index = index + 1
+ if index >= max_entity_id then
+ index = 0
+ end
+ end
+ luaentity.entities_index = index
+
+ local entity = {
+ name = name,
+ _id = index,
+ _pos = vector.new(pos),
+ _velocity = {x = 0, y = 0, z = 0},
+ _acceleration = {x = 0, y = 0, z = 0},
+ _attached_entities = {},
+ }
+
+ local prototype = luaentity.registered_entities[name]
+ setmetatable(entity, prototype) -- Default to prototype for other methods
+ luaentity.entities[index] = entity
+
+ if entity.on_activate then
+ entity:on_activate()
+ end
+ return entity
+end
+
+-- todo: check if remove in get_staticdata works
+function luaentity.get_staticdata(self)
+ local parent = luaentity.entities[self.parent_id]
+ if parent and parent._remove_attached then
+ parent:_remove_attached(self.attached_id)
+ end
+ return "toremove"
+end
+
+function luaentity.on_activate(self, staticdata)
+ if staticdata == "toremove" then
+ self.object:remove()
+ end
+end
+
+function luaentity.get_objects_inside_radius(pos, radius)
+ local objects = {}
+ local index = 1
+ for id, entity in pairs(luaentity.entities) do
+ if vector.distance(pos, entity:getpos()) <= radius then
+ objects[index] = entity
+ index = index + 1
+ end
+ end
+end
+
+minetest.register_globalstep(function(dtime)
+ if not luaentity.entities then
+ luaentity.entities = read_entities()
+ end
+ for id, entity in pairs(luaentity.entities) do
+ local master = entity._attached_entities_master
+ local master_def = master and entity._attached_entities[master]
+ local master_entity = master_def and master_def.entity
+ local master_entity_pos = master_entity and master_entity:getpos()
+ if master_entity_pos then
+ entity._pos = vector.subtract(master_entity_pos, master_def.offset)
+ entity._velocity = master_entity:getvelocity()
+ entity._acceleration = master_entity:getacceleration()
+ else
+ entity._pos = vector.add(vector.add(
+ entity._pos,
+ vector.multiply(entity._velocity, dtime)),
+ vector.multiply(entity._acceleration, 0.5 * dtime * dtime))
+ entity._velocity = vector.add(
+ entity._velocity,
+ vector.multiply(entity._acceleration, dtime))
+ end
+ if master and not master_entity_pos then -- The entity has somehow been cleared
+ if pipeworks.delete_item_on_clearobject then
+ entity:remove()
+ else
+ entity:_remove_attached(master)
+ entity:_add_loaded()
+ if entity.on_step then
+ entity:on_step(dtime)
+ end
+ end
+ else
+ entity:_add_loaded()
+ if entity.on_step then
+ entity:on_step(dtime)
+ end
+ end
+ end
+end)
diff --git a/pipeworks/models.lua b/pipeworks/models.lua
new file mode 100644
index 0000000..3be773c
--- /dev/null
+++ b/pipeworks/models.lua
@@ -0,0 +1,49 @@
+-----------------------------------
+-- The various pipe select boxes
+
+pipeworks.pipe_selectboxes = {
+ { -32/64, -8/64, -8/64, 8/64, 8/64, 8/64 },
+ { -8/64 , -8/64, -8/64, 32/64, 8/64, 8/64 },
+ { -8/64 , -32/64, -8/64, 8/64, 8/64, 8/64 },
+ { -8/64 , -8/64, -8/64, 8/64, 32/64, 8/64 },
+ { -8/64 , -8/64, -32/64, 8/64, 8/64, 8/64 },
+ { -8/64 , -8/64, -8/64, 8/64, 8/64, 32/64 }
+}
+
+-- Tube models
+
+pipeworks.tube_leftstub = {
+ { -32/64, -9/64, -9/64, 9/64, 9/64, 9/64 }, -- tube segment against -X face
+}
+
+pipeworks.tube_rightstub = {
+ { -9/64, -9/64, -9/64, 32/64, 9/64, 9/64 }, -- tube segment against +X face
+}
+
+pipeworks.tube_bottomstub = {
+ { -9/64, -32/64, -9/64, 9/64, 9/64, 9/64 }, -- tube segment against -Y face
+}
+
+pipeworks.tube_topstub = {
+ { -9/64, -9/64, -9/64, 9/64, 32/64, 9/64 }, -- tube segment against +Y face
+}
+
+pipeworks.tube_frontstub = {
+ { -9/64, -9/64, -32/64, 9/64, 9/64, 9/64 }, -- tube segment against -Z face
+}
+
+pipeworks.tube_backstub = {
+ { -9/64, -9/64, -9/64, 9/64, 9/64, 32/64 }, -- tube segment against -Z face
+}
+
+pipeworks.tube_boxes = {pipeworks.tube_leftstub, pipeworks.tube_rightstub, pipeworks.tube_bottomstub, pipeworks.tube_topstub, pipeworks.tube_frontstub, pipeworks.tube_backstub}
+
+pipeworks.tube_selectboxes = {
+ { -32/64, -10/64, -10/64, 10/64, 10/64, 10/64 },
+ { -10/64 , -10/64, -10/64, 32/64, 10/64, 10/64 },
+ { -10/64 , -32/64, -10/64, 10/64, 10/64, 10/64 },
+ { -10/64 , -10/64, -10/64, 10/64, 32/64, 10/64 },
+ { -10/64 , -10/64, -32/64, 10/64, 10/64, 10/64 },
+ { -10/64 , -10/64, -10/64, 10/64, 10/64, 32/64 }
+}
+
diff --git a/pipeworks/models/pipeworks_entry_panel.obj b/pipeworks/models/pipeworks_entry_panel.obj
new file mode 100644
index 0000000..27577d7
--- /dev/null
+++ b/pipeworks/models/pipeworks_entry_panel.obj
@@ -0,0 +1,390 @@
+# Blender v2.69 (sub 0) OBJ File: 'pipe-entry-panel.blend'
+# www.blender.org
+o Cube.001
+v 0.030483 -0.153248 -0.468750
+v 0.030483 -0.153248 -0.500000
+v -0.030483 -0.153248 -0.468750
+v -0.030483 -0.153248 -0.500000
+v -0.086808 -0.129917 -0.468750
+v -0.086808 -0.129917 -0.500000
+v -0.129917 -0.086808 -0.468750
+v -0.129917 -0.086808 -0.500000
+v -0.153248 -0.030483 -0.468750
+v -0.153248 -0.030483 -0.500000
+v -0.153248 0.030483 -0.468750
+v -0.153248 0.030483 -0.500000
+v -0.129917 0.086808 -0.468750
+v -0.129917 0.086808 -0.500000
+v -0.086808 0.129917 -0.468750
+v -0.086808 0.129917 -0.500000
+v -0.030483 0.153248 -0.468750
+v -0.030483 0.153247 -0.500000
+v 0.030483 0.153248 -0.468750
+v 0.030483 0.153248 -0.500000
+v 0.086808 0.129917 -0.468750
+v 0.086808 0.129917 -0.500000
+v 0.129917 0.086808 -0.468750
+v 0.129917 0.086808 -0.500000
+v 0.153248 0.030483 -0.468750
+v 0.153248 0.030483 -0.500000
+v 0.153248 -0.030483 -0.468750
+v 0.153248 -0.030483 -0.500000
+v 0.129917 -0.086808 -0.468750
+v 0.129917 -0.086808 -0.500000
+v 0.086808 -0.129917 -0.468750
+v 0.086808 -0.129917 -0.500000
+v 0.024386 -0.122598 -0.468750
+v -0.024386 -0.122598 -0.468750
+v -0.069446 -0.103934 -0.468750
+v -0.103934 -0.069446 -0.468750
+v -0.122598 -0.024386 -0.468750
+v -0.122598 0.024386 -0.468750
+v -0.103934 0.069446 -0.468750
+v -0.069446 0.103934 -0.468750
+v -0.024386 0.122598 -0.468750
+v 0.024386 0.122598 -0.468750
+v 0.069446 0.103934 -0.468750
+v 0.103934 0.069446 -0.468750
+v 0.122598 0.024386 -0.468750
+v 0.122598 -0.024387 -0.468750
+v 0.103934 -0.069447 -0.468750
+v 0.069446 -0.103934 -0.468750
+v 0.000000 -0.000000 -0.468750
+v 0.000000 -0.000000 -0.500000
+v -0.103934 -0.069446 0.468750
+v -0.069447 -0.103933 0.468750
+v -0.024387 -0.122598 0.468750
+v 0.024386 -0.122598 0.468750
+v 0.086808 -0.129917 0.500000
+v 0.086808 -0.129917 0.468750
+v 0.129917 -0.086808 0.500000
+v 0.129917 -0.086808 0.468750
+v 0.153247 -0.030483 0.500000
+v 0.153247 -0.030483 0.468750
+v 0.153247 0.030483 0.500000
+v 0.153247 0.030483 0.468750
+v 0.129917 0.086808 0.500000
+v 0.129917 0.086808 0.468750
+v 0.086808 0.129917 0.500000
+v 0.086808 0.129917 0.468750
+v 0.030483 0.153248 0.500000
+v 0.030483 0.153248 0.468750
+v -0.030483 0.153248 0.500000
+v -0.030483 0.153248 0.468750
+v -0.086808 0.129917 0.500000
+v -0.086808 0.129917 0.468750
+v -0.129917 0.086808 0.500000
+v -0.129917 0.086808 0.468750
+v -0.153248 0.030483 0.500000
+v -0.153248 0.030483 0.468750
+v -0.153248 -0.030483 0.500000
+v -0.153248 -0.030483 0.468750
+v -0.129917 -0.086808 0.500000
+v -0.129917 -0.086808 0.468750
+v -0.086808 -0.129917 0.500000
+v -0.086808 -0.129917 0.468750
+v -0.030483 -0.153247 0.500000
+v -0.030483 -0.153247 0.468750
+v 0.030483 -0.153247 0.500000
+v 0.030483 -0.153247 0.468750
+v -0.122598 -0.024386 0.468750
+v -0.122598 0.024387 0.468750
+v -0.103934 0.069447 0.468750
+v -0.069447 0.103934 0.468750
+v -0.024387 0.122598 0.468750
+v 0.024386 0.122598 0.468750
+v 0.069446 0.103934 0.468750
+v 0.103933 0.069447 0.468750
+v 0.122598 0.024387 0.468750
+v 0.122598 -0.024386 0.468750
+v 0.103933 -0.069446 0.468750
+v 0.069446 -0.103933 0.468750
+v -0.000000 0.000000 0.468750
+v -0.000000 0.000000 0.500000
+v 0.500000 -0.500000 0.062500
+v -0.500000 -0.500000 0.062500
+v -0.500000 -0.500000 -0.062500
+v 0.500000 -0.500000 -0.062500
+v 0.500000 0.500000 0.062500
+v -0.500000 0.500000 0.062500
+v -0.500000 0.500000 -0.062500
+v 0.500000 0.500000 -0.062500
+vt 0.871212 0.265152
+vt 0.840909 0.265152
+vt 0.840909 0.295455
+vt 0.871212 0.295455
+vt 0.810606 0.265152
+vt 0.810606 0.295455
+vt 0.780303 0.265152
+vt 0.780303 0.295455
+vt 0.750000 0.265152
+vt 0.750000 0.295455
+vt 0.719697 0.265152
+vt 0.719697 0.295455
+vt 0.689394 0.265152
+vt 0.689394 0.295455
+vt 0.659091 0.265152
+vt 0.659091 0.295455
+vt 0.628788 0.265152
+vt 0.628788 0.295455
+vt 0.598485 0.265152
+vt 0.598485 0.295455
+vt 0.568182 0.265152
+vt 0.568182 0.295455
+vt 0.537879 0.265152
+vt 0.537879 0.295455
+vt 0.507576 0.265152
+vt 0.507576 0.295455
+vt 0.992424 0.265152
+vt 0.962121 0.265152
+vt 0.962121 0.295455
+vt 0.992424 0.295455
+vt 0.931818 0.265152
+vt 0.931818 0.295455
+vt 0.901515 0.265152
+vt 0.901515 0.295455
+vt 0.613449 0.318703
+vt 0.597693 0.397916
+vt 0.581936 0.318703
+vt 0.765436 0.318703
+vt 0.781192 0.397916
+vt 0.796949 0.318703
+vt 0.826063 0.330762
+vt 0.848346 0.353045
+vt 0.860405 0.382159
+vt 0.860405 0.413672
+vt 0.848346 0.442786
+vt 0.826063 0.465069
+vt 0.796949 0.477128
+vt 0.765436 0.477128
+vt 0.736322 0.465069
+vt 0.714039 0.442786
+vt 0.701980 0.413672
+vt 0.701980 0.382159
+vt 0.714039 0.353045
+vt 0.736322 0.330762
+vt 0.552823 0.330762
+vt 0.530540 0.353045
+vt 0.518480 0.382159
+vt 0.518480 0.413672
+vt 0.530540 0.442786
+vt 0.552822 0.465069
+vt 0.581936 0.477128
+vt 0.613449 0.477128
+vt 0.642563 0.465069
+vt 0.664846 0.442786
+vt 0.676906 0.413672
+vt 0.676906 0.382159
+vt 0.664846 0.353045
+vt 0.642563 0.330762
+vt 0.598485 0.250000
+vt 0.598485 0.007576
+vt 0.628788 0.007576
+vt 0.628788 0.250000
+vt 0.552823 0.330759
+vt 0.581937 0.318699
+vt 0.597694 0.397912
+vt 0.530540 0.353042
+vt 0.518481 0.382156
+vt 0.518481 0.413668
+vt 0.530540 0.442782
+vt 0.552823 0.465065
+vt 0.581937 0.477125
+vt 0.613450 0.477125
+vt 0.642564 0.465065
+vt 0.664847 0.442782
+vt 0.676906 0.413668
+vt 0.676906 0.382156
+vt 0.664847 0.353042
+vt 0.642564 0.330759
+vt 0.613450 0.318699
+vt 0.736320 0.330759
+vt 0.765434 0.318699
+vt 0.781190 0.397912
+vt 0.714037 0.353041
+vt 0.701978 0.382156
+vt 0.701978 0.413668
+vt 0.714037 0.442782
+vt 0.736320 0.465065
+vt 0.765434 0.477125
+vt 0.796947 0.477125
+vt 0.826061 0.465065
+vt 0.848344 0.442782
+vt 0.860403 0.413668
+vt 0.860403 0.382156
+vt 0.848344 0.353041
+vt 0.826061 0.330759
+vt 0.796947 0.318699
+vt 0.931818 0.250000
+vt 0.931818 0.007576
+vt 0.962121 0.007576
+vt 0.962121 0.250000
+vt 0.871212 0.250000
+vt 0.871212 0.007576
+vt 0.901515 0.007576
+vt 0.901515 0.250000
+vt 0.780303 0.250000
+vt 0.780303 0.007576
+vt 0.810606 0.007576
+vt 0.810606 0.250000
+vt 0.840909 0.250000
+vt 0.840909 0.007576
+vt 0.750000 0.250000
+vt 0.750000 0.007576
+vt 0.719697 0.250000
+vt 0.719697 0.007576
+vt 0.689394 0.250000
+vt 0.689394 0.007576
+vt 0.659091 0.250000
+vt 0.659091 0.007576
+vt 0.568182 0.250000
+vt 0.568182 0.007576
+vt 0.537879 0.250000
+vt 0.537879 0.007576
+vt 0.507576 0.250000
+vt 0.507576 0.007576
+vt 0.992424 0.007576
+vt 0.992424 0.250000
+vt 0.507576 0.507576
+vt 0.992424 0.507576
+vt 0.992424 0.992424
+vt 0.507576 0.992424
+vt 0.068182 0.492424
+vt 0.007576 0.492424
+vt 0.007576 0.007576
+vt 0.068182 0.007576
+vt 0.492424 0.992424
+vt 0.007576 0.992424
+vt 0.007576 0.507576
+vt 0.492424 0.507576
+vt 0.295455 0.492424
+vt 0.234848 0.492424
+vt 0.234848 0.007576
+vt 0.295455 0.007576
+vt 0.219697 0.007576
+vt 0.219697 0.492424
+vt 0.159091 0.492424
+vt 0.159091 0.007576
+vt 0.083333 0.492424
+vt 0.083333 0.007576
+vt 0.143939 0.007576
+vt 0.143939 0.492424
+s off
+f 1/1 3/2 4/3 2/4
+f 3/2 5/5 6/6 4/3
+f 5/5 7/7 8/8 6/6
+f 7/7 9/9 10/10 8/8
+f 9/9 11/11 12/12 10/10
+f 11/11 13/13 14/14 12/12
+f 13/13 15/15 16/16 14/14
+f 15/15 17/17 18/18 16/16
+f 17/17 19/19 20/20 18/18
+f 19/19 21/21 22/22 20/20
+f 21/21 23/23 24/24 22/22
+f 23/23 25/25 26/26 24/24
+f 25/27 27/28 28/29 26/30
+f 27/28 29/31 30/32 28/29
+f 31/33 1/1 2/4 32/34
+f 29/31 31/33 32/34 30/32
+f 4/35 50/36 2/37
+f 1/38 49/39 3/40
+f 3/40 49/39 5/41
+f 5/41 49/39 7/42
+f 7/42 49/39 9/43
+f 9/43 49/39 11/44
+f 11/44 49/39 13/45
+f 13/45 49/39 15/46
+f 15/46 49/39 17/47
+f 17/47 49/39 19/48
+f 19/48 49/39 21/49
+f 21/49 49/39 23/50
+f 23/50 49/39 25/51
+f 25/51 49/39 27/52
+f 27/52 49/39 29/53
+f 29/53 49/39 31/54
+f 31/54 49/39 1/38
+f 2/37 50/36 32/55
+f 32/55 50/36 30/56
+f 30/56 50/36 28/57
+f 28/57 50/36 26/58
+f 26/58 50/36 24/59
+f 24/59 50/36 22/60
+f 22/60 50/36 20/61
+f 20/61 50/36 18/62
+f 18/62 50/36 16/63
+f 16/63 50/36 14/64
+f 14/64 50/36 12/65
+f 12/65 50/36 10/66
+f 10/66 50/36 8/67
+f 8/67 50/36 6/68
+f 6/68 50/36 4/35
+f 41/69 91/70 92/71 42/72
+f 81/73 83/74 100/75
+f 79/76 81/73 100/75
+f 77/77 79/76 100/75
+f 75/78 77/77 100/75
+f 73/79 75/78 100/75
+f 71/80 73/79 100/75
+f 69/81 71/80 100/75
+f 67/82 69/81 100/75
+f 65/83 67/82 100/75
+f 63/84 65/83 100/75
+f 61/85 63/84 100/75
+f 59/86 61/85 100/75
+f 57/87 59/86 100/75
+f 55/88 57/87 100/75
+f 85/89 55/88 100/75
+f 56/90 86/91 99/92
+f 58/93 56/90 99/92
+f 60/94 58/93 99/92
+f 62/95 60/94 99/92
+f 64/96 62/95 99/92
+f 66/97 64/96 99/92
+f 68/98 66/97 99/92
+f 70/99 68/98 99/92
+f 72/100 70/99 99/92
+f 74/101 72/100 99/92
+f 76/102 74/101 99/92
+f 78/103 76/102 99/92
+f 80/104 78/103 99/92
+f 82/105 80/104 99/92
+f 84/106 82/105 99/92
+f 86/91 84/106 99/92
+f 83/74 85/89 100/75
+f 58/22 57/21 55/19 56/20
+f 56/20 55/19 85/17 86/18
+f 60/24 59/23 57/21 58/22
+f 62/26 61/25 59/23 60/24
+f 64/29 63/28 61/27 62/30
+f 66/32 65/31 63/28 64/29
+f 68/34 67/33 65/31 66/32
+f 70/4 69/1 67/33 68/34
+f 72/3 71/2 69/1 70/4
+f 74/6 73/5 71/2 72/3
+f 76/8 75/7 73/5 74/6
+f 78/10 77/9 75/7 76/8
+f 80/12 79/11 77/9 78/10
+f 82/14 81/13 79/11 80/12
+f 84/16 83/15 81/13 82/14
+f 86/18 85/17 83/15 84/16
+f 36/107 51/108 87/109 37/110
+f 34/111 53/112 52/113 35/114
+f 47/115 97/116 98/117 48/118
+f 33/119 54/120 53/112 34/111
+f 35/114 52/113 51/108 36/107
+f 48/118 98/117 54/120 33/119
+f 46/121 96/122 97/116 47/115
+f 45/123 95/124 96/122 46/121
+f 44/125 94/126 95/124 45/123
+f 43/127 93/128 94/126 44/125
+f 42/72 92/71 93/128 43/127
+f 40/129 90/130 91/70 41/69
+f 39/131 89/132 90/130 40/129
+f 38/133 88/134 89/132 39/131
+f 37/110 87/109 88/135 38/136
+f 105/137 106/138 102/139 101/140
+f 106/141 107/142 103/143 102/144
+f 107/145 108/146 104/147 103/148
+f 108/149 105/150 101/151 104/152
+f 101/153 102/154 103/155 104/156
+f 108/157 107/158 106/159 105/160
diff --git a/pipeworks/models/pipeworks_flow_sensor.obj b/pipeworks/models/pipeworks_flow_sensor.obj
new file mode 100644
index 0000000..f0ba87e
--- /dev/null
+++ b/pipeworks/models/pipeworks_flow_sensor.obj
@@ -0,0 +1,390 @@
+# Blender v2.69 (sub 0) OBJ File: 'pipe-flow-sensor.blend'
+# www.blender.org
+o Cube.001
+v -0.468750 -0.153248 -0.030483
+v -0.500000 -0.153248 -0.030483
+v -0.468750 -0.153248 0.030483
+v -0.500000 -0.153248 0.030483
+v -0.468750 -0.129917 0.086808
+v -0.500000 -0.129917 0.086808
+v -0.468750 -0.086808 0.129917
+v -0.500000 -0.086808 0.129917
+v -0.468750 -0.030483 0.153248
+v -0.500000 -0.030483 0.153248
+v -0.468750 0.030483 0.153248
+v -0.500000 0.030483 0.153248
+v -0.468750 0.086808 0.129917
+v -0.500000 0.086808 0.129917
+v -0.468750 0.129917 0.086808
+v -0.500000 0.129917 0.086808
+v -0.468750 0.153248 0.030483
+v -0.500000 0.153247 0.030483
+v -0.468750 0.153248 -0.030483
+v -0.500000 0.153248 -0.030483
+v -0.468750 0.129917 -0.086808
+v -0.500000 0.129917 -0.086808
+v -0.468750 0.086808 -0.129917
+v -0.500000 0.086808 -0.129917
+v -0.468750 0.030483 -0.153248
+v -0.500000 0.030483 -0.153248
+v -0.468750 -0.030483 -0.153248
+v -0.500000 -0.030483 -0.153248
+v -0.468750 -0.086808 -0.129917
+v -0.500000 -0.086808 -0.129917
+v -0.468750 -0.129917 -0.086808
+v -0.500000 -0.129917 -0.086808
+v -0.468750 -0.122598 -0.024386
+v -0.468750 -0.122598 0.024386
+v -0.468750 -0.103934 0.069446
+v -0.468750 -0.069446 0.103934
+v -0.468750 -0.024386 0.122598
+v -0.468750 0.024386 0.122598
+v -0.468750 0.069446 0.103934
+v -0.468750 0.103934 0.069446
+v -0.468750 0.122598 0.024386
+v -0.468750 0.122598 -0.024386
+v -0.468750 0.103934 -0.069446
+v -0.468750 0.069446 -0.103934
+v -0.468750 0.024386 -0.122598
+v -0.468750 -0.024387 -0.122598
+v -0.468750 -0.069447 -0.103934
+v -0.468750 -0.103934 -0.069446
+v -0.468750 -0.000000 -0.000000
+v -0.500000 -0.000000 -0.000000
+v 0.468750 -0.069446 0.103934
+v 0.468750 -0.103933 0.069447
+v 0.468750 -0.122598 0.024387
+v 0.468750 -0.122598 -0.024386
+v 0.500000 -0.129917 -0.086807
+v 0.468750 -0.129917 -0.086807
+v 0.500000 -0.086808 -0.129917
+v 0.468750 -0.086808 -0.129917
+v 0.500000 -0.030483 -0.153247
+v 0.468750 -0.030483 -0.153247
+v 0.500000 0.030483 -0.153247
+v 0.468750 0.030483 -0.153247
+v 0.500000 0.086808 -0.129917
+v 0.468750 0.086808 -0.129917
+v 0.500000 0.129917 -0.086808
+v 0.468750 0.129917 -0.086808
+v 0.500000 0.153248 -0.030483
+v 0.468750 0.153248 -0.030483
+v 0.500000 0.153248 0.030483
+v 0.468750 0.153248 0.030483
+v 0.500000 0.129917 0.086808
+v 0.468750 0.129917 0.086808
+v 0.500000 0.086808 0.129917
+v 0.468750 0.086808 0.129917
+v 0.500000 0.030483 0.153248
+v 0.468750 0.030483 0.153248
+v 0.500000 -0.030483 0.153248
+v 0.468750 -0.030483 0.153248
+v 0.500000 -0.086808 0.129917
+v 0.468750 -0.086808 0.129917
+v 0.500000 -0.129917 0.086808
+v 0.468750 -0.129917 0.086808
+v 0.500000 -0.153247 0.030483
+v 0.468750 -0.153247 0.030483
+v 0.500000 -0.153247 -0.030483
+v 0.468750 -0.153247 -0.030483
+v 0.468750 -0.024386 0.122598
+v 0.468750 0.024387 0.122598
+v 0.468750 0.069447 0.103934
+v 0.468750 0.103934 0.069447
+v 0.468750 0.122598 0.024387
+v 0.468750 0.122598 -0.024386
+v 0.468750 0.103934 -0.069446
+v 0.468750 0.069447 -0.103933
+v 0.468750 0.024387 -0.122598
+v 0.468750 -0.024386 -0.122598
+v 0.468750 -0.069446 -0.103933
+v 0.468750 -0.103933 -0.069446
+v 0.468750 0.000000 0.000000
+v 0.500000 0.000000 0.000000
+v 0.250000 -0.187500 0.187500
+v -0.250000 -0.187500 0.187500
+v -0.250000 -0.187500 -0.187500
+v 0.250000 -0.187500 -0.187500
+v 0.250000 0.187500 0.187500
+v -0.250000 0.187500 0.187500
+v -0.250000 0.187500 -0.187500
+v 0.250000 0.187500 -0.187500
+vt 0.813725 0.460784
+vt 0.774510 0.460784
+vt 0.774510 0.500000
+vt 0.813725 0.500000
+vt 0.735294 0.460784
+vt 0.735294 0.500000
+vt 0.696078 0.460784
+vt 0.696078 0.500000
+vt 0.656863 0.460784
+vt 0.656863 0.500000
+vt 0.617647 0.460784
+vt 0.617647 0.500000
+vt 0.578431 0.460784
+vt 0.578431 0.500000
+vt 0.539216 0.460784
+vt 0.539216 0.500000
+vt 0.500000 0.460784
+vt 0.500000 0.500000
+vt 0.460784 0.460784
+vt 0.460784 0.500000
+vt 0.421569 0.460784
+vt 0.421569 0.500000
+vt 0.382353 0.460784
+vt 0.382353 0.500000
+vt 0.343137 0.460784
+vt 0.343137 0.500000
+vt 0.970588 0.460784
+vt 0.931373 0.460784
+vt 0.931373 0.500000
+vt 0.970588 0.500000
+vt 0.892157 0.460784
+vt 0.892157 0.500000
+vt 0.852941 0.460784
+vt 0.852941 0.500000
+vt 0.480968 0.531171
+vt 0.460590 0.633014
+vt 0.440211 0.531171
+vt 0.677539 0.531171
+vt 0.697917 0.633014
+vt 0.718296 0.531171
+vt 0.755950 0.546676
+vt 0.784770 0.575325
+vt 0.800366 0.612756
+vt 0.800366 0.653272
+vt 0.784770 0.690703
+vt 0.755950 0.719352
+vt 0.718296 0.734857
+vt 0.677539 0.734857
+vt 0.639884 0.719352
+vt 0.611065 0.690703
+vt 0.595468 0.653272
+vt 0.595468 0.612756
+vt 0.611065 0.575325
+vt 0.639885 0.546676
+vt 0.402557 0.546676
+vt 0.373737 0.575325
+vt 0.358140 0.612756
+vt 0.358140 0.653272
+vt 0.373737 0.690703
+vt 0.402557 0.719352
+vt 0.440211 0.734857
+vt 0.480968 0.734857
+vt 0.518622 0.719352
+vt 0.547442 0.690703
+vt 0.563039 0.653272
+vt 0.563039 0.612756
+vt 0.547442 0.575325
+vt 0.518622 0.546676
+vt 0.460784 0.441176
+vt 0.460784 0.127451
+vt 0.500000 0.127451
+vt 0.500000 0.441176
+vt 0.402558 0.546671
+vt 0.440212 0.531167
+vt 0.460591 0.633009
+vt 0.373738 0.575320
+vt 0.358141 0.612752
+vt 0.358141 0.653267
+vt 0.373738 0.690699
+vt 0.402558 0.719348
+vt 0.440212 0.734852
+vt 0.480969 0.734852
+vt 0.518623 0.719348
+vt 0.547443 0.690699
+vt 0.563040 0.653267
+vt 0.563040 0.612752
+vt 0.547443 0.575320
+vt 0.518623 0.546671
+vt 0.480969 0.531167
+vt 0.639882 0.546671
+vt 0.677537 0.531167
+vt 0.697915 0.633009
+vt 0.611063 0.575320
+vt 0.595466 0.612752
+vt 0.595466 0.653267
+vt 0.611063 0.690699
+vt 0.639882 0.719347
+vt 0.677537 0.734852
+vt 0.718293 0.734852
+vt 0.755947 0.719347
+vt 0.784767 0.690699
+vt 0.800364 0.653267
+vt 0.800364 0.612752
+vt 0.784767 0.575320
+vt 0.755948 0.546671
+vt 0.718293 0.531167
+vt 0.892157 0.441176
+vt 0.892157 0.127451
+vt 0.931373 0.127451
+vt 0.931373 0.441176
+vt 0.813725 0.441176
+vt 0.813725 0.127451
+vt 0.852941 0.127451
+vt 0.852941 0.441176
+vt 0.696078 0.441176
+vt 0.696078 0.127451
+vt 0.735294 0.127451
+vt 0.735294 0.441176
+vt 0.774510 0.441176
+vt 0.774510 0.127451
+vt 0.656863 0.441176
+vt 0.656863 0.127451
+vt 0.617647 0.441176
+vt 0.617647 0.127451
+vt 0.578431 0.441176
+vt 0.578431 0.127451
+vt 0.539216 0.441176
+vt 0.539216 0.127451
+vt 0.421569 0.441176
+vt 0.421569 0.127451
+vt 0.382353 0.441176
+vt 0.382353 0.127451
+vt 0.343137 0.441176
+vt 0.343137 0.127451
+vt 0.970588 0.127451
+vt 0.970588 0.441176
+vt 0.009804 0.500000
+vt 0.323529 0.500000
+vt 0.323529 0.735294
+vt 0.009804 0.735294
+vt 0.264706 0.990196
+vt 0.264706 0.754902
+vt 0.500000 0.754902
+vt 0.500000 0.990196
+vt 0.519608 0.754902
+vt 0.833333 0.754902
+vt 0.833333 0.990196
+vt 0.519608 0.990196
+vt 0.245098 0.754902
+vt 0.245098 0.990196
+vt 0.009804 0.990196
+vt 0.009804 0.754902
+vt 0.323529 0.245098
+vt 0.009804 0.245098
+vt 0.009804 0.009804
+vt 0.323529 0.009804
+vt 0.009804 0.254902
+vt 0.323529 0.254902
+vt 0.323529 0.490196
+vt 0.009804 0.490196
+s off
+f 1/1 3/2 4/3 2/4
+f 3/2 5/5 6/6 4/3
+f 5/5 7/7 8/8 6/6
+f 7/7 9/9 10/10 8/8
+f 9/9 11/11 12/12 10/10
+f 11/11 13/13 14/14 12/12
+f 13/13 15/15 16/16 14/14
+f 15/15 17/17 18/18 16/16
+f 17/17 19/19 20/20 18/18
+f 19/19 21/21 22/22 20/20
+f 21/21 23/23 24/24 22/22
+f 23/23 25/25 26/26 24/24
+f 25/27 27/28 28/29 26/30
+f 27/28 29/31 30/32 28/29
+f 31/33 1/1 2/4 32/34
+f 29/31 31/33 32/34 30/32
+f 4/35 50/36 2/37
+f 1/38 49/39 3/40
+f 3/40 49/39 5/41
+f 5/41 49/39 7/42
+f 7/42 49/39 9/43
+f 9/43 49/39 11/44
+f 11/44 49/39 13/45
+f 13/45 49/39 15/46
+f 15/46 49/39 17/47
+f 17/47 49/39 19/48
+f 19/48 49/39 21/49
+f 21/49 49/39 23/50
+f 23/50 49/39 25/51
+f 25/51 49/39 27/52
+f 27/52 49/39 29/53
+f 29/53 49/39 31/54
+f 31/54 49/39 1/38
+f 2/37 50/36 32/55
+f 32/55 50/36 30/56
+f 30/56 50/36 28/57
+f 28/57 50/36 26/58
+f 26/58 50/36 24/59
+f 24/59 50/36 22/60
+f 22/60 50/36 20/61
+f 20/61 50/36 18/62
+f 18/62 50/36 16/63
+f 16/63 50/36 14/64
+f 14/64 50/36 12/65
+f 12/65 50/36 10/66
+f 10/66 50/36 8/67
+f 8/67 50/36 6/68
+f 6/68 50/36 4/35
+f 41/69 91/70 92/71 42/72
+f 81/73 83/74 100/75
+f 79/76 81/73 100/75
+f 77/77 79/76 100/75
+f 75/78 77/77 100/75
+f 73/79 75/78 100/75
+f 71/80 73/79 100/75
+f 69/81 71/80 100/75
+f 67/82 69/81 100/75
+f 65/83 67/82 100/75
+f 63/84 65/83 100/75
+f 61/85 63/84 100/75
+f 59/86 61/85 100/75
+f 57/87 59/86 100/75
+f 55/88 57/87 100/75
+f 85/89 55/88 100/75
+f 56/90 86/91 99/92
+f 58/93 56/90 99/92
+f 60/94 58/93 99/92
+f 62/95 60/94 99/92
+f 64/96 62/95 99/92
+f 66/97 64/96 99/92
+f 68/98 66/97 99/92
+f 70/99 68/98 99/92
+f 72/100 70/99 99/92
+f 74/101 72/100 99/92
+f 76/102 74/101 99/92
+f 78/103 76/102 99/92
+f 80/104 78/103 99/92
+f 82/105 80/104 99/92
+f 84/106 82/105 99/92
+f 86/91 84/106 99/92
+f 83/74 85/89 100/75
+f 58/22 57/21 55/19 56/20
+f 56/20 55/19 85/17 86/18
+f 60/24 59/23 57/21 58/22
+f 62/26 61/25 59/23 60/24
+f 64/29 63/28 61/27 62/30
+f 66/32 65/31 63/28 64/29
+f 68/34 67/33 65/31 66/32
+f 70/4 69/1 67/33 68/34
+f 72/3 71/2 69/1 70/4
+f 74/6 73/5 71/2 72/3
+f 76/8 75/7 73/5 74/6
+f 78/10 77/9 75/7 76/8
+f 80/12 79/11 77/9 78/10
+f 82/14 81/13 79/11 80/12
+f 84/16 83/15 81/13 82/14
+f 86/18 85/17 83/15 84/16
+f 36/107 51/108 87/109 37/110
+f 34/111 53/112 52/113 35/114
+f 47/115 97/116 98/117 48/118
+f 33/119 54/120 53/112 34/111
+f 35/114 52/113 51/108 36/107
+f 48/118 98/117 54/120 33/119
+f 46/121 96/122 97/116 47/115
+f 45/123 95/124 96/122 46/121
+f 44/125 94/126 95/124 45/123
+f 43/127 93/128 94/126 44/125
+f 42/72 92/71 93/128 43/127
+f 40/129 90/130 91/70 41/69
+f 39/131 89/132 90/130 40/129
+f 38/133 88/134 89/132 39/131
+f 37/110 87/109 88/135 38/136
+f 105/137 106/138 102/139 101/140
+f 106/141 107/142 103/143 102/144
+f 107/145 108/146 104/147 103/148
+f 108/149 105/150 101/151 104/152
+f 101/153 102/154 103/155 104/156
+f 108/157 107/158 106/159 105/160
diff --git a/pipeworks/models/pipeworks_fountainhead.obj b/pipeworks/models/pipeworks_fountainhead.obj
new file mode 100644
index 0000000..7685dbf
--- /dev/null
+++ b/pipeworks/models/pipeworks_fountainhead.obj
@@ -0,0 +1,352 @@
+# Blender v2.69 (sub 0) OBJ File: 'pipe-fountainhead.blend'
+# www.blender.org
+o Cube.001
+v 0.153248 -0.468750 -0.030483
+v 0.153248 -0.500000 -0.030483
+v 0.153248 -0.468750 0.030483
+v 0.153248 -0.500000 0.030483
+v 0.129917 -0.468750 0.086808
+v 0.129917 -0.500000 0.086808
+v 0.086808 -0.468750 0.129917
+v 0.086808 -0.500000 0.129917
+v 0.030483 -0.468750 0.153248
+v 0.030483 -0.500000 0.153248
+v -0.030483 -0.468750 0.153248
+v -0.030483 -0.500000 0.153248
+v -0.086808 -0.468750 0.129917
+v -0.086808 -0.500000 0.129917
+v -0.129917 -0.468750 0.086808
+v -0.129917 -0.500000 0.086808
+v -0.153247 -0.468750 0.030483
+v -0.153247 -0.500000 0.030483
+v -0.153247 -0.468750 -0.030483
+v -0.153247 -0.500000 -0.030483
+v -0.129917 -0.468750 -0.086808
+v -0.129917 -0.500000 -0.086808
+v -0.086808 -0.468750 -0.129917
+v -0.086807 -0.500000 -0.129917
+v -0.030482 -0.468750 -0.153248
+v -0.030482 -0.500000 -0.153248
+v 0.030483 -0.468750 -0.153248
+v 0.030483 -0.500000 -0.153248
+v 0.086808 -0.468750 -0.129917
+v 0.086808 -0.500000 -0.129917
+v 0.129918 -0.468750 -0.086808
+v 0.129918 -0.500000 -0.086808
+v 0.122598 -0.468750 -0.024386
+v 0.122598 -0.468750 0.024386
+v 0.103934 -0.468750 0.069446
+v 0.069447 -0.468750 0.103934
+v 0.024387 -0.468750 0.122598
+v -0.024386 -0.468750 0.122598
+v -0.069446 -0.468750 0.103934
+v -0.103933 -0.468750 0.069446
+v -0.122598 -0.468750 0.024386
+v -0.122598 -0.468750 -0.024386
+v -0.103933 -0.468750 -0.069446
+v -0.069446 -0.468750 -0.103934
+v -0.024386 -0.468750 -0.122598
+v 0.024387 -0.468750 -0.122598
+v 0.069447 -0.468750 -0.103934
+v 0.103934 -0.468750 -0.069446
+v 0.000000 -0.468750 0.000000
+v 0.000000 -0.500000 -0.000000
+v 0.069446 0.312500 0.103934
+v 0.103933 0.312500 0.069447
+v 0.122598 0.312500 0.024387
+v 0.122598 0.312500 -0.024386
+v 0.129917 0.500000 -0.086808
+v 0.129917 0.312500 -0.086808
+v 0.086808 0.500000 -0.129917
+v 0.086808 0.312500 -0.129917
+v 0.030483 0.500000 -0.153247
+v 0.030483 0.312500 -0.153248
+v -0.030483 0.500000 -0.153247
+v -0.030483 0.312500 -0.153248
+v -0.086808 0.500000 -0.129917
+v -0.086808 0.312500 -0.129917
+v -0.129918 0.500000 -0.086808
+v -0.129918 0.312500 -0.086808
+v -0.153248 0.500000 -0.030483
+v -0.153248 0.312500 -0.030483
+v -0.153248 0.500000 0.030483
+v -0.153248 0.312500 0.030483
+v -0.129918 0.500000 0.086808
+v -0.129918 0.312500 0.086808
+v -0.086808 0.500000 0.129917
+v -0.086808 0.312500 0.129917
+v -0.030483 0.500000 0.153248
+v -0.030483 0.312500 0.153248
+v 0.030482 0.500000 0.153248
+v 0.030482 0.312500 0.153248
+v 0.086807 0.500000 0.129917
+v 0.086807 0.312500 0.129917
+v 0.129917 0.500000 0.086808
+v 0.129917 0.312500 0.086808
+v 0.153247 0.500000 0.030483
+v 0.153247 0.312500 0.030483
+v 0.153247 0.500000 -0.030483
+v 0.153247 0.312500 -0.030483
+v 0.024386 0.312500 0.122598
+v -0.024387 0.312500 0.122598
+v -0.069447 0.312500 0.103934
+v -0.103934 0.312500 0.069446
+v -0.122599 0.312500 0.024386
+v -0.122599 0.312500 -0.024386
+v -0.103934 0.312500 -0.069446
+v -0.069447 0.312500 -0.103934
+v -0.024387 0.312500 -0.122598
+v 0.024386 0.312500 -0.122598
+v 0.069446 0.312500 -0.103933
+v 0.103933 0.312500 -0.069446
+v -0.000000 0.312500 0.000000
+v -0.000000 0.500000 0.000000
+vt 0.680556 0.486111
+vt 0.625000 0.486111
+vt 0.625000 0.652778
+vt 0.680556 0.652778
+vt 0.569444 0.486111
+vt 0.569444 0.652778
+vt 0.513889 0.486111
+vt 0.513889 0.652778
+vt 0.458333 0.486111
+vt 0.458333 0.652778
+vt 0.402778 0.486111
+vt 0.402778 0.652778
+vt 0.347222 0.486111
+vt 0.347222 0.652778
+vt 0.291667 0.486111
+vt 0.291667 0.652778
+vt 0.236111 0.486111
+vt 0.236111 0.652778
+vt 0.180556 0.486111
+vt 0.180556 0.652778
+vt 0.125000 0.486111
+vt 0.125000 0.652778
+vt 0.069444 0.486111
+vt 0.069444 0.652778
+vt 0.013889 0.486111
+vt 0.013889 0.652778
+vt 0.902778 0.486111
+vt 0.847222 0.486111
+vt 0.847222 0.652778
+vt 0.902778 0.652778
+vt 0.791667 0.486111
+vt 0.791667 0.652778
+vt 0.736111 0.486111
+vt 0.736111 0.652778
+vt 0.194034 0.696809
+vt 0.165430 0.839757
+vt 0.136827 0.696809
+vt 0.469943 0.696809
+vt 0.498546 0.839757
+vt 0.527150 0.696809
+vt 0.580002 0.718572
+vt 0.620453 0.758784
+vt 0.642345 0.811323
+vt 0.642345 0.868191
+vt 0.620453 0.920730
+vt 0.580002 0.960942
+vt 0.527149 0.982704
+vt 0.469943 0.982704
+vt 0.417091 0.960942
+vt 0.376639 0.920730
+vt 0.354747 0.868191
+vt 0.354747 0.811323
+vt 0.376639 0.758784
+vt 0.417091 0.718572
+vt 0.083975 0.718572
+vt 0.043524 0.758784
+vt 0.021631 0.811323
+vt 0.021631 0.868191
+vt 0.043523 0.920730
+vt 0.083975 0.960942
+vt 0.136827 0.982704
+vt 0.194034 0.982704
+vt 0.246886 0.960942
+vt 0.287337 0.920730
+vt 0.309229 0.868191
+vt 0.309229 0.811323
+vt 0.287337 0.758784
+vt 0.246886 0.718572
+vt 0.180556 0.458333
+vt 0.180556 0.013889
+vt 0.236111 0.013889
+vt 0.236111 0.458333
+vt 0.750889 0.718565
+vt 0.803741 0.696803
+vt 0.832345 0.839750
+vt 0.710438 0.758777
+vt 0.688546 0.811316
+vt 0.688546 0.868184
+vt 0.710438 0.920723
+vt 0.750889 0.960935
+vt 0.803741 0.982698
+vt 0.860948 0.982698
+vt 0.913800 0.960935
+vt 0.954251 0.920723
+vt 0.976143 0.868184
+vt 0.976143 0.811316
+vt 0.954251 0.758777
+vt 0.913800 0.718565
+vt 0.860948 0.696803
+vt 0.417087 0.718565
+vt 0.469939 0.696803
+vt 0.498543 0.839750
+vt 0.376636 0.758777
+vt 0.354744 0.811316
+vt 0.354744 0.868184
+vt 0.376636 0.920723
+vt 0.417087 0.960935
+vt 0.469939 0.982698
+vt 0.527146 0.982698
+vt 0.579998 0.960935
+vt 0.620449 0.920723
+vt 0.642341 0.868184
+vt 0.642341 0.811316
+vt 0.620449 0.758777
+vt 0.579998 0.718565
+vt 0.527146 0.696803
+vt 0.791667 0.458333
+vt 0.791667 0.013889
+vt 0.847222 0.013889
+vt 0.847222 0.458333
+vt 0.680556 0.458333
+vt 0.680556 0.013889
+vt 0.736111 0.013889
+vt 0.736111 0.458333
+vt 0.513889 0.458333
+vt 0.513889 0.013889
+vt 0.569444 0.013889
+vt 0.569444 0.458333
+vt 0.625000 0.458333
+vt 0.625000 0.013889
+vt 0.458333 0.458333
+vt 0.458333 0.013889
+vt 0.402778 0.458333
+vt 0.402778 0.013889
+vt 0.347222 0.458333
+vt 0.347222 0.013889
+vt 0.291667 0.458333
+vt 0.291667 0.013889
+vt 0.125000 0.458333
+vt 0.125000 0.013889
+vt 0.069444 0.458333
+vt 0.069444 0.013889
+vt 0.013889 0.458333
+vt 0.013889 0.013889
+vt 0.902778 0.013889
+vt 0.902778 0.458333
+s off
+f 1/1 3/2 4/3 2/4
+f 3/2 5/5 6/6 4/3
+f 5/5 7/7 8/8 6/6
+f 7/7 9/9 10/10 8/8
+f 9/9 11/11 12/12 10/10
+f 11/11 13/13 14/14 12/12
+f 13/13 15/15 16/16 14/14
+f 15/15 17/17 18/18 16/16
+f 17/17 19/19 20/20 18/18
+f 19/19 21/21 22/22 20/20
+f 21/21 23/23 24/24 22/22
+f 23/23 25/25 26/26 24/24
+f 25/27 27/28 28/29 26/30
+f 27/28 29/31 30/32 28/29
+f 31/33 1/1 2/4 32/34
+f 29/31 31/33 32/34 30/32
+f 4/35 50/36 2/37
+f 1/38 49/39 3/40
+f 3/40 49/39 5/41
+f 5/41 49/39 7/42
+f 7/42 49/39 9/43
+f 9/43 49/39 11/44
+f 11/44 49/39 13/45
+f 13/45 49/39 15/46
+f 15/46 49/39 17/47
+f 17/47 49/39 19/48
+f 19/48 49/39 21/49
+f 21/49 49/39 23/50
+f 23/50 49/39 25/51
+f 25/51 49/39 27/52
+f 27/52 49/39 29/53
+f 29/53 49/39 31/54
+f 31/54 49/39 1/38
+f 2/37 50/36 32/55
+f 32/55 50/36 30/56
+f 30/56 50/36 28/57
+f 28/57 50/36 26/58
+f 26/58 50/36 24/59
+f 24/59 50/36 22/60
+f 22/60 50/36 20/61
+f 20/61 50/36 18/62
+f 18/62 50/36 16/63
+f 16/63 50/36 14/64
+f 14/64 50/36 12/65
+f 12/65 50/36 10/66
+f 10/66 50/36 8/67
+f 8/67 50/36 6/68
+f 6/68 50/36 4/35
+f 41/69 91/70 92/71 42/72
+f 81/73 83/74 100/75
+f 79/76 81/73 100/75
+f 77/77 79/76 100/75
+f 75/78 77/77 100/75
+f 73/79 75/78 100/75
+f 71/80 73/79 100/75
+f 69/81 71/80 100/75
+f 67/82 69/81 100/75
+f 65/83 67/82 100/75
+f 63/84 65/83 100/75
+f 61/85 63/84 100/75
+f 59/86 61/85 100/75
+f 57/87 59/86 100/75
+f 55/88 57/87 100/75
+f 85/89 55/88 100/75
+f 56/90 86/91 99/92
+f 58/93 56/90 99/92
+f 60/94 58/93 99/92
+f 62/95 60/94 99/92
+f 64/96 62/95 99/92
+f 66/97 64/96 99/92
+f 68/98 66/97 99/92
+f 70/99 68/98 99/92
+f 72/100 70/99 99/92
+f 74/101 72/100 99/92
+f 76/102 74/101 99/92
+f 78/103 76/102 99/92
+f 80/104 78/103 99/92
+f 82/105 80/104 99/92
+f 84/106 82/105 99/92
+f 86/91 84/106 99/92
+f 83/74 85/89 100/75
+f 58/22 57/21 55/19 56/20
+f 56/20 55/19 85/17 86/18
+f 60/24 59/23 57/21 58/22
+f 62/26 61/25 59/23 60/24
+f 64/29 63/28 61/27 62/30
+f 66/32 65/31 63/28 64/29
+f 68/34 67/33 65/31 66/32
+f 70/4 69/1 67/33 68/34
+f 72/3 71/2 69/1 70/4
+f 74/6 73/5 71/2 72/3
+f 76/8 75/7 73/5 74/6
+f 78/10 77/9 75/7 76/8
+f 80/12 79/11 77/9 78/10
+f 82/14 81/13 79/11 80/12
+f 84/16 83/15 81/13 82/14
+f 86/18 85/17 83/15 84/16
+f 36/107 51/108 87/109 37/110
+f 34/111 53/112 52/113 35/114
+f 47/115 97/116 98/117 48/118
+f 33/119 54/120 53/112 34/111
+f 35/114 52/113 51/108 36/107
+f 48/118 98/117 54/120 33/119
+f 46/121 96/122 97/116 47/115
+f 45/123 95/124 96/122 46/121
+f 44/125 94/126 95/124 45/123
+f 43/127 93/128 94/126 44/125
+f 42/72 92/71 93/128 43/127
+f 40/129 90/130 91/70 41/69
+f 39/131 89/132 90/130 40/129
+f 38/133 88/134 89/132 39/131
+f 37/110 87/109 88/135 38/136
diff --git a/pipeworks/models/pipeworks_pipe_10.obj b/pipeworks/models/pipeworks_pipe_10.obj
new file mode 100644
index 0000000..9edb938
--- /dev/null
+++ b/pipeworks/models/pipeworks_pipe_10.obj
@@ -0,0 +1,891 @@
+# Blender v2.69 (sub 0) OBJ File: 'pipe-6way.blend'
+# www.blender.org
+mtllib pipeworks_pipe_10.mtl
+o Cube.000
+v 0.069446 -0.468750 -0.103934
+v 0.103933 -0.468750 -0.069446
+v 0.122598 -0.468750 -0.024386
+v 0.122598 -0.468750 0.024386
+v 0.129917 -0.500000 0.086808
+v 0.129917 -0.468750 0.086808
+v 0.086808 -0.500000 0.129917
+v 0.086808 -0.468750 0.129917
+v 0.030483 -0.500000 0.153247
+v 0.030483 -0.468750 0.153248
+v -0.030483 -0.500000 0.153247
+v -0.030483 -0.468750 0.153248
+v -0.086808 -0.500000 0.129917
+v -0.086808 -0.468750 0.129917
+v -0.129918 -0.500000 0.086808
+v -0.129917 -0.468750 0.086808
+v -0.153248 -0.500000 0.030483
+v -0.153248 -0.468750 0.030483
+v -0.153248 -0.500000 -0.030483
+v -0.153248 -0.468750 -0.030483
+v -0.129918 -0.500000 -0.086808
+v -0.129917 -0.468750 -0.086808
+v -0.086808 -0.500000 -0.129917
+v -0.086808 -0.468750 -0.129917
+v -0.030483 -0.500000 -0.153248
+v -0.030483 -0.468750 -0.153248
+v 0.030482 -0.500000 -0.153248
+v 0.030482 -0.468750 -0.153248
+v 0.086807 -0.500000 -0.129917
+v 0.086807 -0.468750 -0.129917
+v 0.129917 -0.500000 -0.086808
+v 0.129917 -0.468750 -0.086808
+v 0.153247 -0.500000 -0.030483
+v 0.153247 -0.468750 -0.030483
+v 0.153247 -0.500000 0.030483
+v 0.153247 -0.468750 0.030483
+v 0.024386 -0.468750 -0.122598
+v -0.024387 -0.468750 -0.122598
+v -0.069447 -0.468750 -0.103934
+v -0.103934 -0.468750 -0.069446
+v -0.122599 -0.468750 -0.024386
+v -0.122599 -0.468750 0.024386
+v -0.103934 -0.468750 0.069446
+v -0.069447 -0.468750 0.103934
+v -0.024387 -0.468750 0.122598
+v 0.024386 -0.468750 0.122598
+v 0.069446 -0.468750 0.103933
+v 0.103933 -0.468750 0.069446
+v -0.000000 -0.468750 -0.000000
+v -0.000000 -0.500000 -0.000000
+v -0.024386 -0.024391 -0.122598
+v -0.069446 -0.024391 -0.103934
+v -0.103934 -0.024391 -0.069446
+v -0.122598 -0.024391 -0.024386
+v -0.122598 -0.024391 0.024386
+v -0.103934 -0.024391 0.069446
+v -0.069446 -0.024391 0.103934
+v -0.024386 -0.024391 0.122598
+v 0.024386 -0.024391 0.122598
+v 0.103934 -0.024391 0.069446
+v 0.069446 -0.024391 0.103934
+v 0.103934 -0.024391 -0.069446
+v 0.122598 -0.024391 -0.024386
+v 0.122598 -0.024391 0.024386
+v 0.069446 -0.024391 -0.103934
+v 0.024386 -0.024391 -0.122598
+v 0.153248 0.468750 0.030483
+v 0.153248 0.500000 0.030483
+v 0.153248 0.468750 -0.030483
+v 0.153248 0.500000 -0.030483
+v 0.129917 0.468750 -0.086808
+v 0.129917 0.500000 -0.086808
+v 0.086808 0.468750 -0.129917
+v 0.086808 0.500000 -0.129917
+v 0.030483 0.468750 -0.153248
+v 0.030483 0.500000 -0.153248
+v -0.030483 0.468750 -0.153248
+v -0.030483 0.500000 -0.153248
+v -0.086808 0.468750 -0.129917
+v -0.086808 0.500000 -0.129917
+v -0.129917 0.468750 -0.086808
+v -0.129917 0.500000 -0.086808
+v -0.153247 0.468750 -0.030483
+v -0.153247 0.500000 -0.030483
+v -0.153247 0.468750 0.030483
+v -0.153247 0.500000 0.030483
+v -0.129917 0.468750 0.086808
+v -0.129917 0.500000 0.086808
+v -0.086808 0.468750 0.129917
+v -0.086808 0.500000 0.129917
+v -0.030483 0.468750 0.153248
+v -0.030483 0.500000 0.153248
+v 0.030483 0.468750 0.153248
+v 0.030483 0.500000 0.153248
+v 0.086808 0.468750 0.129917
+v 0.086808 0.500000 0.129917
+v 0.129917 0.468750 0.086808
+v 0.129918 0.500000 0.086808
+v 0.122598 0.468750 0.024386
+v 0.122598 0.468750 -0.024386
+v 0.103934 0.468750 -0.069446
+v 0.069447 0.468750 -0.103934
+v 0.024387 0.468750 -0.122598
+v -0.024386 0.468750 -0.122598
+v -0.069446 0.468750 -0.103934
+v -0.103933 0.468750 -0.069446
+v -0.122598 0.468750 -0.024386
+v -0.122598 0.468750 0.024386
+v -0.103933 0.468750 0.069446
+v -0.069446 0.468750 0.103934
+v -0.024386 0.468750 0.122598
+v 0.024387 0.468750 0.122598
+v 0.069447 0.468750 0.103934
+v 0.103934 0.468750 0.069446
+v 0.000000 0.468750 -0.000000
+v 0.000000 0.500000 0.000000
+v -0.024386 0.024390 -0.122598
+v -0.069446 0.024390 -0.103934
+v -0.103934 0.024390 -0.069446
+v -0.122598 0.024390 -0.024386
+v -0.122598 0.024390 0.024386
+v -0.103934 0.024390 0.069446
+v -0.069446 0.024390 0.103934
+v -0.024386 0.024389 0.122598
+v 0.024386 0.024389 0.122598
+v 0.103934 0.024390 0.069446
+v 0.069446 0.024390 0.103934
+v 0.103934 0.024390 -0.069446
+v 0.122598 0.024390 -0.024386
+v 0.122598 0.024390 0.024386
+v 0.069446 0.024390 -0.103934
+v 0.024386 0.024390 -0.122598
+v 0.468750 -0.153248 0.030483
+v 0.500000 -0.153248 0.030483
+v 0.468750 -0.153248 -0.030483
+v 0.500000 -0.153248 -0.030483
+v 0.468750 -0.129917 -0.086808
+v 0.500000 -0.129917 -0.086808
+v 0.468750 -0.086808 -0.129917
+v 0.500000 -0.086808 -0.129917
+v 0.468750 -0.030483 -0.153248
+v 0.500000 -0.030483 -0.153248
+v 0.468750 0.030483 -0.153248
+v 0.500000 0.030483 -0.153248
+v 0.468750 0.086808 -0.129917
+v 0.500000 0.086808 -0.129917
+v 0.468750 0.129917 -0.086808
+v 0.500000 0.129917 -0.086808
+v 0.468750 0.153248 -0.030483
+v 0.500000 0.153247 -0.030483
+v 0.468750 0.153248 0.030483
+v 0.500000 0.153248 0.030483
+v 0.468750 0.129917 0.086808
+v 0.500000 0.129917 0.086808
+v 0.468750 0.086808 0.129917
+v 0.500000 0.086808 0.129917
+v 0.468750 0.030483 0.153248
+v 0.500000 0.030483 0.153248
+v 0.468750 -0.030483 0.153248
+v 0.500000 -0.030483 0.153248
+v 0.468750 -0.086808 0.129917
+v 0.500000 -0.086808 0.129917
+v 0.468750 -0.129917 0.086808
+v 0.500000 -0.129917 0.086808
+v 0.468750 -0.122598 0.024386
+v 0.468750 -0.122598 -0.024386
+v 0.468750 -0.103934 -0.069446
+v 0.468750 -0.069446 -0.103934
+v 0.468750 -0.024386 -0.122598
+v 0.468750 0.024386 -0.122598
+v 0.468750 0.069446 -0.103934
+v 0.468750 0.103934 -0.069446
+v 0.468750 0.122598 -0.024386
+v 0.468750 0.122598 0.024386
+v 0.468750 0.103934 0.069446
+v 0.468750 0.069446 0.103934
+v 0.468750 0.024386 0.122598
+v 0.468750 -0.024387 0.122598
+v 0.468750 -0.069447 0.103934
+v 0.468750 -0.103934 0.069446
+v 0.468750 -0.000000 -0.000000
+v 0.500000 -0.000000 0.000000
+v -0.468750 -0.069446 -0.103934
+v -0.468750 -0.103933 -0.069446
+v -0.468750 -0.122598 -0.024387
+v -0.468750 -0.122598 0.024386
+v -0.500000 -0.129917 0.086808
+v -0.468750 -0.129917 0.086808
+v -0.500000 -0.086808 0.129917
+v -0.468750 -0.086808 0.129917
+v -0.500000 -0.030483 0.153247
+v -0.468750 -0.030483 0.153248
+v -0.500000 0.030483 0.153247
+v -0.468750 0.030483 0.153248
+v -0.500000 0.086808 0.129917
+v -0.468750 0.086808 0.129917
+v -0.500000 0.129917 0.086808
+v -0.468750 0.129917 0.086808
+v -0.500000 0.153248 0.030483
+v -0.468750 0.153248 0.030483
+v -0.500000 0.153248 -0.030483
+v -0.468750 0.153248 -0.030483
+v -0.500000 0.129917 -0.086808
+v -0.468750 0.129917 -0.086808
+v -0.500000 0.086808 -0.129917
+v -0.468750 0.086808 -0.129917
+v -0.500000 0.030483 -0.153248
+v -0.468750 0.030483 -0.153248
+v -0.500000 -0.030483 -0.153248
+v -0.468750 -0.030483 -0.153248
+v -0.500000 -0.086808 -0.129917
+v -0.468750 -0.086808 -0.129917
+v -0.500000 -0.129917 -0.086808
+v -0.468750 -0.129917 -0.086808
+v -0.500000 -0.153247 -0.030483
+v -0.468750 -0.153247 -0.030483
+v -0.500000 -0.153247 0.030483
+v -0.468750 -0.153247 0.030483
+v -0.468750 -0.024386 -0.122598
+v -0.468750 0.024387 -0.122598
+v -0.468750 0.069447 -0.103934
+v -0.468750 0.103934 -0.069446
+v -0.468750 0.122598 -0.024386
+v -0.468750 0.122598 0.024386
+v -0.468750 0.103934 0.069446
+v -0.468750 0.069447 0.103934
+v -0.468750 0.024387 0.122598
+v -0.468750 -0.024386 0.122598
+v -0.468750 -0.069446 0.103933
+v -0.468750 -0.103933 0.069446
+v -0.468750 0.000000 -0.000000
+v -0.500000 0.000000 -0.000000
+v 0.069446 -0.103934 0.468750
+v 0.103933 -0.069447 0.468750
+v 0.122598 -0.024387 0.468750
+v 0.122598 0.024386 0.468750
+v 0.129917 0.086807 0.500000
+v 0.129917 0.086807 0.468750
+v 0.086808 0.129917 0.500000
+v 0.086808 0.129917 0.468750
+v 0.030483 0.153247 0.500000
+v 0.030483 0.153247 0.468750
+v -0.030483 0.153247 0.500000
+v -0.030483 0.153247 0.468750
+v -0.086808 0.129917 0.500000
+v -0.086808 0.129917 0.468750
+v -0.129918 0.086808 0.500000
+v -0.129917 0.086808 0.468750
+v -0.153248 0.030483 0.500000
+v -0.153248 0.030483 0.468750
+v -0.153248 -0.030483 0.500000
+v -0.153248 -0.030483 0.468750
+v -0.129918 -0.086808 0.500000
+v -0.129917 -0.086808 0.468750
+v -0.086808 -0.129917 0.500000
+v -0.086808 -0.129917 0.468750
+v -0.030483 -0.153248 0.500000
+v -0.030483 -0.153248 0.468750
+v 0.030482 -0.153248 0.500000
+v 0.030482 -0.153248 0.468750
+v 0.086807 -0.129917 0.500000
+v 0.086807 -0.129917 0.468750
+v 0.129917 -0.086808 0.500000
+v 0.129917 -0.086808 0.468750
+v 0.153247 -0.030483 0.500000
+v 0.153247 -0.030483 0.468750
+v 0.153247 0.030483 0.500000
+v 0.153247 0.030483 0.468750
+v 0.024386 -0.122598 0.468750
+v -0.024387 -0.122598 0.468750
+v -0.069447 -0.103934 0.468750
+v -0.103934 -0.069447 0.468750
+v -0.122599 -0.024387 0.468750
+v -0.122599 0.024386 0.468750
+v -0.103934 0.069446 0.468750
+v -0.069447 0.103933 0.468750
+v -0.024387 0.122598 0.468750
+v 0.024386 0.122598 0.468750
+v 0.069446 0.103933 0.468750
+v 0.103933 0.069446 0.468750
+v -0.000000 -0.000000 0.468750
+v -0.000000 -0.000000 0.500000
+v -0.024386 -0.122598 0.024391
+v -0.069446 -0.103934 0.024391
+v -0.103934 -0.069446 0.024391
+v -0.122598 -0.024386 0.024391
+v -0.122598 0.024386 0.024391
+v -0.103934 0.069446 0.024391
+v -0.069446 0.103934 0.024391
+v -0.024386 0.122598 0.024391
+v 0.024386 0.122598 0.024391
+v 0.103934 0.069446 0.024391
+v 0.069446 0.103934 0.024391
+v 0.103934 -0.069446 0.024391
+v 0.122598 -0.024386 0.024391
+v 0.122598 0.024386 0.024391
+v 0.069446 -0.103934 0.024391
+v 0.024386 -0.122598 0.024391
+v 0.153248 0.030483 -0.468750
+v 0.153248 0.030483 -0.500000
+v 0.153248 -0.030483 -0.468750
+v 0.153248 -0.030483 -0.500000
+v 0.129917 -0.086808 -0.468750
+v 0.129917 -0.086808 -0.500000
+v 0.086808 -0.129917 -0.468750
+v 0.086808 -0.129917 -0.500000
+v 0.030483 -0.153248 -0.468750
+v 0.030483 -0.153248 -0.500000
+v -0.030483 -0.153248 -0.468750
+v -0.030483 -0.153248 -0.500000
+v -0.086808 -0.129917 -0.468750
+v -0.086808 -0.129917 -0.500000
+v -0.129917 -0.086808 -0.468750
+v -0.129917 -0.086808 -0.500000
+v -0.153247 -0.030483 -0.468750
+v -0.153247 -0.030483 -0.500000
+v -0.153247 0.030483 -0.468750
+v -0.153247 0.030483 -0.500000
+v -0.129917 0.086808 -0.468750
+v -0.129917 0.086808 -0.500000
+v -0.086808 0.129917 -0.468750
+v -0.086808 0.129917 -0.500000
+v -0.030483 0.153248 -0.468750
+v -0.030483 0.153248 -0.500000
+v 0.030483 0.153248 -0.468750
+v 0.030483 0.153248 -0.500000
+v 0.086808 0.129917 -0.468750
+v 0.086808 0.129917 -0.500000
+v 0.129917 0.086808 -0.468750
+v 0.129918 0.086808 -0.500000
+v 0.122598 0.024386 -0.468750
+v 0.122598 -0.024386 -0.468750
+v 0.103934 -0.069446 -0.468750
+v 0.069447 -0.103934 -0.468750
+v 0.024387 -0.122598 -0.468750
+v -0.024386 -0.122598 -0.468750
+v -0.069446 -0.103934 -0.468750
+v -0.103933 -0.069446 -0.468750
+v -0.122598 -0.024386 -0.468750
+v -0.122598 0.024386 -0.468750
+v -0.103933 0.069446 -0.468750
+v -0.069446 0.103934 -0.468750
+v -0.024386 0.122598 -0.468750
+v 0.024387 0.122598 -0.468750
+v 0.069447 0.103934 -0.468750
+v 0.103934 0.069446 -0.468750
+v 0.000000 -0.000000 -0.468750
+v 0.000000 0.000000 -0.500000
+v -0.024386 -0.122598 -0.024390
+v -0.069446 -0.103934 -0.024391
+v -0.103934 -0.069446 -0.024391
+v -0.122598 -0.024386 -0.024391
+v -0.122598 0.024386 -0.024391
+v -0.103934 0.069446 -0.024390
+v -0.069446 0.103934 -0.024390
+v -0.024386 0.122598 -0.024389
+v 0.024386 0.122598 -0.024389
+v 0.103934 0.069446 -0.024390
+v 0.069446 0.103934 -0.024390
+v 0.103934 -0.069446 -0.024390
+v 0.122598 -0.024386 -0.024390
+v 0.122598 0.024386 -0.024390
+v 0.069446 -0.103934 -0.024390
+v 0.024386 -0.122598 -0.024390
+vt 0.187500 0.265625
+vt 0.187500 0.015625
+vt 0.250000 0.015625
+vt 0.250000 0.265625
+vt 0.093322 0.682190
+vt 0.153370 0.657318
+vt 0.185867 0.820694
+vt 0.047364 0.728149
+vt 0.022491 0.788196
+vt 0.022491 0.853192
+vt 0.047364 0.913239
+vt 0.093322 0.959198
+vt 0.153370 0.984070
+vt 0.218365 0.984070
+vt 0.278413 0.959198
+vt 0.324371 0.913239
+vt 0.349244 0.853192
+vt 0.349244 0.788196
+vt 0.324371 0.728149
+vt 0.278413 0.682190
+vt 0.218365 0.657318
+vt 0.471785 0.682190
+vt 0.531832 0.657318
+vt 0.564330 0.820694
+vt 0.425826 0.728149
+vt 0.400953 0.788196
+vt 0.400953 0.853192
+vt 0.425826 0.913239
+vt 0.471785 0.959198
+vt 0.531832 0.984070
+vt 0.596827 0.984070
+vt 0.656875 0.959198
+vt 0.702834 0.913239
+vt 0.727706 0.853192
+vt 0.727706 0.788196
+vt 0.702834 0.728149
+vt 0.656875 0.682190
+vt 0.596827 0.657318
+vt 0.125000 0.609375
+vt 0.125000 0.546875
+vt 0.187500 0.546875
+vt 0.187500 0.609375
+vt 0.250000 0.546875
+vt 0.250000 0.609375
+vt 0.062500 0.609375
+vt 0.062500 0.546875
+vt 0.000000 0.609375
+vt 0.000000 0.546875
+vt 0.937500 0.609375
+vt 0.937500 0.546875
+vt 1.000000 0.546875
+vt 1.000000 0.609375
+vt 0.875000 0.609375
+vt 0.875000 0.546875
+vt 0.812500 0.609375
+vt 0.812500 0.546875
+vt 0.750000 0.609375
+vt 0.750000 0.546875
+vt 0.687500 0.609375
+vt 0.687500 0.546875
+vt 0.625000 0.609375
+vt 0.625000 0.546875
+vt 0.562500 0.609375
+vt 0.562500 0.546875
+vt 0.500000 0.609375
+vt 0.500000 0.546875
+vt 0.437500 0.609375
+vt 0.437500 0.546875
+vt 0.375000 0.609375
+vt 0.375000 0.546875
+vt 0.312500 0.609375
+vt 0.312500 0.546875
+vt 0.875000 0.265625
+vt 0.875000 0.015625
+vt 0.937500 0.015625
+vt 0.937500 0.265625
+vt 0.750000 0.265625
+vt 0.750000 0.015625
+vt 0.812500 0.015625
+vt 0.812500 0.265625
+vt 0.562500 0.265625
+vt 0.562500 0.015625
+vt 0.625000 0.015625
+vt 0.625000 0.265625
+vt 0.687500 0.265625
+vt 0.687500 0.015625
+vt 0.500000 0.265625
+vt 0.500000 0.015625
+vt 0.437500 0.265625
+vt 0.437500 0.015625
+vt 0.375000 0.265625
+vt 0.375000 0.015625
+vt 0.312500 0.265625
+vt 0.312500 0.015625
+vt 0.125000 0.265625
+vt 0.125000 0.015625
+vt 0.062500 0.265625
+vt 0.062500 0.015625
+vt 0.000000 0.265625
+vt 0.000000 0.015625
+vt 1.000000 0.015625
+vt 1.000000 0.265625
+vt 0.218363 0.657325
+vt 0.185866 0.820702
+vt 0.153368 0.657325
+vt 0.531836 0.657325
+vt 0.564334 0.820702
+vt 0.596832 0.657325
+vt 0.656879 0.682198
+vt 0.702838 0.728156
+vt 0.727710 0.788204
+vt 0.727710 0.853199
+vt 0.702838 0.913247
+vt 0.656879 0.959205
+vt 0.596831 0.984078
+vt 0.531836 0.984078
+vt 0.471788 0.959205
+vt 0.425830 0.913247
+vt 0.400957 0.853199
+vt 0.400957 0.788204
+vt 0.425830 0.728156
+vt 0.471789 0.682198
+vt 0.093321 0.682198
+vt 0.047362 0.728156
+vt 0.022489 0.788204
+vt 0.022489 0.853199
+vt 0.047362 0.913247
+vt 0.093320 0.959205
+vt 0.153368 0.984078
+vt 0.218363 0.984078
+vt 0.278411 0.959205
+vt 0.324369 0.913247
+vt 0.349242 0.853199
+vt 0.349242 0.788204
+vt 0.324369 0.728156
+vt 0.278411 0.682198
+vt 0.187500 0.515625
+vt 0.250000 0.515625
+vt 0.875000 0.515625
+vt 0.937500 0.515625
+vt 0.750000 0.515625
+vt 0.812500 0.515625
+vt 0.562500 0.515625
+vt 0.625000 0.515625
+vt 0.687500 0.515625
+vt 0.500000 0.515625
+vt 0.437500 0.515625
+vt 0.375000 0.515625
+vt 0.312500 0.515625
+vt 0.125000 0.515625
+vt 0.062500 0.515625
+vt 0.000000 0.515625
+vt 1.000000 0.515625
+usemtl None
+s off
+f 54/1 41/2 42/3 55/4
+f 31/5 33/6 50/7
+f 29/8 31/5 50/7
+f 27/9 29/8 50/7
+f 25/10 27/9 50/7
+f 23/11 25/10 50/7
+f 21/12 23/11 50/7
+f 19/13 21/12 50/7
+f 17/14 19/13 50/7
+f 15/15 17/14 50/7
+f 13/16 15/15 50/7
+f 11/17 13/16 50/7
+f 9/18 11/17 50/7
+f 7/19 9/18 50/7
+f 5/20 7/19 50/7
+f 35/21 5/20 50/7
+f 6/22 36/23 49/24
+f 8/25 6/22 49/24
+f 10/26 8/25 49/24
+f 12/27 10/26 49/24
+f 14/28 12/27 49/24
+f 16/29 14/28 49/24
+f 18/30 16/29 49/24
+f 20/31 18/30 49/24
+f 22/32 20/31 49/24
+f 24/33 22/32 49/24
+f 26/34 24/33 49/24
+f 28/35 26/34 49/24
+f 30/36 28/35 49/24
+f 32/37 30/36 49/24
+f 34/38 32/37 49/24
+f 36/23 34/38 49/24
+f 33/6 35/21 50/7
+f 8/39 7/40 5/41 6/42
+f 6/42 5/41 35/43 36/44
+f 10/45 9/46 7/40 8/39
+f 12/47 11/48 9/46 10/45
+f 14/49 13/50 11/51 12/52
+f 16/53 15/54 13/50 14/49
+f 18/55 17/56 15/54 16/53
+f 20/57 19/58 17/56 18/55
+f 22/59 21/60 19/58 20/57
+f 24/61 23/62 21/60 22/59
+f 26/63 25/64 23/62 24/61
+f 28/65 27/66 25/64 26/63
+f 30/67 29/68 27/66 28/65
+f 32/69 31/70 29/68 30/67
+f 34/71 33/72 31/70 32/69
+f 36/44 35/43 33/72 34/71
+f 65/73 1/74 37/75 66/76
+f 63/77 3/78 2/79 62/80
+f 61/81 47/82 48/83 60/84
+f 64/85 4/86 3/78 63/77
+f 62/80 2/79 1/74 65/73
+f 60/84 48/83 4/86 64/85
+f 59/87 46/88 47/82 61/81
+f 58/89 45/90 46/88 59/87
+f 57/91 44/92 45/90 58/89
+f 56/93 43/94 44/92 57/91
+f 55/4 42/3 43/94 56/93
+f 53/95 40/96 41/2 54/1
+f 52/97 39/98 40/96 53/95
+f 51/99 38/100 39/98 52/97
+f 66/76 37/75 38/101 51/102
+f 67/58 69/60 70/59 68/57
+f 69/60 71/62 72/61 70/59
+f 71/62 73/64 74/63 72/61
+f 73/64 75/66 76/65 74/63
+f 75/66 77/68 78/67 76/65
+f 77/68 79/70 80/69 78/67
+f 79/70 81/72 82/71 80/69
+f 81/72 83/43 84/44 82/71
+f 83/43 85/41 86/42 84/44
+f 85/41 87/40 88/39 86/42
+f 87/40 89/46 90/45 88/39
+f 89/46 91/48 92/47 90/45
+f 91/51 93/50 94/49 92/52
+f 93/50 95/54 96/53 94/49
+f 97/56 67/58 68/57 98/55
+f 95/54 97/56 98/55 96/53
+f 70/103 116/104 68/105
+f 67/106 115/107 69/108
+f 69/108 115/107 71/109
+f 71/109 115/107 73/110
+f 73/110 115/107 75/111
+f 75/111 115/107 77/112
+f 77/112 115/107 79/113
+f 79/113 115/107 81/114
+f 81/114 115/107 83/115
+f 83/115 115/107 85/116
+f 85/116 115/107 87/117
+f 87/117 115/107 89/118
+f 89/118 115/107 91/119
+f 91/119 115/107 93/120
+f 93/120 115/107 95/121
+f 95/121 115/107 97/122
+f 97/122 115/107 67/106
+f 68/105 116/104 98/123
+f 98/123 116/104 96/124
+f 96/124 116/104 94/125
+f 94/125 116/104 92/126
+f 92/126 116/104 90/127
+f 90/127 116/104 88/128
+f 88/128 116/104 86/129
+f 86/129 116/104 84/130
+f 84/130 116/104 82/131
+f 82/131 116/104 80/132
+f 80/132 116/104 78/133
+f 78/133 116/104 76/134
+f 76/134 116/104 74/135
+f 74/135 116/104 72/136
+f 72/136 116/104 70/103
+f 107/137 120/1 121/4 108/138
+f 102/139 131/73 132/76 103/140
+f 100/141 129/77 128/80 101/142
+f 113/143 127/81 126/84 114/144
+f 99/145 130/85 129/77 100/141
+f 101/142 128/80 131/73 102/139
+f 114/144 126/84 130/85 99/145
+f 112/146 125/87 127/81 113/143
+f 111/147 124/89 125/87 112/146
+f 110/148 123/91 124/89 111/147
+f 109/149 122/93 123/91 110/148
+f 108/138 121/4 122/93 109/149
+f 106/150 119/95 120/1 107/137
+f 105/151 118/97 119/95 106/150
+f 104/152 117/99 118/97 105/151
+f 103/140 132/76 117/102 104/153
+f 133/58 135/60 136/59 134/57
+f 135/60 137/62 138/61 136/59
+f 137/62 139/64 140/63 138/61
+f 139/64 141/66 142/65 140/63
+f 141/66 143/68 144/67 142/65
+f 143/68 145/70 146/69 144/67
+f 145/70 147/72 148/71 146/69
+f 147/72 149/43 150/44 148/71
+f 149/43 151/41 152/42 150/44
+f 151/41 153/40 154/39 152/42
+f 153/40 155/46 156/45 154/39
+f 155/46 157/48 158/47 156/45
+f 157/51 159/50 160/49 158/52
+f 159/50 161/54 162/53 160/49
+f 163/56 133/58 134/57 164/55
+f 161/54 163/56 164/55 162/53
+f 136/103 182/104 134/105
+f 133/106 181/107 135/108
+f 135/108 181/107 137/109
+f 137/109 181/107 139/110
+f 139/110 181/107 141/111
+f 141/111 181/107 143/112
+f 143/112 181/107 145/113
+f 145/113 181/107 147/114
+f 147/114 181/107 149/115
+f 149/115 181/107 151/116
+f 151/116 181/107 153/117
+f 153/117 181/107 155/118
+f 155/118 181/107 157/119
+f 157/119 181/107 159/120
+f 159/120 181/107 161/121
+f 161/121 181/107 163/122
+f 163/122 181/107 133/106
+f 134/105 182/104 164/123
+f 164/123 182/104 162/124
+f 162/124 182/104 160/125
+f 160/125 182/104 158/126
+f 158/126 182/104 156/127
+f 156/127 182/104 154/128
+f 154/128 182/104 152/129
+f 152/129 182/104 150/130
+f 150/130 182/104 148/131
+f 148/131 182/104 146/132
+f 146/132 182/104 144/133
+f 144/133 182/104 142/134
+f 142/134 182/104 140/135
+f 140/135 182/104 138/136
+f 138/136 182/104 136/103
+f 173/137 223/2 224/3 174/138
+f 213/5 215/6 232/7
+f 211/8 213/5 232/7
+f 209/9 211/8 232/7
+f 207/10 209/9 232/7
+f 205/11 207/10 232/7
+f 203/12 205/11 232/7
+f 201/13 203/12 232/7
+f 199/14 201/13 232/7
+f 197/15 199/14 232/7
+f 195/16 197/15 232/7
+f 193/17 195/16 232/7
+f 191/18 193/17 232/7
+f 189/19 191/18 232/7
+f 187/20 189/19 232/7
+f 217/21 187/20 232/7
+f 188/22 218/23 231/24
+f 190/25 188/22 231/24
+f 192/26 190/25 231/24
+f 194/27 192/26 231/24
+f 196/28 194/27 231/24
+f 198/29 196/28 231/24
+f 200/30 198/29 231/24
+f 202/31 200/30 231/24
+f 204/32 202/31 231/24
+f 206/33 204/32 231/24
+f 208/34 206/33 231/24
+f 210/35 208/34 231/24
+f 212/36 210/35 231/24
+f 214/37 212/36 231/24
+f 216/38 214/37 231/24
+f 218/23 216/38 231/24
+f 215/6 217/21 232/7
+f 190/39 189/40 187/41 188/42
+f 188/42 187/41 217/43 218/44
+f 192/45 191/46 189/40 190/39
+f 194/47 193/48 191/46 192/45
+f 196/49 195/50 193/51 194/52
+f 198/53 197/54 195/50 196/49
+f 200/55 199/56 197/54 198/53
+f 202/57 201/58 199/56 200/55
+f 204/59 203/60 201/58 202/57
+f 206/61 205/62 203/60 204/59
+f 208/63 207/64 205/62 206/61
+f 210/65 209/66 207/64 208/63
+f 212/67 211/68 209/66 210/65
+f 214/69 213/70 211/68 212/67
+f 216/71 215/72 213/70 214/69
+f 218/44 217/43 215/72 216/71
+f 168/139 183/74 219/75 169/140
+f 166/141 185/78 184/79 167/142
+f 179/143 229/82 230/83 180/144
+f 165/145 186/86 185/78 166/141
+f 167/142 184/79 183/74 168/139
+f 180/144 230/83 186/86 165/145
+f 178/146 228/88 229/82 179/143
+f 177/147 227/90 228/88 178/146
+f 176/148 226/92 227/90 177/147
+f 175/149 225/94 226/92 176/148
+f 174/138 224/3 225/94 175/149
+f 172/150 222/96 223/2 173/137
+f 171/151 221/98 222/96 172/150
+f 170/152 220/100 221/98 171/151
+f 169/140 219/75 220/101 170/153
+f 286/1 273/2 274/3 287/4
+f 263/5 265/6 282/7
+f 261/8 263/5 282/7
+f 259/9 261/8 282/7
+f 257/10 259/9 282/7
+f 255/11 257/10 282/7
+f 253/12 255/11 282/7
+f 251/13 253/12 282/7
+f 249/14 251/13 282/7
+f 247/15 249/14 282/7
+f 245/16 247/15 282/7
+f 243/17 245/16 282/7
+f 241/18 243/17 282/7
+f 239/19 241/18 282/7
+f 237/20 239/19 282/7
+f 267/21 237/20 282/7
+f 238/22 268/23 281/24
+f 240/25 238/22 281/24
+f 242/26 240/25 281/24
+f 244/27 242/26 281/24
+f 246/28 244/27 281/24
+f 248/29 246/28 281/24
+f 250/30 248/29 281/24
+f 252/31 250/30 281/24
+f 254/32 252/31 281/24
+f 256/33 254/32 281/24
+f 258/34 256/33 281/24
+f 260/35 258/34 281/24
+f 262/36 260/35 281/24
+f 264/37 262/36 281/24
+f 266/38 264/37 281/24
+f 268/23 266/38 281/24
+f 265/6 267/21 282/7
+f 240/39 239/40 237/41 238/42
+f 238/42 237/41 267/43 268/44
+f 242/45 241/46 239/40 240/39
+f 244/47 243/48 241/46 242/45
+f 246/49 245/50 243/51 244/52
+f 248/53 247/54 245/50 246/49
+f 250/55 249/56 247/54 248/53
+f 252/57 251/58 249/56 250/55
+f 254/59 253/60 251/58 252/57
+f 256/61 255/62 253/60 254/59
+f 258/63 257/64 255/62 256/61
+f 260/65 259/66 257/64 258/63
+f 262/67 261/68 259/66 260/65
+f 264/69 263/70 261/68 262/67
+f 266/71 265/72 263/70 264/69
+f 268/44 267/43 265/72 266/71
+f 297/73 233/74 269/75 298/76
+f 295/77 235/78 234/79 294/80
+f 293/81 279/82 280/83 292/84
+f 296/85 236/86 235/78 295/77
+f 294/80 234/79 233/74 297/73
+f 292/84 280/83 236/86 296/85
+f 291/87 278/88 279/82 293/81
+f 290/89 277/90 278/88 291/87
+f 289/91 276/92 277/90 290/89
+f 288/93 275/94 276/92 289/91
+f 287/4 274/3 275/94 288/93
+f 285/95 272/96 273/2 286/1
+f 284/97 271/98 272/96 285/95
+f 283/99 270/100 271/98 284/97
+f 298/76 269/75 270/101 283/102
+f 299/58 301/60 302/59 300/57
+f 301/60 303/62 304/61 302/59
+f 303/62 305/64 306/63 304/61
+f 305/64 307/66 308/65 306/63
+f 307/66 309/68 310/67 308/65
+f 309/68 311/70 312/69 310/67
+f 311/70 313/72 314/71 312/69
+f 313/72 315/43 316/44 314/71
+f 315/43 317/41 318/42 316/44
+f 317/41 319/40 320/39 318/42
+f 319/40 321/46 322/45 320/39
+f 321/46 323/48 324/47 322/45
+f 323/51 325/50 326/49 324/52
+f 325/50 327/54 328/53 326/49
+f 329/56 299/58 300/57 330/55
+f 327/54 329/56 330/55 328/53
+f 302/103 348/104 300/105
+f 299/106 347/107 301/108
+f 301/108 347/107 303/109
+f 303/109 347/107 305/110
+f 305/110 347/107 307/111
+f 307/111 347/107 309/112
+f 309/112 347/107 311/113
+f 311/113 347/107 313/114
+f 313/114 347/107 315/115
+f 315/115 347/107 317/116
+f 317/116 347/107 319/117
+f 319/117 347/107 321/118
+f 321/118 347/107 323/119
+f 323/119 347/107 325/120
+f 325/120 347/107 327/121
+f 327/121 347/107 329/122
+f 329/122 347/107 299/106
+f 300/105 348/104 330/123
+f 330/123 348/104 328/124
+f 328/124 348/104 326/125
+f 326/125 348/104 324/126
+f 324/126 348/104 322/127
+f 322/127 348/104 320/128
+f 320/128 348/104 318/129
+f 318/129 348/104 316/130
+f 316/130 348/104 314/131
+f 314/131 348/104 312/132
+f 312/132 348/104 310/133
+f 310/133 348/104 308/134
+f 308/134 348/104 306/135
+f 306/135 348/104 304/136
+f 304/136 348/104 302/103
+f 339/137 352/1 353/4 340/138
+f 334/139 363/73 364/76 335/140
+f 332/141 361/77 360/80 333/142
+f 345/143 359/81 358/84 346/144
+f 331/145 362/85 361/77 332/141
+f 333/142 360/80 363/73 334/139
+f 346/144 358/84 362/85 331/145
+f 344/146 357/87 359/81 345/143
+f 343/147 356/89 357/87 344/146
+f 342/148 355/91 356/89 343/147
+f 341/149 354/93 355/91 342/148
+f 340/138 353/4 354/93 341/149
+f 338/150 351/95 352/1 339/137
+f 337/151 350/97 351/95 338/150
+f 336/152 349/99 350/97 337/151
+f 335/140 364/76 349/102 336/153
diff --git a/pipeworks/models/pipeworks_pipe_2.obj b/pipeworks/models/pipeworks_pipe_2.obj
new file mode 100644
index 0000000..c75bca4
--- /dev/null
+++ b/pipeworks/models/pipeworks_pipe_2.obj
@@ -0,0 +1,392 @@
+# Blender v2.69 (sub 0) OBJ File: 'pipe-stub-end.blend'
+# www.blender.org
+o pipe.001_Cylinder.000
+v 0.024386 -0.024391 0.122598
+v 0.024386 -0.024391 -0.122598
+v 0.468750 -0.024387 0.122599
+v 0.468750 0.024386 0.122599
+v 0.024391 0.024386 0.122598
+v 0.500000 -0.086808 -0.129917
+v 0.500000 -0.030483 -0.153247
+v 0.500000 -0.000000 0.000001
+v 0.500000 -0.129917 -0.086807
+v 0.500000 -0.153248 -0.030482
+v 0.500000 -0.153248 0.030483
+v 0.500000 -0.129917 0.086808
+v 0.500000 -0.086808 0.129918
+v 0.500000 -0.030483 0.153248
+v 0.500000 0.030483 0.153248
+v 0.500000 0.086808 0.129918
+v 0.500000 0.129917 0.086808
+v 0.500000 0.153247 0.030483
+v 0.500000 0.153247 -0.030482
+v 0.500000 0.129917 -0.086807
+v 0.500000 0.086808 -0.129917
+v 0.500000 0.030483 -0.153247
+v 0.468750 0.086808 -0.129917
+v 0.468750 0.030483 -0.153247
+v 0.468750 -0.000000 -0.000000
+v 0.468750 0.129917 -0.086807
+v 0.468750 0.153247 -0.030482
+v 0.468750 0.153247 0.030483
+v 0.468750 0.129917 0.086808
+v 0.468750 0.086808 0.129918
+v 0.468750 0.030483 0.153248
+v 0.468750 -0.030483 0.153248
+v 0.468750 -0.086808 0.129918
+v 0.468750 -0.129917 0.086808
+v 0.468750 -0.153248 0.030483
+v 0.468750 -0.153248 -0.030482
+v 0.468750 -0.129917 -0.086807
+v 0.468750 -0.086808 -0.129917
+v 0.468750 -0.030483 -0.153247
+v 0.024391 -0.103934 -0.069446
+v 0.468750 -0.103934 -0.069446
+v 0.468750 -0.122598 -0.024386
+v 0.024391 -0.122598 -0.024386
+v 0.468750 -0.024387 -0.122598
+v 0.468750 -0.069447 -0.103933
+v 0.024391 -0.069446 -0.103934
+v 0.468750 0.103933 -0.069446
+v 0.468750 0.069446 -0.103933
+v 0.024391 0.069446 -0.103934
+v 0.024391 0.024386 -0.122598
+v 0.468750 0.024386 -0.122598
+v 0.024391 0.122598 -0.024386
+v 0.468750 0.122598 -0.024386
+v 0.024391 0.122598 0.024386
+v 0.468750 0.122598 0.024387
+v 0.024391 0.103934 0.069446
+v 0.468750 0.103933 0.069447
+v 0.024391 0.069446 0.103934
+v 0.468750 0.069446 0.103934
+v 0.024391 -0.069446 0.103934
+v 0.468750 -0.069447 0.103934
+v 0.024391 -0.103934 0.069446
+v 0.468750 -0.103934 0.069447
+v 0.024391 -0.122598 0.024386
+v 0.468750 -0.122598 0.024387
+v 0.024390 0.103934 -0.069446
+v -0.042016 -0.000000 0.000000
+v -0.034206 -0.012195 0.061299
+v -0.034203 -0.034723 0.051967
+v -0.034203 -0.061299 0.012193
+v -0.034203 -0.061299 -0.012193
+v -0.034203 -0.051967 -0.034723
+v -0.034203 -0.051967 0.034723
+v -0.034203 -0.034723 -0.051967
+v -0.034206 -0.012196 -0.061299
+v -0.034203 0.012193 -0.061299
+v -0.034203 0.034723 -0.051967
+v -0.034203 0.051967 -0.034723
+v -0.034203 0.061299 -0.012193
+v -0.034203 0.061299 0.012193
+v -0.034203 0.051967 0.034723
+v -0.034203 0.034723 0.051967
+v -0.034203 0.012193 0.061299
+v -0.042017 -0.006098 0.030650
+v -0.042016 -0.017362 0.025984
+v -0.042016 -0.030650 0.006097
+v -0.042016 -0.030650 -0.006096
+v -0.042016 -0.025984 -0.017361
+v -0.014672 -0.077950 0.052085
+v -0.042016 -0.017362 -0.025983
+v -0.042017 -0.006098 -0.030649
+v -0.042016 0.006096 -0.030649
+v -0.042016 0.017361 -0.025983
+v -0.042016 0.025983 -0.017362
+v -0.042016 0.030649 -0.006096
+v -0.042016 0.030649 0.006097
+v -0.042016 0.025983 0.017362
+v -0.042016 0.017361 0.025984
+v -0.042016 0.006096 0.030650
+v -0.014675 -0.018293 0.091949
+v -0.014672 -0.052084 0.077951
+v -0.014672 -0.091948 0.018290
+v -0.014672 -0.091949 -0.018289
+v -0.014672 -0.077951 -0.052084
+v -0.042016 -0.025984 0.017362
+v -0.014672 -0.052085 -0.077950
+v -0.014675 -0.018293 -0.091948
+v -0.014672 0.018289 -0.091948
+v -0.014672 0.052084 -0.077950
+v -0.014672 0.077950 -0.052085
+v -0.014672 0.091948 -0.018289
+v -0.014672 0.091949 0.018290
+v -0.014672 0.077951 0.052085
+v -0.014672 0.052085 0.077951
+v -0.014672 0.018290 0.091949
+vt 0.093322 0.682190
+vt 0.153370 0.657318
+vt 0.185867 0.820694
+vt 0.047364 0.728149
+vt 0.022491 0.788196
+vt 0.022491 0.853192
+vt 0.047364 0.913239
+vt 0.093322 0.959198
+vt 0.153370 0.984070
+vt 0.218365 0.984070
+vt 0.278413 0.959198
+vt 0.324371 0.913239
+vt 0.349244 0.853192
+vt 0.349244 0.788196
+vt 0.324371 0.728149
+vt 0.278413 0.682190
+vt 0.218365 0.657318
+vt 0.471785 0.682190
+vt 0.531832 0.657318
+vt 0.564330 0.820694
+vt 0.425826 0.728149
+vt 0.400953 0.788196
+vt 0.400953 0.853192
+vt 0.425826 0.913239
+vt 0.471785 0.959198
+vt 0.531832 0.984070
+vt 0.596827 0.984070
+vt 0.656875 0.959198
+vt 0.702834 0.913239
+vt 0.727706 0.853192
+vt 0.727706 0.788196
+vt 0.702834 0.728149
+vt 0.656875 0.682190
+vt 0.596827 0.657318
+vt 0.125000 0.609375
+vt 0.125000 0.546875
+vt 0.187500 0.546875
+vt 0.187500 0.609375
+vt 0.250000 0.546875
+vt 0.250000 0.609375
+vt 0.062500 0.609375
+vt 0.062500 0.546875
+vt 0.000000 0.609375
+vt 0.000000 0.546875
+vt 0.937500 0.609375
+vt 0.937500 0.546875
+vt 1.000000 0.546875
+vt 1.000000 0.609375
+vt 0.875000 0.609375
+vt 0.875000 0.546875
+vt 0.812500 0.609375
+vt 0.812500 0.546875
+vt 0.750000 0.609375
+vt 0.750000 0.546875
+vt 0.687500 0.609375
+vt 0.687500 0.546875
+vt 0.625000 0.609375
+vt 0.625000 0.546875
+vt 0.562500 0.609375
+vt 0.562500 0.546875
+vt 0.500000 0.609375
+vt 0.500000 0.546875
+vt 0.437500 0.609375
+vt 0.437500 0.546875
+vt 0.375000 0.609375
+vt 0.375000 0.546875
+vt 0.312500 0.609375
+vt 0.312500 0.546875
+vt 0.875000 0.265625
+vt 0.875000 0.015625
+vt 0.937500 0.015625
+vt 0.937500 0.265625
+vt 0.812500 0.265625
+vt 0.812500 0.015625
+vt 0.625000 0.265625
+vt 0.625000 0.015625
+vt 0.687500 0.015625
+vt 0.687500 0.265625
+vt 0.437500 0.265625
+vt 0.437500 0.015625
+vt 0.500000 0.015625
+vt 0.500000 0.265625
+vt 0.375000 0.265625
+vt 0.375000 0.015625
+vt 0.312500 0.265625
+vt 0.312500 0.015625
+vt 0.250000 0.265625
+vt 0.250000 0.015625
+vt 0.062500 0.265625
+vt 0.062500 0.015625
+vt 0.125000 0.015625
+vt 0.125000 0.265625
+vt 0.000000 0.265625
+vt 0.000000 0.015625
+vt 1.000000 0.015625
+vt 1.000000 0.265625
+vt 0.187500 0.265625
+vt 0.187500 0.015625
+vt 0.750000 0.265625
+vt 0.750000 0.015625
+vt 0.562500 0.265625
+vt 0.562500 0.015625
+vt 0.648437 0.265625
+vt 0.414062 0.265625
+vt 0.531250 0.265625
+vt 0.632812 0.265625
+vt 0.617187 0.265625
+vt 0.601562 0.265625
+vt 0.585937 0.265625
+vt 0.570312 0.265625
+vt 0.554687 0.265625
+vt 0.539062 0.265625
+vt 0.523437 0.265625
+vt 0.507812 0.265625
+vt 0.492187 0.265625
+vt 0.476562 0.265625
+vt 0.460937 0.265625
+vt 0.445312 0.265625
+vt 0.429687 0.265625
+vt 0.882812 0.265625
+vt 0.179687 0.265625
+vt 0.296875 0.265625
+vt 0.765625 0.265625
+vt 0.835937 0.265625
+vt 0.734375 0.265625
+vt 0.789062 0.265625
+vt 0.703125 0.265625
+vt 0.742187 0.265625
+vt 0.671875 0.265625
+vt 0.695312 0.265625
+vt 0.640625 0.265625
+vt 0.609375 0.265625
+vt 0.578125 0.265625
+vt 0.546875 0.265625
+vt 0.515625 0.265625
+vt 0.484375 0.265625
+vt 0.453125 0.265625
+vt 0.367187 0.265625
+vt 0.421875 0.265625
+vt 0.320312 0.265625
+vt 0.390625 0.265625
+vt 0.273437 0.265625
+vt 0.359375 0.265625
+vt 0.226562 0.265625
+vt 0.328125 0.265625
+s off
+f 6/1 7/2 8/3
+f 9/4 6/1 8/3
+f 10/5 9/4 8/3
+f 11/6 10/5 8/3
+f 12/7 11/6 8/3
+f 13/8 12/7 8/3
+f 14/9 13/8 8/3
+f 15/10 14/9 8/3
+f 16/11 15/10 8/3
+f 17/12 16/11 8/3
+f 18/13 17/12 8/3
+f 19/14 18/13 8/3
+f 20/15 19/14 8/3
+f 21/16 20/15 8/3
+f 22/17 21/16 8/3
+f 23/18 24/19 25/20
+f 26/21 23/18 25/20
+f 27/22 26/21 25/20
+f 28/23 27/22 25/20
+f 29/24 28/23 25/20
+f 30/25 29/24 25/20
+f 31/26 30/25 25/20
+f 32/27 31/26 25/20
+f 33/28 32/27 25/20
+f 34/29 33/28 25/20
+f 35/30 34/29 25/20
+f 36/31 35/30 25/20
+f 37/32 36/31 25/20
+f 38/33 37/32 25/20
+f 39/34 38/33 25/20
+f 24/19 39/34 25/20
+f 7/2 22/17 8/3
+f 26/35 20/36 21/37 23/38
+f 23/38 21/37 22/39 24/40
+f 27/41 19/42 20/36 26/35
+f 28/43 18/44 19/42 27/41
+f 29/45 17/46 18/47 28/48
+f 30/49 16/50 17/46 29/45
+f 31/51 15/52 16/50 30/49
+f 32/53 14/54 15/52 31/51
+f 33/55 13/56 14/54 32/53
+f 34/57 12/58 13/56 33/55
+f 35/59 11/60 12/58 34/57
+f 36/61 10/62 11/60 35/59
+f 37/63 9/64 10/62 36/61
+f 38/65 6/66 9/64 37/63
+f 39/67 7/68 6/66 38/65
+f 24/40 22/39 7/68 39/67
+f 40/69 41/70 42/71 43/72
+f 46/73 45/74 41/70 40/69
+f 49/75 48/76 51/77 50/78
+f 54/79 55/80 53/81 52/82
+f 56/83 57/84 55/80 54/79
+f 58/85 59/86 57/84 56/83
+f 5/87 4/88 59/86 58/85
+f 62/89 63/90 61/91 60/92
+f 64/93 65/94 63/90 62/89
+f 43/72 42/71 65/95 64/96
+f 1/97 3/98 4/88 5/87
+f 2/99 44/100 45/74 46/73
+f 66/101 47/102 48/76 49/75
+f 50/78 51/77 44/100 2/99
+f 52/82 53/81 47/102 66/101
+f 60/92 61/91 3/98 1/97
+f 86/103 105/104 67/105
+f 87/106 86/103 67/105
+f 88/107 87/106 67/105
+f 90/108 88/107 67/105
+f 91/109 90/108 67/105
+f 92/110 91/109 67/105
+f 93/111 92/110 67/105
+f 94/112 93/111 67/105
+f 95/113 94/112 67/105
+f 96/114 95/113 67/105
+f 97/115 96/114 67/105
+f 98/116 97/115 67/105
+f 99/117 98/116 67/105
+f 84/118 99/117 67/105
+f 85/119 84/118 67/105
+f 105/104 85/119 67/105
+f 102/120 89/121 73/122 70/123
+f 103/124 102/120 70/123 71/125
+f 104/126 103/124 71/125 72/127
+f 106/128 104/126 72/127 74/129
+f 107/130 106/128 74/129 75/131
+f 108/103 107/130 75/131 76/132
+f 109/108 108/103 76/132 77/133
+f 110/111 109/108 77/133 78/134
+f 111/114 110/111 78/134 79/135
+f 112/117 111/114 79/135 80/136
+f 113/104 112/117 80/136 81/137
+f 114/138 113/104 81/137 82/139
+f 115/140 114/138 82/139 83/141
+f 100/142 115/140 83/141 68/143
+f 101/144 100/142 68/143 69/145
+f 89/121 101/144 69/145 73/122
+f 70/123 73/122 105/104 86/103
+f 71/125 70/123 86/103 87/106
+f 72/127 71/125 87/106 88/107
+f 74/129 72/127 88/107 90/108
+f 75/131 74/129 90/108 91/109
+f 76/132 75/131 91/109 92/110
+f 77/133 76/132 92/110 93/111
+f 78/134 77/133 93/111 94/112
+f 79/135 78/134 94/112 95/113
+f 80/136 79/135 95/113 96/114
+f 81/137 80/136 96/114 97/115
+f 82/139 81/137 97/115 98/116
+f 83/141 82/139 98/116 99/117
+f 68/143 83/141 99/117 84/118
+f 69/145 68/143 84/118 85/119
+f 73/122 69/145 85/119 105/104
+f 64/96 62/89 89/121 102/120
+f 43/72 64/96 102/120 103/124
+f 40/69 43/72 103/124 104/126
+f 46/73 40/69 104/126 106/128
+f 2/99 46/73 106/128 107/130
+f 50/78 2/99 107/130 108/103
+f 49/75 50/78 108/103 109/108
+f 66/101 49/75 109/108 110/111
+f 52/82 66/101 110/111 111/114
+f 54/79 52/82 111/114 112/117
+f 56/83 54/79 112/117 113/104
+f 58/85 56/83 113/104 114/138
+f 5/87 58/85 114/138 115/140
+f 1/97 5/87 115/140 100/142
+f 60/92 1/97 100/142 101/144
+f 62/89 60/92 101/144 89/121
diff --git a/pipeworks/models/pipeworks_pipe_3.obj b/pipeworks/models/pipeworks_pipe_3.obj
new file mode 100644
index 0000000..f126551
--- /dev/null
+++ b/pipeworks/models/pipeworks_pipe_3.obj
@@ -0,0 +1,354 @@
+# Blender v2.69 (sub 0) OBJ File: 'pipe-2way-straight.blend'
+# www.blender.org
+mtllib pipeworks_pipe_3.mtl
+o Cube.001
+v 0.468750 -0.153248 0.030483
+v 0.500000 -0.153248 0.030483
+v 0.468750 -0.153248 -0.030483
+v 0.500000 -0.153248 -0.030483
+v 0.468750 -0.129917 -0.086808
+v 0.500000 -0.129917 -0.086808
+v 0.468750 -0.086808 -0.129917
+v 0.500000 -0.086808 -0.129917
+v 0.468750 -0.030483 -0.153248
+v 0.500000 -0.030483 -0.153248
+v 0.468750 0.030483 -0.153248
+v 0.500000 0.030483 -0.153248
+v 0.468750 0.086808 -0.129917
+v 0.500000 0.086808 -0.129917
+v 0.468750 0.129917 -0.086808
+v 0.500000 0.129917 -0.086808
+v 0.468750 0.153248 -0.030483
+v 0.500000 0.153247 -0.030483
+v 0.468750 0.153248 0.030483
+v 0.500000 0.153248 0.030483
+v 0.468750 0.129917 0.086808
+v 0.500000 0.129917 0.086808
+v 0.468750 0.086808 0.129917
+v 0.500000 0.086808 0.129917
+v 0.468750 0.030483 0.153248
+v 0.500000 0.030483 0.153248
+v 0.468750 -0.030483 0.153248
+v 0.500000 -0.030483 0.153248
+v 0.468750 -0.086808 0.129917
+v 0.500000 -0.086808 0.129917
+v 0.468750 -0.129917 0.086808
+v 0.500000 -0.129917 0.086808
+v 0.468750 -0.122598 0.024386
+v 0.468750 -0.122598 -0.024386
+v 0.468750 -0.103934 -0.069446
+v 0.468750 -0.069446 -0.103934
+v 0.468750 -0.024386 -0.122598
+v 0.468750 0.024386 -0.122598
+v 0.468750 0.069446 -0.103934
+v 0.468750 0.103934 -0.069446
+v 0.468750 0.122598 -0.024386
+v 0.468750 0.122598 0.024386
+v 0.468750 0.103934 0.069446
+v 0.468750 0.069446 0.103934
+v 0.468750 0.024386 0.122598
+v 0.468750 -0.024387 0.122598
+v 0.468750 -0.069447 0.103934
+v 0.468750 -0.103934 0.069446
+v 0.468750 -0.000000 -0.000000
+v 0.500000 -0.000000 0.000000
+v -0.468750 -0.069446 -0.103934
+v -0.468750 -0.103933 -0.069446
+v -0.468750 -0.122598 -0.024387
+v -0.468750 -0.122598 0.024386
+v -0.500000 -0.129917 0.086808
+v -0.468750 -0.129917 0.086808
+v -0.500000 -0.086808 0.129917
+v -0.468750 -0.086808 0.129917
+v -0.500000 -0.030483 0.153247
+v -0.468750 -0.030483 0.153248
+v -0.500000 0.030483 0.153247
+v -0.468750 0.030483 0.153248
+v -0.500000 0.086808 0.129917
+v -0.468750 0.086808 0.129917
+v -0.500000 0.129917 0.086808
+v -0.468750 0.129917 0.086808
+v -0.500000 0.153248 0.030483
+v -0.468750 0.153248 0.030483
+v -0.500000 0.153248 -0.030483
+v -0.468750 0.153248 -0.030483
+v -0.500000 0.129917 -0.086808
+v -0.468750 0.129917 -0.086808
+v -0.500000 0.086808 -0.129917
+v -0.468750 0.086808 -0.129917
+v -0.500000 0.030483 -0.153248
+v -0.468750 0.030483 -0.153248
+v -0.500000 -0.030483 -0.153248
+v -0.468750 -0.030483 -0.153248
+v -0.500000 -0.086808 -0.129917
+v -0.468750 -0.086808 -0.129917
+v -0.500000 -0.129917 -0.086808
+v -0.468750 -0.129917 -0.086808
+v -0.500000 -0.153247 -0.030483
+v -0.468750 -0.153247 -0.030483
+v -0.500000 -0.153247 0.030483
+v -0.468750 -0.153247 0.030483
+v -0.468750 -0.024386 -0.122598
+v -0.468750 0.024387 -0.122598
+v -0.468750 0.069447 -0.103934
+v -0.468750 0.103934 -0.069446
+v -0.468750 0.122598 -0.024386
+v -0.468750 0.122598 0.024386
+v -0.468750 0.103934 0.069446
+v -0.468750 0.069447 0.103934
+v -0.468750 0.024387 0.122598
+v -0.468750 -0.024386 0.122598
+v -0.468750 -0.069446 0.103933
+v -0.468750 -0.103933 0.069446
+v -0.468750 0.000000 -0.000000
+v -0.500000 0.000000 -0.000000
+vt 0.750000 0.546875
+vt 0.687500 0.546875
+vt 0.687500 0.609375
+vt 0.750000 0.609375
+vt 0.625000 0.546875
+vt 0.625000 0.609375
+vt 0.562500 0.546875
+vt 0.562500 0.609375
+vt 0.500000 0.546875
+vt 0.500000 0.609375
+vt 0.437500 0.546875
+vt 0.437500 0.609375
+vt 0.375000 0.546875
+vt 0.375000 0.609375
+vt 0.312500 0.546875
+vt 0.312500 0.609375
+vt 0.250000 0.546875
+vt 0.250000 0.609375
+vt 0.187500 0.546875
+vt 0.187500 0.609375
+vt 0.125000 0.546875
+vt 0.125000 0.609375
+vt 0.062500 0.546875
+vt 0.062500 0.609375
+vt 0.000000 0.546875
+vt 0.000000 0.609375
+vt 1.000000 0.546875
+vt 0.937500 0.546875
+vt 0.937500 0.609375
+vt 1.000000 0.609375
+vt 0.875000 0.546875
+vt 0.875000 0.609375
+vt 0.812500 0.546875
+vt 0.812500 0.609375
+vt 0.218363 0.657325
+vt 0.185866 0.820702
+vt 0.153368 0.657325
+vt 0.531836 0.657325
+vt 0.564334 0.820702
+vt 0.596832 0.657325
+vt 0.656879 0.682198
+vt 0.702838 0.728156
+vt 0.727710 0.788204
+vt 0.727710 0.853199
+vt 0.702838 0.913247
+vt 0.656879 0.959205
+vt 0.596831 0.984078
+vt 0.531836 0.984078
+vt 0.471788 0.959205
+vt 0.425830 0.913247
+vt 0.400957 0.853199
+vt 0.400957 0.788204
+vt 0.425830 0.728156
+vt 0.471789 0.682198
+vt 0.093321 0.682198
+vt 0.047362 0.728156
+vt 0.022489 0.788204
+vt 0.022489 0.853199
+vt 0.047362 0.913247
+vt 0.093320 0.959205
+vt 0.153368 0.984078
+vt 0.218363 0.984078
+vt 0.278411 0.959205
+vt 0.324369 0.913247
+vt 0.349242 0.853199
+vt 0.349242 0.788204
+vt 0.324369 0.728156
+vt 0.278411 0.682198
+vt 0.187500 0.515625
+vt 0.187500 0.015625
+vt 0.250000 0.015625
+vt 0.250000 0.515625
+vt 0.093322 0.682190
+vt 0.153370 0.657318
+vt 0.185867 0.820694
+vt 0.047364 0.728149
+vt 0.022491 0.788196
+vt 0.022491 0.853192
+vt 0.047364 0.913239
+vt 0.093322 0.959198
+vt 0.153370 0.984070
+vt 0.218365 0.984070
+vt 0.278413 0.959198
+vt 0.324371 0.913239
+vt 0.349244 0.853192
+vt 0.349244 0.788196
+vt 0.324371 0.728149
+vt 0.278413 0.682190
+vt 0.218365 0.657318
+vt 0.471785 0.682190
+vt 0.531832 0.657318
+vt 0.564330 0.820694
+vt 0.425826 0.728149
+vt 0.400953 0.788196
+vt 0.400953 0.853192
+vt 0.425826 0.913239
+vt 0.471785 0.959198
+vt 0.531832 0.984070
+vt 0.596827 0.984070
+vt 0.656875 0.959198
+vt 0.702834 0.913239
+vt 0.727706 0.853192
+vt 0.727706 0.788196
+vt 0.702834 0.728149
+vt 0.656875 0.682190
+vt 0.596827 0.657318
+vt 0.875000 0.515625
+vt 0.875000 0.015625
+vt 0.937500 0.015625
+vt 0.937500 0.515625
+vt 0.750000 0.515625
+vt 0.750000 0.015625
+vt 0.812500 0.015625
+vt 0.812500 0.515625
+vt 0.562500 0.515625
+vt 0.562500 0.015625
+vt 0.625000 0.015625
+vt 0.625000 0.515625
+vt 0.687500 0.515625
+vt 0.687500 0.015625
+vt 0.500000 0.515625
+vt 0.500000 0.015625
+vt 0.437500 0.515625
+vt 0.437500 0.015625
+vt 0.375000 0.515625
+vt 0.375000 0.015625
+vt 0.312500 0.515625
+vt 0.312500 0.015625
+vt 0.125000 0.515625
+vt 0.125000 0.015625
+vt 0.062500 0.515625
+vt 0.062500 0.015625
+vt 0.000000 0.515625
+vt 0.000000 0.015625
+vt 1.000000 0.015625
+vt 1.000000 0.515625
+usemtl None
+s off
+f 1/1 3/2 4/3 2/4
+f 3/2 5/5 6/6 4/3
+f 5/5 7/7 8/8 6/6
+f 7/7 9/9 10/10 8/8
+f 9/9 11/11 12/12 10/10
+f 11/11 13/13 14/14 12/12
+f 13/13 15/15 16/16 14/14
+f 15/15 17/17 18/18 16/16
+f 17/17 19/19 20/20 18/18
+f 19/19 21/21 22/22 20/20
+f 21/21 23/23 24/24 22/22
+f 23/23 25/25 26/26 24/24
+f 25/27 27/28 28/29 26/30
+f 27/28 29/31 30/32 28/29
+f 31/33 1/1 2/4 32/34
+f 29/31 31/33 32/34 30/32
+f 4/35 50/36 2/37
+f 1/38 49/39 3/40
+f 3/40 49/39 5/41
+f 5/41 49/39 7/42
+f 7/42 49/39 9/43
+f 9/43 49/39 11/44
+f 11/44 49/39 13/45
+f 13/45 49/39 15/46
+f 15/46 49/39 17/47
+f 17/47 49/39 19/48
+f 19/48 49/39 21/49
+f 21/49 49/39 23/50
+f 23/50 49/39 25/51
+f 25/51 49/39 27/52
+f 27/52 49/39 29/53
+f 29/53 49/39 31/54
+f 31/54 49/39 1/38
+f 2/37 50/36 32/55
+f 32/55 50/36 30/56
+f 30/56 50/36 28/57
+f 28/57 50/36 26/58
+f 26/58 50/36 24/59
+f 24/59 50/36 22/60
+f 22/60 50/36 20/61
+f 20/61 50/36 18/62
+f 18/62 50/36 16/63
+f 16/63 50/36 14/64
+f 14/64 50/36 12/65
+f 12/65 50/36 10/66
+f 10/66 50/36 8/67
+f 8/67 50/36 6/68
+f 6/68 50/36 4/35
+f 41/69 91/70 92/71 42/72
+f 81/73 83/74 100/75
+f 79/76 81/73 100/75
+f 77/77 79/76 100/75
+f 75/78 77/77 100/75
+f 73/79 75/78 100/75
+f 71/80 73/79 100/75
+f 69/81 71/80 100/75
+f 67/82 69/81 100/75
+f 65/83 67/82 100/75
+f 63/84 65/83 100/75
+f 61/85 63/84 100/75
+f 59/86 61/85 100/75
+f 57/87 59/86 100/75
+f 55/88 57/87 100/75
+f 85/89 55/88 100/75
+f 56/90 86/91 99/92
+f 58/93 56/90 99/92
+f 60/94 58/93 99/92
+f 62/95 60/94 99/92
+f 64/96 62/95 99/92
+f 66/97 64/96 99/92
+f 68/98 66/97 99/92
+f 70/99 68/98 99/92
+f 72/100 70/99 99/92
+f 74/101 72/100 99/92
+f 76/102 74/101 99/92
+f 78/103 76/102 99/92
+f 80/104 78/103 99/92
+f 82/105 80/104 99/92
+f 84/106 82/105 99/92
+f 86/91 84/106 99/92
+f 83/74 85/89 100/75
+f 58/22 57/21 55/19 56/20
+f 56/20 55/19 85/17 86/18
+f 60/24 59/23 57/21 58/22
+f 62/26 61/25 59/23 60/24
+f 64/29 63/28 61/27 62/30
+f 66/32 65/31 63/28 64/29
+f 68/34 67/33 65/31 66/32
+f 70/4 69/1 67/33 68/34
+f 72/3 71/2 69/1 70/4
+f 74/6 73/5 71/2 72/3
+f 76/8 75/7 73/5 74/6
+f 78/10 77/9 75/7 76/8
+f 80/12 79/11 77/9 78/10
+f 82/14 81/13 79/11 80/12
+f 84/16 83/15 81/13 82/14
+f 86/18 85/17 83/15 84/16
+f 36/107 51/108 87/109 37/110
+f 34/111 53/112 52/113 35/114
+f 47/115 97/116 98/117 48/118
+f 33/119 54/120 53/112 34/111
+f 35/114 52/113 51/108 36/107
+f 48/118 98/117 54/120 33/119
+f 46/121 96/122 97/116 47/115
+f 45/123 95/124 96/122 46/121
+f 44/125 94/126 95/124 45/123
+f 43/127 93/128 94/126 44/125
+f 42/72 92/71 93/128 43/127
+f 40/129 90/130 91/70 41/69
+f 39/131 89/132 90/130 40/129
+f 38/133 88/134 89/132 39/131
+f 37/110 87/109 88/135 38/136
diff --git a/pipeworks/models/pipeworks_pipe_4.obj b/pipeworks/models/pipeworks_pipe_4.obj
new file mode 100644
index 0000000..0ef583f
--- /dev/null
+++ b/pipeworks/models/pipeworks_pipe_4.obj
@@ -0,0 +1,478 @@
+# Blender v2.69 (sub 0) OBJ File: 'pipe-2way-corner.blend'
+# www.blender.org
+mtllib pipeworks_pipe_4.mtl
+o pipe.001_Cylinder.000
+v -0.024386 -0.024391 0.122598
+v -0.024387 -0.468750 0.122598
+v 0.024386 -0.468750 0.122598
+v 0.024386 -0.024391 0.122598
+v -0.086808 -0.500000 -0.129917
+v -0.030483 -0.500000 -0.153247
+v -0.000000 -0.500000 0.000000
+v -0.129917 -0.500000 -0.086808
+v -0.153248 -0.500000 -0.030483
+v -0.153248 -0.500000 0.030483
+v -0.129917 -0.500000 0.086808
+v -0.086808 -0.500000 0.129917
+v -0.030483 -0.500000 0.153248
+v 0.030483 -0.500000 0.153248
+v 0.086808 -0.500000 0.129917
+v 0.129917 -0.500000 0.086808
+v 0.153247 -0.500000 0.030483
+v 0.153248 -0.500000 -0.030483
+v 0.129917 -0.500000 -0.086808
+v 0.086808 -0.500000 -0.129917
+v 0.030483 -0.500000 -0.153247
+v 0.086808 -0.468750 -0.129917
+v 0.030483 -0.468750 -0.153248
+v -0.000000 -0.468750 0.000000
+v 0.129917 -0.468750 -0.086808
+v 0.153248 -0.468750 -0.030483
+v 0.153247 -0.468750 0.030483
+v 0.129917 -0.468750 0.086808
+v 0.086808 -0.468750 0.129917
+v 0.030483 -0.468750 0.153248
+v -0.030483 -0.468750 0.153248
+v -0.086808 -0.468750 0.129917
+v -0.129917 -0.468750 0.086808
+v -0.153248 -0.468750 0.030483
+v -0.153248 -0.468750 -0.030483
+v -0.129917 -0.468750 -0.086808
+v -0.086808 -0.468750 -0.129917
+v -0.030483 -0.468750 -0.153248
+v -0.103934 -0.024391 -0.069446
+v -0.103934 -0.468750 -0.069446
+v -0.122598 -0.468750 -0.024386
+v -0.122598 -0.024391 -0.024386
+v -0.024386 -0.024391 -0.122598
+v -0.024386 -0.468750 -0.122598
+v -0.069446 -0.468750 -0.103933
+v -0.069446 -0.024391 -0.103934
+v 0.103934 -0.024391 -0.069446
+v 0.103933 -0.468750 -0.069446
+v 0.069446 -0.468750 -0.103934
+v 0.069446 -0.024391 -0.103934
+v 0.024386 -0.024391 -0.122598
+v 0.024386 -0.468750 -0.122598
+v 0.122598 -0.024391 -0.024386
+v 0.122598 -0.468750 -0.024386
+v 0.122598 -0.024391 0.024386
+v 0.122598 -0.468750 0.024386
+v 0.103934 -0.024391 0.069446
+v 0.103933 -0.468750 0.069447
+v 0.069446 -0.024391 0.103934
+v 0.069446 -0.468750 0.103934
+v -0.069446 -0.024391 0.103934
+v -0.069447 -0.468750 0.103934
+v -0.103934 -0.024391 0.069446
+v -0.103934 -0.468750 0.069446
+v -0.122598 -0.024391 0.024386
+v -0.122598 -0.468750 0.024386
+v -0.041924 0.041589 0.103934
+v -0.041925 0.041589 -0.103934
+v -0.010062 0.009727 -0.122598
+v -0.079509 0.079173 -0.024386
+v -0.066311 0.065976 -0.069446
+v -0.024663 0.094826 -0.069446
+v -0.011464 0.062964 0.103934
+v -0.024662 0.094827 0.069446
+v -0.031805 0.112070 0.024386
+v -0.031805 0.112070 -0.024386
+v 0.005779 0.021334 -0.122598
+v -0.011464 0.062964 -0.103934
+v 0.005780 0.021334 0.122598
+v -0.079509 0.079173 0.024386
+v -0.066311 0.065976 0.069446
+v 0.468750 -0.024387 0.122599
+v 0.468750 0.024386 0.122599
+v 0.024391 0.024386 0.122598
+v 0.500000 -0.086808 -0.129917
+v 0.500000 -0.030483 -0.153247
+v 0.500000 -0.000000 0.000001
+v 0.500000 -0.129917 -0.086807
+v 0.500000 -0.153248 -0.030482
+v 0.500000 -0.153248 0.030483
+v 0.500000 -0.129917 0.086808
+v 0.500000 -0.086808 0.129918
+v 0.500000 -0.030483 0.153248
+v 0.500000 0.030483 0.153248
+v 0.500000 0.086808 0.129918
+v 0.500000 0.129917 0.086808
+v 0.500000 0.153247 0.030483
+v 0.500000 0.153247 -0.030482
+v 0.500000 0.129917 -0.086807
+v 0.500000 0.086808 -0.129917
+v 0.500000 0.030483 -0.153247
+v 0.468750 0.086808 -0.129917
+v 0.468750 0.030483 -0.153247
+v 0.468750 -0.000000 -0.000000
+v 0.468750 0.129917 -0.086807
+v 0.468750 0.153247 -0.030482
+v 0.468750 0.153247 0.030483
+v 0.468750 0.129917 0.086808
+v 0.468750 0.086808 0.129918
+v 0.468750 0.030483 0.153248
+v 0.468750 -0.030483 0.153248
+v 0.468750 -0.086808 0.129918
+v 0.468750 -0.129917 0.086808
+v 0.468750 -0.153248 0.030483
+v 0.468750 -0.153248 -0.030482
+v 0.468750 -0.129917 -0.086807
+v 0.468750 -0.086808 -0.129917
+v 0.468750 -0.030483 -0.153247
+v 0.024391 -0.103934 -0.069446
+v 0.468750 -0.103934 -0.069446
+v 0.468750 -0.122598 -0.024386
+v 0.024391 -0.122598 -0.024386
+v 0.468750 -0.024387 -0.122598
+v 0.468750 -0.069447 -0.103933
+v 0.024391 -0.069446 -0.103934
+v 0.468750 0.103933 -0.069446
+v 0.468750 0.069446 -0.103933
+v 0.024391 0.069446 -0.103934
+v 0.024391 0.024386 -0.122598
+v 0.468750 0.024386 -0.122598
+v 0.024391 0.122598 -0.024386
+v 0.468750 0.122598 -0.024386
+v 0.024391 0.122598 0.024386
+v 0.468750 0.122598 0.024387
+v 0.024391 0.103934 0.069446
+v 0.468750 0.103933 0.069447
+v 0.024391 0.069446 0.103934
+v 0.468750 0.069446 0.103934
+v 0.024391 -0.069446 0.103934
+v 0.468750 -0.069447 0.103934
+v 0.024391 -0.103934 0.069446
+v 0.468750 -0.103934 0.069447
+v 0.024391 -0.122598 0.024386
+v 0.468750 -0.122598 0.024387
+v 0.024390 0.103934 -0.069446
+v -0.020763 -0.005780 0.122598
+v -0.111499 0.031804 0.024386
+v -0.094256 0.024662 0.069446
+v -0.062393 0.011464 0.103934
+v -0.062393 0.011464 -0.103934
+v -0.020763 -0.005780 -0.122598
+v -0.111499 0.031804 -0.024386
+v -0.094256 0.024662 -0.069446
+v -0.010062 0.009727 0.122598
+vt 0.187500 0.265625
+vt 0.187500 0.015625
+vt 0.250000 0.015625
+vt 0.250000 0.265625
+vt 0.093322 0.682190
+vt 0.153370 0.657318
+vt 0.185867 0.820694
+vt 0.047364 0.728149
+vt 0.022491 0.788196
+vt 0.022491 0.853192
+vt 0.047364 0.913239
+vt 0.093322 0.959198
+vt 0.153370 0.984070
+vt 0.218365 0.984070
+vt 0.278413 0.959198
+vt 0.324371 0.913239
+vt 0.349244 0.853192
+vt 0.349244 0.788196
+vt 0.324371 0.728149
+vt 0.278413 0.682190
+vt 0.218365 0.657318
+vt 0.471785 0.682190
+vt 0.531832 0.657318
+vt 0.564330 0.820694
+vt 0.425826 0.728149
+vt 0.400953 0.788196
+vt 0.400953 0.853192
+vt 0.425826 0.913239
+vt 0.471785 0.959198
+vt 0.531832 0.984070
+vt 0.596827 0.984070
+vt 0.656875 0.959198
+vt 0.702834 0.913239
+vt 0.727706 0.853192
+vt 0.727706 0.788196
+vt 0.702834 0.728149
+vt 0.656875 0.682190
+vt 0.596827 0.657318
+vt 0.125000 0.609375
+vt 0.125000 0.546875
+vt 0.187500 0.546875
+vt 0.187500 0.609375
+vt 0.250000 0.546875
+vt 0.250000 0.609375
+vt 0.062500 0.609375
+vt 0.062500 0.546875
+vt 0.000000 0.609375
+vt 0.000000 0.546875
+vt 0.937500 0.609375
+vt 0.937500 0.546875
+vt 1.000000 0.546875
+vt 1.000000 0.609375
+vt 0.875000 0.609375
+vt 0.875000 0.546875
+vt 0.812500 0.609375
+vt 0.812500 0.546875
+vt 0.750000 0.609375
+vt 0.750000 0.546875
+vt 0.687500 0.609375
+vt 0.687500 0.546875
+vt 0.625000 0.609375
+vt 0.625000 0.546875
+vt 0.562500 0.609375
+vt 0.562500 0.546875
+vt 0.500000 0.609375
+vt 0.500000 0.546875
+vt 0.437500 0.609375
+vt 0.437500 0.546875
+vt 0.375000 0.609375
+vt 0.375000 0.546875
+vt 0.312500 0.609375
+vt 0.312500 0.546875
+vt 0.875000 0.265625
+vt 0.875000 0.015625
+vt 0.937500 0.015625
+vt 0.937500 0.265625
+vt 0.750000 0.265625
+vt 0.750000 0.015625
+vt 0.812500 0.015625
+vt 0.812500 0.265625
+vt 0.562500 0.265625
+vt 0.562500 0.015625
+vt 0.625000 0.015625
+vt 0.625000 0.265625
+vt 0.687500 0.265625
+vt 0.687500 0.015625
+vt 0.500000 0.265625
+vt 0.500000 0.015625
+vt 0.437500 0.265625
+vt 0.437500 0.015625
+vt 0.375000 0.265625
+vt 0.375000 0.015625
+vt 0.312500 0.265625
+vt 0.312500 0.015625
+vt 0.125000 0.265625
+vt 0.125000 0.015625
+vt 0.062500 0.265625
+vt 0.062500 0.015625
+vt 0.000000 0.265625
+vt 0.000000 0.015625
+vt 1.000000 0.015625
+vt 1.000000 0.265625
+vt 0.201671 0.341280
+vt 0.315528 0.341280
+vt 0.307071 0.384726
+vt 0.531250 0.296875
+vt 0.531250 0.343750
+vt 0.484375 0.343750
+vt 0.484375 0.296875
+vt 0.437500 0.343750
+vt 0.437500 0.296875
+vt 0.390625 0.296875
+vt 0.390625 0.343750
+vt 0.343750 0.343750
+vt 0.343750 0.296875
+vt 0.578125 0.296875
+vt 0.578125 0.343750
+vt 0.625000 0.296875
+vt 0.625000 0.343750
+vt 0.671875 0.296875
+vt 0.671875 0.343750
+vt 0.801371 0.340121
+vt 0.695971 0.383568
+vt 0.687514 0.340121
+vt 0.720953 0.419768
+vt 0.757935 0.446864
+vt 0.801382 0.453989
+vt 0.625000 0.484375
+vt 0.625000 0.437500
+vt 0.671875 0.437500
+vt 0.671875 0.484375
+vt 0.625000 0.390625
+vt 0.671875 0.390625
+vt 0.578125 0.390625
+vt 0.531250 0.390625
+vt 0.484375 0.390625
+vt 0.437500 0.390625
+vt 0.282090 0.420927
+vt 0.245108 0.448023
+vt 0.201660 0.455148
+vt 0.390625 0.390625
+vt 0.343750 0.390625
+vt 0.390625 0.437500
+vt 0.343750 0.437500
+vt 0.343750 0.484375
+vt 0.390625 0.484375
+vt 0.437500 0.437500
+vt 0.437500 0.484375
+vt 0.484375 0.437500
+vt 0.484375 0.484375
+vt 0.531250 0.437500
+vt 0.531250 0.484375
+vt 0.578125 0.484375
+vt 0.578125 0.437500
+usemtl None
+s off
+f 1/1 2/2 3/3 4/4
+f 5/5 6/6 7/7
+f 8/8 5/5 7/7
+f 9/9 8/8 7/7
+f 10/10 9/9 7/7
+f 11/11 10/10 7/7
+f 12/12 11/11 7/7
+f 13/13 12/12 7/7
+f 14/14 13/13 7/7
+f 15/15 14/14 7/7
+f 16/16 15/15 7/7
+f 17/17 16/16 7/7
+f 18/18 17/17 7/7
+f 19/19 18/18 7/7
+f 20/20 19/19 7/7
+f 21/21 20/20 7/7
+f 22/22 23/23 24/24
+f 25/25 22/22 24/24
+f 26/26 25/25 24/24
+f 27/27 26/26 24/24
+f 28/28 27/27 24/24
+f 29/29 28/28 24/24
+f 30/30 29/29 24/24
+f 31/31 30/30 24/24
+f 32/32 31/31 24/24
+f 33/33 32/32 24/24
+f 34/34 33/33 24/24
+f 35/35 34/34 24/24
+f 36/36 35/35 24/24
+f 37/37 36/36 24/24
+f 38/38 37/37 24/24
+f 23/23 38/38 24/24
+f 6/6 21/21 7/7
+f 25/39 19/40 20/41 22/42
+f 22/42 20/41 21/43 23/44
+f 26/45 18/46 19/40 25/39
+f 27/47 17/48 18/46 26/45
+f 28/49 16/50 17/51 27/52
+f 29/53 15/54 16/50 28/49
+f 30/55 14/56 15/54 29/53
+f 31/57 13/58 14/56 30/55
+f 32/59 12/60 13/58 31/57
+f 33/61 11/62 12/60 32/59
+f 34/63 10/64 11/62 33/61
+f 35/65 9/66 10/64 34/63
+f 36/67 8/68 9/66 35/65
+f 37/69 5/70 8/68 36/67
+f 38/71 6/72 5/70 37/69
+f 23/44 21/43 6/72 38/71
+f 39/73 40/74 41/75 42/76
+f 43/77 44/78 45/79 46/80
+f 47/81 48/82 49/83 50/84
+f 51/85 52/86 44/78 43/77
+f 46/80 45/79 40/74 39/73
+f 50/84 49/83 52/86 51/85
+f 53/87 54/88 48/82 47/81
+f 55/89 56/90 54/88 53/87
+f 57/91 58/92 56/90 55/89
+f 59/93 60/94 58/92 57/91
+f 4/4 3/3 60/94 59/93
+f 2/2 1/1 61/95 62/96
+f 63/97 64/98 62/96 61/95
+f 65/99 66/100 64/98 63/97
+f 42/76 41/75 66/101 65/102
+f 85/5 86/6 87/7
+f 88/8 85/5 87/7
+f 89/9 88/8 87/7
+f 90/10 89/9 87/7
+f 91/11 90/10 87/7
+f 92/12 91/11 87/7
+f 93/13 92/12 87/7
+f 94/14 93/13 87/7
+f 95/15 94/14 87/7
+f 96/16 95/15 87/7
+f 97/17 96/16 87/7
+f 98/18 97/17 87/7
+f 99/19 98/18 87/7
+f 100/20 99/19 87/7
+f 101/21 100/20 87/7
+f 102/22 103/23 104/24
+f 105/25 102/22 104/24
+f 106/26 105/25 104/24
+f 107/27 106/26 104/24
+f 108/28 107/27 104/24
+f 109/29 108/28 104/24
+f 110/30 109/29 104/24
+f 111/31 110/30 104/24
+f 112/32 111/31 104/24
+f 113/33 112/32 104/24
+f 114/34 113/33 104/24
+f 115/35 114/34 104/24
+f 116/36 115/35 104/24
+f 117/37 116/36 104/24
+f 118/38 117/37 104/24
+f 103/23 118/38 104/24
+f 86/6 101/21 87/7
+f 105/39 99/40 100/41 102/42
+f 102/42 100/41 101/43 103/44
+f 106/45 98/46 99/40 105/39
+f 107/47 97/48 98/46 106/45
+f 108/49 96/50 97/51 107/52
+f 109/53 95/54 96/50 108/49
+f 110/55 94/56 95/54 109/53
+f 111/57 93/58 94/56 110/55
+f 112/59 92/60 93/58 111/57
+f 113/61 91/62 92/60 112/59
+f 114/63 90/64 91/62 113/61
+f 115/65 89/66 90/64 114/63
+f 116/67 88/68 89/66 115/65
+f 117/69 85/70 88/68 116/67
+f 118/71 86/72 85/70 117/69
+f 103/44 101/43 86/72 118/71
+f 119/73 120/74 121/75 122/76
+f 125/80 124/79 120/74 119/73
+f 128/84 127/83 130/86 129/85
+f 133/89 134/90 132/88 131/87
+f 135/91 136/92 134/90 133/89
+f 137/93 138/94 136/92 135/91
+f 84/4 83/3 138/94 137/93
+f 141/97 142/98 140/96 139/95
+f 143/99 144/100 142/98 141/97
+f 122/76 121/75 144/101 143/102
+f 4/1 82/2 83/3 84/4
+f 51/77 123/78 124/79 125/80
+f 145/81 126/82 127/83 128/84
+f 129/85 130/86 123/78 51/77
+f 131/87 132/88 126/82 145/81
+f 139/95 140/96 82/2 4/1
+f 51/103 43/104 151/105
+f 65/106 147/107 152/108 42/109
+f 42/109 152/108 153/110 39/111
+f 46/112 39/111 153/110 150/113
+f 46/112 150/113 151/114 43/115
+f 65/106 63/116 148/117 147/107
+f 63/116 61/118 149/119 148/117
+f 61/118 1/120 146/121 149/119
+f 4/122 146/123 1/124
+f 4/122 154/125 146/123
+f 4/122 79/126 154/125
+f 79/126 4/122 84/127
+f 137/128 73/129 79/130 84/131
+f 73/129 67/132 154/133 79/130
+f 149/119 146/121 154/133 67/132
+f 81/134 148/117 149/119 67/132
+f 80/135 147/107 148/117 81/134
+f 80/135 70/136 152/108 147/107
+f 70/136 71/137 153/110 152/108
+f 51/103 151/105 69/138
+f 51/103 69/138 77/139
+f 77/139 129/140 51/103
+f 150/113 68/141 69/142 151/114
+f 78/143 77/144 69/142 68/141
+f 68/141 150/113 153/110 71/137
+f 129/145 77/144 78/143 128/146
+f 78/143 68/141 71/137 72/147
+f 78/143 72/147 145/148 128/146
+f 76/149 72/147 71/137 70/136
+f 76/149 131/150 145/148 72/147
+f 80/135 75/151 76/149 70/136
+f 133/152 131/150 76/149 75/151
+f 135/153 133/152 75/151 74/154
+f 75/151 80/135 81/134 74/154
+f 74/154 81/134 67/132 73/129
+f 137/128 135/153 74/154 73/129
diff --git a/pipeworks/models/pipeworks_pipe_5.obj b/pipeworks/models/pipeworks_pipe_5.obj
new file mode 100644
index 0000000..abf8b97
--- /dev/null
+++ b/pipeworks/models/pipeworks_pipe_5.obj
@@ -0,0 +1,542 @@
+# Blender v2.69 (sub 0) OBJ File: 'pipe-3way-corner.blend'
+# www.blender.org
+o pipe.001_Cylinder.000
+v 0.122598 -0.024391 0.024386
+v 0.122598 -0.468750 0.024387
+v 0.122598 -0.468750 -0.024386
+v 0.122598 -0.024391 -0.024386
+v -0.129917 -0.500000 0.086808
+v -0.153247 -0.500000 0.030483
+v 0.000000 -0.500000 -0.000000
+v -0.086808 -0.500000 0.129917
+v -0.030483 -0.500000 0.153248
+v 0.030483 -0.500000 0.153248
+v 0.086808 -0.500000 0.129917
+v 0.129917 -0.500000 0.086808
+v 0.153248 -0.500000 0.030483
+v 0.153248 -0.500000 -0.030483
+v 0.129917 -0.500000 -0.086808
+v 0.086808 -0.500000 -0.129917
+v 0.030483 -0.500000 -0.153247
+v -0.030483 -0.500000 -0.153248
+v -0.086808 -0.500000 -0.129917
+v -0.129917 -0.500000 -0.086808
+v -0.153247 -0.500000 -0.030483
+v -0.129917 -0.468750 -0.086808
+v -0.153248 -0.468750 -0.030483
+v 0.000000 -0.468750 -0.000000
+v -0.086808 -0.468750 -0.129917
+v -0.030483 -0.468750 -0.153248
+v 0.030483 -0.468750 -0.153247
+v 0.086808 -0.468750 -0.129917
+v 0.129917 -0.468750 -0.086808
+v 0.153248 -0.468750 -0.030483
+v 0.153248 -0.468750 0.030483
+v 0.129917 -0.468750 0.086808
+v 0.086808 -0.468750 0.129917
+v 0.030483 -0.468750 0.153248
+v -0.030483 -0.468750 0.153248
+v -0.086808 -0.468750 0.129917
+v -0.129917 -0.468750 0.086808
+v -0.153248 -0.468750 0.030483
+v -0.069446 -0.024391 0.103934
+v -0.069446 -0.468750 0.103934
+v -0.024386 -0.468750 0.122598
+v -0.024386 -0.024391 0.122598
+v -0.122598 -0.024391 0.024386
+v -0.122598 -0.468750 0.024386
+v -0.103933 -0.468750 0.069446
+v -0.103934 -0.024391 0.069446
+v -0.069446 -0.024391 -0.103934
+v -0.069446 -0.468750 -0.103933
+v -0.103934 -0.468750 -0.069446
+v -0.103934 -0.024391 -0.069446
+v -0.122598 -0.024391 -0.024386
+v -0.122598 -0.468750 -0.024386
+v -0.024386 -0.024391 -0.122598
+v -0.024386 -0.468750 -0.122598
+v 0.024386 -0.024391 -0.122598
+v 0.024386 -0.468750 -0.122598
+v 0.069446 -0.024391 -0.103934
+v 0.069447 -0.468750 -0.103933
+v 0.103934 -0.024391 -0.069446
+v 0.103934 -0.468750 -0.069446
+v 0.103934 -0.024391 0.069446
+v 0.103934 -0.468750 0.069447
+v 0.069446 -0.024391 0.103934
+v 0.069446 -0.468750 0.103934
+v 0.024386 -0.024391 0.122598
+v 0.024386 -0.468750 0.122598
+v 0.468750 0.122598 0.024387
+v 0.468750 0.122598 -0.024386
+v 0.500000 -0.129917 0.086808
+v 0.500000 -0.153248 0.030483
+v 0.500000 0.000000 0.000000
+v 0.500000 -0.086808 0.129917
+v 0.500000 -0.030483 0.153248
+v 0.500000 0.030483 0.153248
+v 0.500000 0.086808 0.129917
+v 0.500000 0.129917 0.086808
+v 0.500000 0.153248 0.030483
+v 0.500000 0.153248 -0.030483
+v 0.500000 0.129917 -0.086808
+v 0.500000 0.086808 -0.129917
+v 0.500000 0.030483 -0.153247
+v 0.500000 -0.030483 -0.153247
+v 0.500000 -0.086808 -0.129917
+v 0.500000 -0.129917 -0.086807
+v 0.500000 -0.153248 -0.030482
+v 0.468750 -0.129917 -0.086807
+v 0.468750 -0.153248 -0.030483
+v 0.468750 -0.000000 0.000000
+v 0.468750 -0.086808 -0.129917
+v 0.468750 -0.030483 -0.153247
+v 0.468750 0.030483 -0.153247
+v 0.468750 0.086808 -0.129917
+v 0.468750 0.129917 -0.086808
+v 0.468750 0.153248 -0.030483
+v 0.468750 0.153248 0.030483
+v 0.468750 0.129917 0.086808
+v 0.468750 0.086808 0.129917
+v 0.468750 0.030483 0.153248
+v 0.468750 -0.030483 0.153248
+v 0.468750 -0.086808 0.129917
+v 0.468750 -0.129917 0.086808
+v 0.468750 -0.153248 0.030483
+v 0.024386 -0.069446 0.103934
+v 0.468750 -0.069446 0.103934
+v 0.468750 -0.024386 0.122598
+v 0.024386 -0.122598 0.024386
+v 0.468750 -0.122598 0.024387
+v 0.468750 -0.103934 0.069447
+v 0.024386 -0.103934 0.069446
+v 0.024386 -0.069446 -0.103934
+v 0.468750 -0.069446 -0.103933
+v 0.468750 -0.103934 -0.069446
+v 0.024386 -0.103934 -0.069446
+v 0.468750 -0.122598 -0.024386
+v 0.468750 -0.024386 -0.122598
+v 0.024386 0.024386 -0.122598
+v 0.468750 0.024386 -0.122598
+v 0.024386 0.069446 -0.103934
+v 0.468750 0.069446 -0.103933
+v 0.024386 0.103934 -0.069446
+v 0.468750 0.103934 -0.069446
+v 0.468750 0.103934 0.069447
+v 0.468750 0.069446 0.103934
+v 0.468750 0.024386 0.122598
+v 0.122599 -0.024387 -0.468750
+v 0.122599 0.024386 -0.468750
+v 0.122598 0.024386 -0.024391
+v -0.129917 -0.086808 -0.500000
+v -0.153247 -0.030483 -0.500000
+v 0.000001 0.000000 -0.500000
+v -0.086807 -0.129917 -0.500000
+v -0.030482 -0.153248 -0.500000
+v 0.030483 -0.153248 -0.500000
+v 0.086808 -0.129917 -0.500000
+v 0.129918 -0.086808 -0.500000
+v 0.153248 -0.030483 -0.500000
+v 0.153248 0.030483 -0.500000
+v 0.129918 0.086808 -0.500000
+v 0.086808 0.129917 -0.500000
+v 0.030483 0.153247 -0.500000
+v -0.030482 0.153247 -0.500000
+v -0.086807 0.129917 -0.500000
+v -0.129917 0.086808 -0.500000
+v -0.153247 0.030483 -0.500000
+v -0.129917 0.086808 -0.468750
+v -0.153247 0.030483 -0.468750
+v 0.000000 0.000000 -0.468750
+v -0.086807 0.129917 -0.468750
+v -0.030482 0.153247 -0.468750
+v 0.030483 0.153247 -0.468750
+v 0.086808 0.129917 -0.468750
+v 0.129918 0.086808 -0.468750
+v 0.153248 0.030483 -0.468750
+v 0.153248 -0.030483 -0.468750
+v 0.129918 -0.086808 -0.468750
+v 0.086808 -0.129917 -0.468750
+v 0.030483 -0.153248 -0.468750
+v -0.030482 -0.153248 -0.468750
+v -0.086807 -0.129917 -0.468750
+v -0.129917 -0.086808 -0.468750
+v -0.153247 -0.030483 -0.468750
+v -0.069446 -0.103934 -0.024391
+v -0.069446 -0.103934 -0.468750
+v -0.024386 -0.122598 -0.468750
+v -0.024386 -0.122598 -0.024391
+v -0.122598 -0.024387 -0.468750
+v -0.103933 -0.069447 -0.468750
+v -0.103934 -0.069446 -0.024391
+v -0.069446 0.103933 -0.468750
+v -0.103933 0.069446 -0.468750
+v -0.103934 0.069446 -0.024391
+v -0.122598 0.024386 -0.024391
+v -0.122598 0.024386 -0.468750
+v -0.024386 0.122598 -0.024391
+v -0.024386 0.122598 -0.468750
+v 0.024386 0.122598 -0.024391
+v 0.024387 0.122598 -0.468750
+v 0.069446 0.103934 -0.024391
+v 0.069447 0.103933 -0.468750
+v 0.103934 0.069446 -0.024391
+v 0.103934 0.069446 -0.468750
+v 0.103934 -0.069446 -0.024391
+v 0.103934 -0.069447 -0.468750
+v 0.069446 -0.103934 -0.024391
+v 0.069447 -0.103934 -0.468750
+v 0.024386 -0.122598 -0.024391
+v 0.024387 -0.122598 -0.468750
+v -0.069446 0.103934 -0.024390
+v 0.024386 0.024386 0.122594
+v 0.024386 0.069446 0.103930
+v 0.024386 0.103933 0.069442
+v 0.024386 0.122598 0.024382
+v -0.028389 0.109793 0.028385
+v -0.109793 0.028389 0.028387
+v -0.028389 0.028389 0.109791
+v -0.073974 0.029365 0.073972
+v -0.073974 0.070067 0.028386
+v -0.028389 0.070067 0.073971
+vt 0.187500 0.265625
+vt 0.187500 0.015625
+vt 0.250000 0.015625
+vt 0.250000 0.265625
+vt 0.093322 0.682190
+vt 0.153370 0.657318
+vt 0.185867 0.820694
+vt 0.047364 0.728149
+vt 0.022491 0.788196
+vt 0.022491 0.853192
+vt 0.047364 0.913239
+vt 0.093322 0.959198
+vt 0.153370 0.984070
+vt 0.218365 0.984070
+vt 0.278413 0.959198
+vt 0.324371 0.913239
+vt 0.349244 0.853192
+vt 0.349244 0.788196
+vt 0.324371 0.728149
+vt 0.278413 0.682190
+vt 0.218365 0.657318
+vt 0.471785 0.682190
+vt 0.531832 0.657318
+vt 0.564330 0.820694
+vt 0.425826 0.728149
+vt 0.400953 0.788196
+vt 0.400953 0.853192
+vt 0.425826 0.913239
+vt 0.471785 0.959198
+vt 0.531832 0.984070
+vt 0.596827 0.984070
+vt 0.656875 0.959198
+vt 0.702834 0.913239
+vt 0.727706 0.853192
+vt 0.727706 0.788196
+vt 0.702834 0.728149
+vt 0.656875 0.682190
+vt 0.596827 0.657318
+vt 0.125000 0.609375
+vt 0.125000 0.546875
+vt 0.187500 0.546875
+vt 0.187500 0.609375
+vt 0.250000 0.546875
+vt 0.250000 0.609375
+vt 0.062500 0.609375
+vt 0.062500 0.546875
+vt 0.000000 0.609375
+vt 0.000000 0.546875
+vt 0.937500 0.609375
+vt 0.937500 0.546875
+vt 1.000000 0.546875
+vt 1.000000 0.609375
+vt 0.875000 0.609375
+vt 0.875000 0.546875
+vt 0.812500 0.609375
+vt 0.812500 0.546875
+vt 0.750000 0.609375
+vt 0.750000 0.546875
+vt 0.687500 0.609375
+vt 0.687500 0.546875
+vt 0.625000 0.609375
+vt 0.625000 0.546875
+vt 0.562500 0.609375
+vt 0.562500 0.546875
+vt 0.500000 0.609375
+vt 0.500000 0.546875
+vt 0.437500 0.609375
+vt 0.437500 0.546875
+vt 0.375000 0.609375
+vt 0.375000 0.546875
+vt 0.312500 0.609375
+vt 0.312500 0.546875
+vt 0.875000 0.265625
+vt 0.875000 0.015625
+vt 0.937500 0.015625
+vt 0.937500 0.265625
+vt 0.750000 0.265625
+vt 0.750000 0.015625
+vt 0.812500 0.015625
+vt 0.812500 0.265625
+vt 0.562500 0.265625
+vt 0.562500 0.015625
+vt 0.625000 0.015625
+vt 0.625000 0.265625
+vt 0.687500 0.265625
+vt 0.687500 0.015625
+vt 0.500000 0.265625
+vt 0.500000 0.015625
+vt 0.437500 0.265625
+vt 0.437500 0.015625
+vt 0.375000 0.265625
+vt 0.375000 0.015625
+vt 0.312500 0.265625
+vt 0.312500 0.015625
+vt 0.125000 0.265625
+vt 0.125000 0.015625
+vt 0.062500 0.265625
+vt 0.062500 0.015625
+vt 0.000000 0.265625
+vt 0.000000 0.015625
+vt 1.000000 0.015625
+vt 1.000000 0.265625
+vt 0.934657 0.863213
+vt 0.901601 0.899049
+vt 0.865820 0.861492
+vt 0.925541 0.762929
+vt 0.899262 0.810455
+vt 0.865821 0.758725
+vt 0.832379 0.810455
+vt 0.806102 0.762929
+vt 0.959958 0.821457
+vt 0.796982 0.863213
+vt 0.973651 0.780138
+vt 0.830039 0.899049
+vt 0.865820 0.923510
+vt 0.757989 0.745545
+vt 0.793772 0.721082
+vt 0.757989 0.780138
+vt 0.937873 0.721082
+vt 0.973654 0.745543
+vt 0.771681 0.821457
+vt 0.840522 0.707845
+vt 0.891124 0.707845
+s off
+f 1/1 2/2 3/3 4/4
+f 5/5 6/6 7/7
+f 8/8 5/5 7/7
+f 9/9 8/8 7/7
+f 10/10 9/9 7/7
+f 11/11 10/10 7/7
+f 12/12 11/11 7/7
+f 13/13 12/12 7/7
+f 14/14 13/13 7/7
+f 15/15 14/14 7/7
+f 16/16 15/15 7/7
+f 17/17 16/16 7/7
+f 18/18 17/17 7/7
+f 19/19 18/18 7/7
+f 20/20 19/19 7/7
+f 21/21 20/20 7/7
+f 22/22 23/23 24/24
+f 25/25 22/22 24/24
+f 26/26 25/25 24/24
+f 27/27 26/26 24/24
+f 28/28 27/27 24/24
+f 29/29 28/28 24/24
+f 30/30 29/29 24/24
+f 31/31 30/30 24/24
+f 32/32 31/31 24/24
+f 33/33 32/32 24/24
+f 34/34 33/33 24/24
+f 35/35 34/34 24/24
+f 36/36 35/35 24/24
+f 37/37 36/36 24/24
+f 38/38 37/37 24/24
+f 23/23 38/38 24/24
+f 6/6 21/21 7/7
+f 25/39 19/40 20/41 22/42
+f 22/42 20/41 21/43 23/44
+f 26/45 18/46 19/40 25/39
+f 27/47 17/48 18/46 26/45
+f 28/49 16/50 17/51 27/52
+f 29/53 15/54 16/50 28/49
+f 30/55 14/56 15/54 29/53
+f 31/57 13/58 14/56 30/55
+f 32/59 12/60 13/58 31/57
+f 33/61 11/62 12/60 32/59
+f 34/63 10/64 11/62 33/61
+f 35/65 9/66 10/64 34/63
+f 36/67 8/68 9/66 35/65
+f 37/69 5/70 8/68 36/67
+f 38/71 6/72 5/70 37/69
+f 23/44 21/43 6/72 38/71
+f 39/73 40/74 41/75 42/76
+f 43/77 44/78 45/79 46/80
+f 47/81 48/82 49/83 50/84
+f 51/85 52/86 44/78 43/77
+f 46/80 45/79 40/74 39/73
+f 50/84 49/83 52/86 51/85
+f 53/87 54/88 48/82 47/81
+f 55/89 56/90 54/88 53/87
+f 57/91 58/92 56/90 55/89
+f 59/93 60/94 58/92 57/91
+f 4/4 3/3 60/94 59/93
+f 2/2 1/1 61/95 62/96
+f 63/97 64/98 62/96 61/95
+f 65/99 66/100 64/98 63/97
+f 42/76 41/75 66/101 65/102
+f 69/5 70/6 71/7
+f 72/8 69/5 71/7
+f 73/9 72/8 71/7
+f 74/10 73/9 71/7
+f 75/11 74/10 71/7
+f 76/12 75/11 71/7
+f 77/13 76/12 71/7
+f 78/14 77/13 71/7
+f 79/15 78/14 71/7
+f 80/16 79/15 71/7
+f 81/17 80/16 71/7
+f 82/18 81/17 71/7
+f 83/19 82/18 71/7
+f 84/20 83/19 71/7
+f 85/21 84/20 71/7
+f 86/22 87/23 88/24
+f 89/25 86/22 88/24
+f 90/26 89/25 88/24
+f 91/27 90/26 88/24
+f 92/28 91/27 88/24
+f 93/29 92/28 88/24
+f 94/30 93/29 88/24
+f 95/31 94/30 88/24
+f 96/32 95/31 88/24
+f 97/33 96/32 88/24
+f 98/34 97/33 88/24
+f 99/35 98/34 88/24
+f 100/36 99/35 88/24
+f 101/37 100/36 88/24
+f 102/38 101/37 88/24
+f 87/23 102/38 88/24
+f 70/6 85/21 71/7
+f 89/39 83/40 84/41 86/42
+f 86/42 84/41 85/43 87/44
+f 90/45 82/46 83/40 89/39
+f 91/47 81/48 82/46 90/45
+f 92/49 80/50 81/51 91/52
+f 93/53 79/54 80/50 92/49
+f 94/55 78/56 79/54 93/53
+f 95/57 77/58 78/56 94/55
+f 96/59 76/60 77/58 95/57
+f 97/61 75/62 76/60 96/59
+f 98/63 74/64 75/62 97/61
+f 99/65 73/66 74/64 98/63
+f 100/67 72/68 73/66 99/65
+f 101/69 69/70 72/68 100/67
+f 102/71 70/72 69/70 101/69
+f 87/44 85/43 70/72 102/71
+f 106/77 107/78 108/79 109/80
+f 110/81 111/82 112/83 113/84
+f 109/80 108/79 104/74 103/73
+f 118/91 119/92 117/90 116/89
+f 120/93 121/94 119/92 118/91
+f 128/5 129/6 130/7
+f 131/8 128/5 130/7
+f 132/9 131/8 130/7
+f 133/10 132/9 130/7
+f 134/11 133/10 130/7
+f 135/12 134/11 130/7
+f 136/13 135/12 130/7
+f 137/14 136/13 130/7
+f 138/15 137/14 130/7
+f 139/16 138/15 130/7
+f 140/17 139/16 130/7
+f 141/18 140/17 130/7
+f 142/19 141/18 130/7
+f 143/20 142/19 130/7
+f 144/21 143/20 130/7
+f 145/22 146/23 147/24
+f 148/25 145/22 147/24
+f 149/26 148/25 147/24
+f 150/27 149/26 147/24
+f 151/28 150/27 147/24
+f 152/29 151/28 147/24
+f 153/30 152/29 147/24
+f 154/31 153/30 147/24
+f 155/32 154/31 147/24
+f 156/33 155/32 147/24
+f 157/34 156/33 147/24
+f 158/35 157/34 147/24
+f 159/36 158/35 147/24
+f 160/37 159/36 147/24
+f 161/38 160/37 147/24
+f 146/23 161/38 147/24
+f 129/6 144/21 130/7
+f 148/39 142/40 143/41 145/42
+f 145/42 143/41 144/43 146/44
+f 149/45 141/46 142/40 148/39
+f 150/47 140/48 141/46 149/45
+f 151/49 139/50 140/51 150/52
+f 152/53 138/54 139/50 151/49
+f 153/55 137/56 138/54 152/53
+f 154/57 136/58 137/56 153/55
+f 155/59 135/60 136/58 154/57
+f 156/61 134/62 135/60 155/59
+f 157/63 133/64 134/62 156/61
+f 158/65 132/66 133/64 157/63
+f 159/67 131/68 132/66 158/65
+f 160/69 128/70 131/68 159/67
+f 161/71 129/72 128/70 160/69
+f 146/44 144/43 129/72 161/71
+f 162/73 163/74 164/75 165/76
+f 168/80 167/79 163/74 162/73
+f 171/84 170/83 173/86 172/85
+f 176/89 177/90 175/88 174/87
+f 178/91 179/92 177/90 176/89
+f 180/93 181/94 179/92 178/91
+f 127/4 126/3 181/94 180/93
+f 184/97 185/98 183/96 182/95
+f 186/99 187/100 185/98 184/97
+f 165/76 164/75 187/101 186/102
+f 191/103 192/104 193/105
+f 195/106 198/107 196/108
+f 198/107 193/105 197/109
+f 198/107 197/109 196/108
+f 196/108 197/109 194/110
+f 190/111 191/103 198/107
+f 193/105 188/112 197/109
+f 193/105 198/107 191/103
+f 195/106 190/111 198/107
+f 190/111 195/106 189/113
+f 192/1 67/2 68/3 176/4
+f 103/73 104/74 105/75 65/76
+f 186/85 114/86 107/78 106/77
+f 113/84 112/83 114/86 186/85
+f 55/87 115/88 111/82 110/81
+f 116/89 117/90 115/88 55/87
+f 176/4 68/3 121/94 120/93
+f 191/95 122/96 67/2 192/1
+f 190/97 123/98 122/96 191/95
+f 189/99 124/100 123/98 190/97
+f 65/76 105/75 124/101 189/102
+f 4/1 125/2 126/3 127/4
+f 51/77 166/78 167/79 168/80
+f 188/81 169/82 170/83 171/84
+f 172/85 173/86 166/78 51/77
+f 174/87 175/88 169/82 188/81
+f 182/95 183/96 125/2 4/1
+f 174/114 192/104 176/115
+f 51/116 43/117 172/118
+f 42/119 65/120 189/113
+f 192/104 174/114 193/105
+f 188/112 193/105 174/114
+f 188/112 171/121 197/109
+f 46/122 39/123 196/108
+f 195/106 196/108 39/123
+f 194/110 46/122 196/108
+f 194/110 197/109 171/121
+f 171/121 172/118 194/110
+f 43/117 194/110 172/118
+f 46/122 194/110 43/117
+f 39/123 42/119 195/106
+f 189/113 195/106 42/119
diff --git a/pipeworks/models/pipeworks_pipe_6.obj b/pipeworks/models/pipeworks_pipe_6.obj
new file mode 100644
index 0000000..0744c45
--- /dev/null
+++ b/pipeworks/models/pipeworks_pipe_6.obj
@@ -0,0 +1,499 @@
+# Blender v2.69 (sub 0) OBJ File: 'pipe-3way.blend'
+# www.blender.org
+o Cube.000
+v -0.069446 -0.468750 0.103934
+v -0.103933 -0.468750 0.069446
+v -0.122598 -0.468750 0.024386
+v -0.122598 -0.468750 -0.024386
+v -0.129917 -0.500000 -0.086808
+v -0.129917 -0.468750 -0.086808
+v -0.086808 -0.500000 -0.129917
+v -0.086808 -0.468750 -0.129917
+v -0.030483 -0.500000 -0.153248
+v -0.030483 -0.468750 -0.153248
+v 0.030483 -0.500000 -0.153247
+v 0.030483 -0.468750 -0.153247
+v 0.086808 -0.500000 -0.129917
+v 0.086808 -0.468750 -0.129917
+v 0.129917 -0.500000 -0.086808
+v 0.129917 -0.468750 -0.086808
+v 0.153248 -0.500000 -0.030483
+v 0.153248 -0.468750 -0.030483
+v 0.153248 -0.500000 0.030483
+v 0.153248 -0.468750 0.030483
+v 0.129917 -0.500000 0.086808
+v 0.129917 -0.468750 0.086808
+v 0.086808 -0.500000 0.129917
+v 0.086808 -0.468750 0.129917
+v 0.030483 -0.500000 0.153248
+v 0.030483 -0.468750 0.153248
+v -0.030483 -0.500000 0.153248
+v -0.030483 -0.468750 0.153248
+v -0.086808 -0.500000 0.129917
+v -0.086808 -0.468750 0.129917
+v -0.129917 -0.500000 0.086808
+v -0.129917 -0.468750 0.086808
+v -0.153247 -0.500000 0.030483
+v -0.153248 -0.468750 0.030483
+v -0.153247 -0.500000 -0.030483
+v -0.153248 -0.468750 -0.030483
+v -0.024386 -0.468750 0.122598
+v 0.024386 -0.468750 0.122598
+v 0.069446 -0.468750 0.103934
+v 0.103934 -0.468750 0.069447
+v 0.122598 -0.468750 0.024387
+v 0.122598 -0.468750 -0.024386
+v 0.103934 -0.468750 -0.069446
+v 0.069447 -0.468750 -0.103933
+v 0.024386 -0.468750 -0.122598
+v -0.024386 -0.468750 -0.122598
+v -0.069446 -0.468750 -0.103933
+v -0.103934 -0.468750 -0.069446
+v 0.000000 -0.468750 0.000000
+v 0.000000 -0.500000 0.000000
+v 0.024386 -0.024391 0.122598
+v 0.069446 -0.024391 0.103934
+v 0.103934 -0.024391 0.069446
+v 0.122598 -0.024391 0.024386
+v 0.122598 -0.024391 -0.024386
+v 0.103934 -0.024391 -0.069446
+v 0.069446 -0.024391 -0.103934
+v 0.024386 -0.024391 -0.122598
+v -0.024386 -0.024391 -0.122598
+v -0.103934 -0.024391 -0.069446
+v -0.069446 -0.024391 -0.103934
+v -0.103934 -0.024391 0.069446
+v -0.122598 -0.024391 0.024386
+v -0.122598 -0.024391 -0.024386
+v -0.069446 -0.024391 0.103934
+v -0.024386 -0.024391 0.122598
+v -0.468750 -0.153248 -0.030483
+v -0.500000 -0.153248 -0.030483
+v -0.468750 -0.153248 0.030483
+v -0.500000 -0.153248 0.030483
+v -0.468750 -0.129917 0.086808
+v -0.500000 -0.129917 0.086808
+v -0.468750 -0.086808 0.129917
+v -0.500000 -0.086808 0.129917
+v -0.468750 -0.030483 0.153248
+v -0.500000 -0.030483 0.153248
+v -0.468750 0.030483 0.153248
+v -0.500000 0.030483 0.153248
+v -0.468750 0.086808 0.129917
+v -0.500000 0.086808 0.129917
+v -0.468750 0.129917 0.086808
+v -0.500000 0.129917 0.086808
+v -0.468750 0.153248 0.030483
+v -0.500000 0.153248 0.030483
+v -0.468750 0.153248 -0.030483
+v -0.500000 0.153248 -0.030483
+v -0.468750 0.129917 -0.086808
+v -0.500000 0.129917 -0.086808
+v -0.468750 0.086808 -0.129917
+v -0.500000 0.086808 -0.129917
+v -0.468750 0.030483 -0.153248
+v -0.500000 0.030483 -0.153248
+v -0.468750 -0.030483 -0.153248
+v -0.500000 -0.030483 -0.153248
+v -0.468750 -0.086808 -0.129917
+v -0.500000 -0.086808 -0.129917
+v -0.468750 -0.129917 -0.086808
+v -0.500000 -0.129917 -0.086808
+v -0.468750 -0.122598 -0.024386
+v -0.468750 -0.122598 0.024386
+v -0.468750 -0.103934 0.069446
+v -0.468750 -0.069446 0.103934
+v -0.468750 -0.024386 0.122598
+v -0.468750 0.024386 0.122598
+v -0.468750 0.069446 0.103934
+v -0.468750 0.103934 0.069446
+v -0.468750 0.122598 0.024386
+v -0.468750 0.122598 -0.024386
+v -0.468750 0.103934 -0.069446
+v -0.468750 0.069446 -0.103934
+v -0.468750 0.024386 -0.122598
+v -0.468750 -0.024386 -0.122598
+v -0.468750 -0.069446 -0.103934
+v -0.468750 -0.103934 -0.069446
+v -0.468750 0.000000 -0.000000
+v -0.500000 -0.000000 -0.000000
+v 0.468750 -0.069446 0.103934
+v 0.468750 -0.103934 0.069447
+v 0.468750 -0.122598 0.024387
+v 0.468750 -0.122598 -0.024386
+v 0.500000 -0.129917 -0.086807
+v 0.468750 -0.129917 -0.086807
+v 0.500000 -0.086808 -0.129917
+v 0.468750 -0.086808 -0.129917
+v 0.500000 -0.030483 -0.153247
+v 0.468750 -0.030483 -0.153247
+v 0.500000 0.030483 -0.153247
+v 0.468750 0.030483 -0.153247
+v 0.500000 0.086808 -0.129917
+v 0.468750 0.086808 -0.129917
+v 0.500000 0.129917 -0.086808
+v 0.468750 0.129917 -0.086808
+v 0.500000 0.153248 -0.030483
+v 0.468750 0.153248 -0.030483
+v 0.500000 0.153248 0.030483
+v 0.468750 0.153248 0.030483
+v 0.500000 0.129917 0.086808
+v 0.468750 0.129917 0.086808
+v 0.500000 0.086808 0.129917
+v 0.468750 0.086808 0.129917
+v 0.500000 0.030483 0.153248
+v 0.468750 0.030483 0.153248
+v 0.500000 -0.030483 0.153248
+v 0.468750 -0.030483 0.153248
+v 0.500000 -0.086808 0.129917
+v 0.468750 -0.086808 0.129917
+v 0.500000 -0.129917 0.086808
+v 0.468750 -0.129917 0.086808
+v 0.500000 -0.153248 0.030483
+v 0.468750 -0.153248 0.030483
+v 0.500000 -0.153248 -0.030482
+v 0.468750 -0.153248 -0.030483
+v 0.468750 -0.024386 0.122598
+v 0.468750 0.024386 0.122598
+v 0.468750 0.069446 0.103934
+v 0.468750 0.103934 0.069447
+v 0.468750 0.122598 0.024387
+v 0.468750 0.122598 -0.024386
+v 0.468750 0.103934 -0.069446
+v 0.468750 0.069446 -0.103933
+v 0.468750 0.024386 -0.122598
+v 0.468750 -0.024386 -0.122598
+v 0.468750 -0.069446 -0.103933
+v 0.468750 -0.103934 -0.069446
+v 0.468750 0.000000 0.000000
+v 0.500000 0.000000 0.000000
+vt 0.187500 0.265625
+vt 0.187500 0.015625
+vt 0.250000 0.015625
+vt 0.250000 0.265625
+vt 0.093322 0.682190
+vt 0.153370 0.657318
+vt 0.185867 0.820694
+vt 0.047364 0.728149
+vt 0.022491 0.788196
+vt 0.022491 0.853192
+vt 0.047364 0.913239
+vt 0.093322 0.959198
+vt 0.153370 0.984070
+vt 0.218365 0.984070
+vt 0.278413 0.959198
+vt 0.324371 0.913239
+vt 0.349244 0.853192
+vt 0.349244 0.788196
+vt 0.324371 0.728149
+vt 0.278413 0.682190
+vt 0.218365 0.657318
+vt 0.471785 0.682190
+vt 0.531832 0.657318
+vt 0.564330 0.820694
+vt 0.425826 0.728149
+vt 0.400953 0.788196
+vt 0.400953 0.853192
+vt 0.425826 0.913239
+vt 0.471785 0.959198
+vt 0.531832 0.984070
+vt 0.596827 0.984070
+vt 0.656875 0.959198
+vt 0.702834 0.913239
+vt 0.727706 0.853192
+vt 0.727706 0.788196
+vt 0.702834 0.728149
+vt 0.656875 0.682190
+vt 0.596827 0.657318
+vt 0.125000 0.609375
+vt 0.125000 0.546875
+vt 0.187500 0.546875
+vt 0.187500 0.609375
+vt 0.250000 0.546875
+vt 0.250000 0.609375
+vt 0.062500 0.609375
+vt 0.062500 0.546875
+vt 0.000000 0.609375
+vt 0.000000 0.546875
+vt 0.937500 0.609375
+vt 0.937500 0.546875
+vt 1.000000 0.546875
+vt 1.000000 0.609375
+vt 0.875000 0.609375
+vt 0.875000 0.546875
+vt 0.812500 0.609375
+vt 0.812500 0.546875
+vt 0.750000 0.609375
+vt 0.750000 0.546875
+vt 0.687500 0.609375
+vt 0.687500 0.546875
+vt 0.625000 0.609375
+vt 0.625000 0.546875
+vt 0.562500 0.609375
+vt 0.562500 0.546875
+vt 0.500000 0.609375
+vt 0.500000 0.546875
+vt 0.437500 0.609375
+vt 0.437500 0.546875
+vt 0.375000 0.609375
+vt 0.375000 0.546875
+vt 0.312500 0.609375
+vt 0.312500 0.546875
+vt 0.875000 0.265625
+vt 0.875000 0.015625
+vt 0.937500 0.015625
+vt 0.937500 0.265625
+vt 0.750000 0.265625
+vt 0.750000 0.015625
+vt 0.812500 0.015625
+vt 0.812500 0.265625
+vt 0.562500 0.265625
+vt 0.562500 0.015625
+vt 0.625000 0.015625
+vt 0.625000 0.265625
+vt 0.687500 0.265625
+vt 0.687500 0.015625
+vt 0.500000 0.265625
+vt 0.500000 0.015625
+vt 0.437500 0.265625
+vt 0.437500 0.015625
+vt 0.375000 0.265625
+vt 0.375000 0.015625
+vt 0.312500 0.265625
+vt 0.312500 0.015625
+vt 0.125000 0.265625
+vt 0.125000 0.015625
+vt 0.062500 0.265625
+vt 0.062500 0.015625
+vt 0.000000 0.265625
+vt 0.000000 0.015625
+vt 1.000000 0.015625
+vt 1.000000 0.265625
+vt 0.218363 0.657325
+vt 0.185866 0.820702
+vt 0.153368 0.657325
+vt 0.531836 0.657325
+vt 0.564334 0.820702
+vt 0.596832 0.657325
+vt 0.656879 0.682198
+vt 0.702838 0.728156
+vt 0.727710 0.788204
+vt 0.727710 0.853199
+vt 0.702838 0.913247
+vt 0.656879 0.959205
+vt 0.596831 0.984078
+vt 0.531836 0.984078
+vt 0.471788 0.959205
+vt 0.425830 0.913247
+vt 0.400957 0.853199
+vt 0.400957 0.788204
+vt 0.425830 0.728156
+vt 0.471789 0.682198
+vt 0.093321 0.682198
+vt 0.047362 0.728156
+vt 0.022489 0.788204
+vt 0.022489 0.853199
+vt 0.047362 0.913247
+vt 0.093320 0.959205
+vt 0.153368 0.984078
+vt 0.218363 0.984078
+vt 0.278411 0.959205
+vt 0.324369 0.913247
+vt 0.349242 0.853199
+vt 0.349242 0.788204
+vt 0.324369 0.728156
+vt 0.278411 0.682198
+vt 0.187500 0.515625
+vt 0.250000 0.515625
+vt 0.875000 0.515625
+vt 0.937500 0.515625
+vt 0.750000 0.515625
+vt 0.812500 0.515625
+vt 0.562500 0.515625
+vt 0.625000 0.515625
+vt 0.687500 0.515625
+vt 0.500000 0.515625
+vt 0.437500 0.515625
+vt 0.375000 0.515625
+vt 0.312500 0.515625
+vt 0.125000 0.515625
+vt 0.062500 0.515625
+vt 0.000000 0.515625
+vt 1.000000 0.515625
+s off
+f 54/1 41/2 42/3 55/4
+f 31/5 33/6 50/7
+f 29/8 31/5 50/7
+f 27/9 29/8 50/7
+f 25/10 27/9 50/7
+f 23/11 25/10 50/7
+f 21/12 23/11 50/7
+f 19/13 21/12 50/7
+f 17/14 19/13 50/7
+f 15/15 17/14 50/7
+f 13/16 15/15 50/7
+f 11/17 13/16 50/7
+f 9/18 11/17 50/7
+f 7/19 9/18 50/7
+f 5/20 7/19 50/7
+f 35/21 5/20 50/7
+f 6/22 36/23 49/24
+f 8/25 6/22 49/24
+f 10/26 8/25 49/24
+f 12/27 10/26 49/24
+f 14/28 12/27 49/24
+f 16/29 14/28 49/24
+f 18/30 16/29 49/24
+f 20/31 18/30 49/24
+f 22/32 20/31 49/24
+f 24/33 22/32 49/24
+f 26/34 24/33 49/24
+f 28/35 26/34 49/24
+f 30/36 28/35 49/24
+f 32/37 30/36 49/24
+f 34/38 32/37 49/24
+f 36/23 34/38 49/24
+f 33/6 35/21 50/7
+f 8/39 7/40 5/41 6/42
+f 6/42 5/41 35/43 36/44
+f 10/45 9/46 7/40 8/39
+f 12/47 11/48 9/46 10/45
+f 14/49 13/50 11/51 12/52
+f 16/53 15/54 13/50 14/49
+f 18/55 17/56 15/54 16/53
+f 20/57 19/58 17/56 18/55
+f 22/59 21/60 19/58 20/57
+f 24/61 23/62 21/60 22/59
+f 26/63 25/64 23/62 24/61
+f 28/65 27/66 25/64 26/63
+f 30/67 29/68 27/66 28/65
+f 32/69 31/70 29/68 30/67
+f 34/71 33/72 31/70 32/69
+f 36/44 35/43 33/72 34/71
+f 65/73 1/74 37/75 66/76
+f 63/77 3/78 2/79 62/80
+f 61/81 47/82 48/83 60/84
+f 64/85 4/86 3/78 63/77
+f 62/80 2/79 1/74 65/73
+f 60/84 48/83 4/86 64/85
+f 59/87 46/88 47/82 61/81
+f 58/89 45/90 46/88 59/87
+f 57/91 44/92 45/90 58/89
+f 56/93 43/94 44/92 57/91
+f 55/4 42/3 43/94 56/93
+f 53/95 40/96 41/2 54/1
+f 52/97 39/98 40/96 53/95
+f 51/99 38/100 39/98 52/97
+f 66/76 37/75 38/101 51/102
+f 67/58 69/60 70/59 68/57
+f 69/60 71/62 72/61 70/59
+f 71/62 73/64 74/63 72/61
+f 73/64 75/66 76/65 74/63
+f 75/66 77/68 78/67 76/65
+f 77/68 79/70 80/69 78/67
+f 79/70 81/72 82/71 80/69
+f 81/72 83/43 84/44 82/71
+f 83/43 85/41 86/42 84/44
+f 85/41 87/40 88/39 86/42
+f 87/40 89/46 90/45 88/39
+f 89/46 91/48 92/47 90/45
+f 91/51 93/50 94/49 92/52
+f 93/50 95/54 96/53 94/49
+f 97/56 67/58 68/57 98/55
+f 95/54 97/56 98/55 96/53
+f 70/103 116/104 68/105
+f 67/106 115/107 69/108
+f 69/108 115/107 71/109
+f 71/109 115/107 73/110
+f 73/110 115/107 75/111
+f 75/111 115/107 77/112
+f 77/112 115/107 79/113
+f 79/113 115/107 81/114
+f 81/114 115/107 83/115
+f 83/115 115/107 85/116
+f 85/116 115/107 87/117
+f 87/117 115/107 89/118
+f 89/118 115/107 91/119
+f 91/119 115/107 93/120
+f 93/120 115/107 95/121
+f 95/121 115/107 97/122
+f 97/122 115/107 67/106
+f 68/105 116/104 98/123
+f 98/123 116/104 96/124
+f 96/124 116/104 94/125
+f 94/125 116/104 92/126
+f 92/126 116/104 90/127
+f 90/127 116/104 88/128
+f 88/128 116/104 86/129
+f 86/129 116/104 84/130
+f 84/130 116/104 82/131
+f 82/131 116/104 80/132
+f 80/132 116/104 78/133
+f 78/133 116/104 76/134
+f 76/134 116/104 74/135
+f 74/135 116/104 72/136
+f 72/136 116/104 70/103
+f 107/137 157/2 158/3 108/138
+f 147/5 149/6 166/7
+f 145/8 147/5 166/7
+f 143/9 145/8 166/7
+f 141/10 143/9 166/7
+f 139/11 141/10 166/7
+f 137/12 139/11 166/7
+f 135/13 137/12 166/7
+f 133/14 135/13 166/7
+f 131/15 133/14 166/7
+f 129/16 131/15 166/7
+f 127/17 129/16 166/7
+f 125/18 127/17 166/7
+f 123/19 125/18 166/7
+f 121/20 123/19 166/7
+f 151/21 121/20 166/7
+f 122/22 152/23 165/24
+f 124/25 122/22 165/24
+f 126/26 124/25 165/24
+f 128/27 126/26 165/24
+f 130/28 128/27 165/24
+f 132/29 130/28 165/24
+f 134/30 132/29 165/24
+f 136/31 134/30 165/24
+f 138/32 136/31 165/24
+f 140/33 138/32 165/24
+f 142/34 140/33 165/24
+f 144/35 142/34 165/24
+f 146/36 144/35 165/24
+f 148/37 146/36 165/24
+f 150/38 148/37 165/24
+f 152/23 150/38 165/24
+f 149/6 151/21 166/7
+f 124/39 123/40 121/41 122/42
+f 122/42 121/41 151/43 152/44
+f 126/45 125/46 123/40 124/39
+f 128/47 127/48 125/46 126/45
+f 130/49 129/50 127/51 128/52
+f 132/53 131/54 129/50 130/49
+f 134/55 133/56 131/54 132/53
+f 136/57 135/58 133/56 134/55
+f 138/59 137/60 135/58 136/57
+f 140/61 139/62 137/60 138/59
+f 142/63 141/64 139/62 140/61
+f 144/65 143/66 141/64 142/63
+f 146/67 145/68 143/66 144/65
+f 148/69 147/70 145/68 146/67
+f 150/71 149/72 147/70 148/69
+f 152/44 151/43 149/72 150/71
+f 102/139 117/74 153/75 103/140
+f 100/141 119/78 118/79 101/142
+f 113/143 163/82 164/83 114/144
+f 99/145 120/86 119/78 100/141
+f 101/142 118/79 117/74 102/139
+f 114/144 164/83 120/86 99/145
+f 112/146 162/88 163/82 113/143
+f 111/147 161/90 162/88 112/146
+f 110/148 160/92 161/90 111/147
+f 109/149 159/94 160/92 110/148
+f 108/138 158/3 159/94 109/149
+f 106/150 156/96 157/2 107/137
+f 105/151 155/98 156/96 106/150
+f 104/152 154/100 155/98 105/151
+f 103/140 153/75 154/101 104/153
diff --git a/pipeworks/models/pipeworks_pipe_7.obj b/pipeworks/models/pipeworks_pipe_7.obj
new file mode 100644
index 0000000..d299361
--- /dev/null
+++ b/pipeworks/models/pipeworks_pipe_7.obj
@@ -0,0 +1,629 @@
+# Blender v2.69 (sub 0) OBJ File: 'pipe-4way-corner.blend'
+# www.blender.org
+o Cube.000
+v -0.069446 -0.468750 0.103934
+v -0.103933 -0.468750 0.069446
+v -0.122598 -0.468750 0.024386
+v -0.122598 -0.468750 -0.024386
+v -0.129917 -0.500000 -0.086808
+v -0.129917 -0.468750 -0.086808
+v -0.086808 -0.500000 -0.129917
+v -0.086808 -0.468750 -0.129917
+v -0.030483 -0.500000 -0.153248
+v -0.030483 -0.468750 -0.153248
+v 0.030483 -0.500000 -0.153247
+v 0.030483 -0.468750 -0.153247
+v 0.086808 -0.500000 -0.129917
+v 0.086808 -0.468750 -0.129917
+v 0.129917 -0.500000 -0.086808
+v 0.129917 -0.468750 -0.086808
+v 0.153248 -0.500000 -0.030483
+v 0.153248 -0.468750 -0.030483
+v 0.153248 -0.500000 0.030483
+v 0.153248 -0.468750 0.030483
+v 0.129917 -0.500000 0.086808
+v 0.129917 -0.468750 0.086808
+v 0.086808 -0.500000 0.129917
+v 0.086808 -0.468750 0.129917
+v 0.030483 -0.500000 0.153248
+v 0.030483 -0.468750 0.153248
+v -0.030483 -0.500000 0.153248
+v -0.030483 -0.468750 0.153248
+v -0.086808 -0.500000 0.129917
+v -0.086808 -0.468750 0.129917
+v -0.129917 -0.500000 0.086808
+v -0.129917 -0.468750 0.086808
+v -0.153247 -0.500000 0.030483
+v -0.153248 -0.468750 0.030483
+v -0.153247 -0.500000 -0.030483
+v -0.153248 -0.468750 -0.030483
+v -0.024386 -0.468750 0.122598
+v 0.024386 -0.468750 0.122598
+v 0.069446 -0.468750 0.103934
+v 0.103934 -0.468750 0.069447
+v 0.122598 -0.468750 0.024387
+v 0.122598 -0.468750 -0.024386
+v 0.103934 -0.468750 -0.069446
+v 0.069447 -0.468750 -0.103933
+v 0.024386 -0.468750 -0.122598
+v -0.024386 -0.468750 -0.122598
+v -0.069446 -0.468750 -0.103933
+v -0.103934 -0.468750 -0.069446
+v 0.000000 -0.468750 0.000000
+v 0.000000 -0.500000 0.000000
+v 0.024386 -0.024391 0.122598
+v 0.069446 -0.024391 0.103934
+v 0.103934 -0.024391 0.069446
+v 0.122598 -0.024391 0.024386
+v 0.122598 -0.024391 -0.024386
+v 0.103934 -0.024391 -0.069446
+v 0.069446 -0.024391 -0.103934
+v 0.024386 -0.024391 -0.122598
+v -0.024386 -0.024391 -0.122598
+v -0.103934 -0.024391 -0.069446
+v -0.069446 -0.024391 -0.103934
+v -0.103934 -0.024391 0.069446
+v -0.122598 -0.024391 0.024386
+v -0.122598 -0.024391 -0.024386
+v -0.069446 -0.024391 0.103934
+v -0.024386 -0.024391 0.122598
+v -0.468750 -0.153248 -0.030483
+v -0.500000 -0.153248 -0.030483
+v -0.468750 -0.153248 0.030483
+v -0.500000 -0.153248 0.030483
+v -0.468750 -0.129917 0.086808
+v -0.500000 -0.129917 0.086808
+v -0.468750 -0.086808 0.129917
+v -0.500000 -0.086808 0.129917
+v -0.468750 -0.030483 0.153248
+v -0.500000 -0.030483 0.153248
+v -0.468750 0.030483 0.153248
+v -0.500000 0.030483 0.153248
+v -0.468750 0.086808 0.129917
+v -0.500000 0.086808 0.129917
+v -0.468750 0.129917 0.086808
+v -0.500000 0.129917 0.086808
+v -0.468750 0.153248 0.030483
+v -0.500000 0.153248 0.030483
+v -0.468750 0.153248 -0.030483
+v -0.500000 0.153248 -0.030483
+v -0.468750 0.129917 -0.086808
+v -0.500000 0.129917 -0.086808
+v -0.468750 0.086808 -0.129917
+v -0.500000 0.086808 -0.129917
+v -0.468750 0.030483 -0.153248
+v -0.500000 0.030483 -0.153248
+v -0.468750 -0.030483 -0.153248
+v -0.500000 -0.030483 -0.153248
+v -0.468750 -0.086808 -0.129917
+v -0.500000 -0.086808 -0.129917
+v -0.468750 -0.129917 -0.086808
+v -0.500000 -0.129917 -0.086808
+v -0.468750 -0.122598 -0.024386
+v -0.468750 -0.122598 0.024386
+v -0.468750 -0.103934 0.069446
+v -0.468750 -0.069446 0.103934
+v -0.468750 -0.024386 0.122598
+v -0.468750 0.024386 0.122598
+v -0.468750 0.069446 0.103934
+v -0.468750 0.103934 0.069446
+v -0.468750 0.122598 0.024386
+v -0.468750 0.122598 -0.024386
+v -0.468750 0.103934 -0.069446
+v -0.468750 0.069446 -0.103934
+v -0.468750 0.024386 -0.122598
+v -0.468750 -0.024386 -0.122598
+v -0.468750 -0.069446 -0.103934
+v -0.468750 -0.103934 -0.069446
+v -0.468750 0.000000 -0.000000
+v -0.500000 -0.000000 -0.000000
+v 0.468750 -0.069446 0.103934
+v 0.468750 -0.103934 0.069447
+v 0.468750 -0.122598 0.024387
+v 0.468750 -0.122598 -0.024386
+v 0.500000 -0.129917 -0.086807
+v 0.468750 -0.129917 -0.086807
+v 0.500000 -0.086808 -0.129917
+v 0.468750 -0.086808 -0.129917
+v 0.500000 -0.030483 -0.153247
+v 0.468750 -0.030483 -0.153247
+v 0.500000 0.030483 -0.153247
+v 0.468750 0.030483 -0.153247
+v 0.500000 0.086808 -0.129917
+v 0.468750 0.086808 -0.129917
+v 0.500000 0.129917 -0.086808
+v 0.468750 0.129917 -0.086808
+v 0.500000 0.153248 -0.030483
+v 0.468750 0.153248 -0.030483
+v 0.500000 0.153248 0.030483
+v 0.468750 0.153248 0.030483
+v 0.500000 0.129917 0.086808
+v 0.468750 0.129917 0.086808
+v 0.500000 0.086808 0.129917
+v 0.468750 0.086808 0.129917
+v 0.500000 0.030483 0.153248
+v 0.468750 0.030483 0.153248
+v 0.500000 -0.030483 0.153248
+v 0.468750 -0.030483 0.153248
+v 0.500000 -0.086808 0.129917
+v 0.468750 -0.086808 0.129917
+v 0.500000 -0.129917 0.086808
+v 0.468750 -0.129917 0.086808
+v 0.500000 -0.153248 0.030483
+v 0.468750 -0.153248 0.030483
+v 0.500000 -0.153248 -0.030482
+v 0.468750 -0.153248 -0.030483
+v 0.468750 -0.024386 0.122598
+v 0.468750 0.024386 0.122598
+v 0.468750 0.069446 0.103934
+v 0.468750 0.103934 0.069447
+v 0.468750 0.122598 0.024387
+v 0.468750 0.122598 -0.024386
+v 0.468750 0.103934 -0.069446
+v 0.468750 0.069446 -0.103933
+v 0.468750 0.024386 -0.122598
+v 0.468750 -0.024386 -0.122598
+v 0.468750 -0.069446 -0.103933
+v 0.468750 -0.103934 -0.069446
+v 0.468750 0.000000 0.000000
+v 0.500000 0.000000 0.000000
+v -0.069446 -0.103934 -0.468750
+v -0.103933 -0.069447 -0.468750
+v -0.122598 -0.024387 -0.468750
+v -0.122598 0.024386 -0.468750
+v -0.129917 0.086808 -0.500000
+v -0.129917 0.086808 -0.468750
+v -0.086807 0.129917 -0.500000
+v -0.086807 0.129917 -0.468750
+v -0.030482 0.153247 -0.500000
+v -0.030482 0.153247 -0.468750
+v 0.030483 0.153247 -0.500000
+v 0.030483 0.153247 -0.468750
+v 0.086808 0.129917 -0.500000
+v 0.086808 0.129917 -0.468750
+v 0.129918 0.086808 -0.500000
+v 0.129918 0.086808 -0.468750
+v 0.153248 0.030483 -0.500000
+v 0.153248 0.030483 -0.468750
+v 0.153248 -0.030483 -0.500000
+v 0.153248 -0.030483 -0.468750
+v 0.129918 -0.086808 -0.500000
+v 0.129918 -0.086808 -0.468750
+v 0.086808 -0.129917 -0.500000
+v 0.086808 -0.129917 -0.468750
+v 0.030483 -0.153248 -0.500000
+v 0.030483 -0.153248 -0.468750
+v -0.030482 -0.153248 -0.500000
+v -0.030482 -0.153248 -0.468750
+v -0.086807 -0.129917 -0.500000
+v -0.086807 -0.129917 -0.468750
+v -0.129917 -0.086808 -0.500000
+v -0.129917 -0.086808 -0.468750
+v -0.153247 -0.030483 -0.500000
+v -0.153247 -0.030483 -0.468750
+v -0.153247 0.030483 -0.500000
+v -0.153247 0.030483 -0.468750
+v -0.024386 -0.122598 -0.468750
+v 0.024387 -0.122598 -0.468750
+v 0.069447 -0.103934 -0.468750
+v 0.103934 -0.069447 -0.468750
+v 0.122599 -0.024387 -0.468750
+v 0.122599 0.024386 -0.468750
+v 0.103934 0.069446 -0.468750
+v 0.069447 0.103933 -0.468750
+v 0.024387 0.122598 -0.468750
+v -0.024386 0.122598 -0.468750
+v -0.069446 0.103933 -0.468750
+v -0.103933 0.069446 -0.468750
+v 0.000000 -0.000000 -0.468750
+v 0.000001 -0.000000 -0.500000
+v 0.024386 -0.122598 -0.024391
+v 0.069446 -0.103934 -0.024391
+v 0.103934 -0.069446 -0.024391
+v 0.122598 -0.024386 -0.024391
+v 0.122598 0.024386 -0.024391
+v 0.103934 0.069446 -0.024391
+v 0.069446 0.103934 -0.024391
+v 0.024386 0.122598 -0.024391
+v -0.024386 0.122598 -0.024391
+v -0.103934 0.069446 -0.024391
+v -0.069446 0.103934 -0.024391
+v -0.103934 -0.069446 -0.024391
+v -0.122598 -0.024386 -0.024391
+v -0.122598 0.024386 -0.024391
+v -0.069446 -0.103934 -0.024391
+v -0.024386 -0.122598 -0.024391
+vt 0.187500 0.265625
+vt 0.187500 0.015625
+vt 0.250000 0.015625
+vt 0.250000 0.265625
+vt 0.093322 0.682190
+vt 0.153370 0.657318
+vt 0.185867 0.820694
+vt 0.047364 0.728149
+vt 0.022491 0.788196
+vt 0.022491 0.853192
+vt 0.047364 0.913239
+vt 0.093322 0.959198
+vt 0.153370 0.984070
+vt 0.218365 0.984070
+vt 0.278413 0.959198
+vt 0.324371 0.913239
+vt 0.349244 0.853192
+vt 0.349244 0.788196
+vt 0.324371 0.728149
+vt 0.278413 0.682190
+vt 0.218365 0.657318
+vt 0.471785 0.682190
+vt 0.531832 0.657318
+vt 0.564330 0.820694
+vt 0.425826 0.728149
+vt 0.400953 0.788196
+vt 0.400953 0.853192
+vt 0.425826 0.913239
+vt 0.471785 0.959198
+vt 0.531832 0.984070
+vt 0.596827 0.984070
+vt 0.656875 0.959198
+vt 0.702834 0.913239
+vt 0.727706 0.853192
+vt 0.727706 0.788196
+vt 0.702834 0.728149
+vt 0.656875 0.682190
+vt 0.596827 0.657318
+vt 0.125000 0.609375
+vt 0.125000 0.546875
+vt 0.187500 0.546875
+vt 0.187500 0.609375
+vt 0.250000 0.546875
+vt 0.250000 0.609375
+vt 0.062500 0.609375
+vt 0.062500 0.546875
+vt 0.000000 0.609375
+vt 0.000000 0.546875
+vt 0.937500 0.609375
+vt 0.937500 0.546875
+vt 1.000000 0.546875
+vt 1.000000 0.609375
+vt 0.875000 0.609375
+vt 0.875000 0.546875
+vt 0.812500 0.609375
+vt 0.812500 0.546875
+vt 0.750000 0.609375
+vt 0.750000 0.546875
+vt 0.687500 0.609375
+vt 0.687500 0.546875
+vt 0.625000 0.609375
+vt 0.625000 0.546875
+vt 0.562500 0.609375
+vt 0.562500 0.546875
+vt 0.500000 0.609375
+vt 0.500000 0.546875
+vt 0.437500 0.609375
+vt 0.437500 0.546875
+vt 0.375000 0.609375
+vt 0.375000 0.546875
+vt 0.312500 0.609375
+vt 0.312500 0.546875
+vt 0.875000 0.265625
+vt 0.875000 0.015625
+vt 0.937500 0.015625
+vt 0.937500 0.265625
+vt 0.750000 0.265625
+vt 0.750000 0.015625
+vt 0.812500 0.015625
+vt 0.812500 0.265625
+vt 0.562500 0.265625
+vt 0.562500 0.015625
+vt 0.625000 0.015625
+vt 0.625000 0.265625
+vt 0.687500 0.265625
+vt 0.687500 0.015625
+vt 0.500000 0.265625
+vt 0.500000 0.015625
+vt 0.437500 0.265625
+vt 0.437500 0.015625
+vt 0.375000 0.265625
+vt 0.375000 0.015625
+vt 0.312500 0.265625
+vt 0.312500 0.015625
+vt 0.125000 0.265625
+vt 0.125000 0.015625
+vt 0.062500 0.265625
+vt 0.062500 0.015625
+vt 0.000000 0.265625
+vt 0.000000 0.015625
+vt 1.000000 0.015625
+vt 1.000000 0.265625
+vt 0.218363 0.657325
+vt 0.185866 0.820702
+vt 0.153368 0.657325
+vt 0.531836 0.657325
+vt 0.564334 0.820702
+vt 0.596832 0.657325
+vt 0.656879 0.682198
+vt 0.702838 0.728156
+vt 0.727710 0.788204
+vt 0.727710 0.853199
+vt 0.702838 0.913247
+vt 0.656879 0.959205
+vt 0.596831 0.984078
+vt 0.531836 0.984078
+vt 0.471788 0.959205
+vt 0.425830 0.913247
+vt 0.400957 0.853199
+vt 0.400957 0.788204
+vt 0.425830 0.728156
+vt 0.471789 0.682198
+vt 0.093321 0.682198
+vt 0.047362 0.728156
+vt 0.022489 0.788204
+vt 0.022489 0.853199
+vt 0.047362 0.913247
+vt 0.093320 0.959205
+vt 0.153368 0.984078
+vt 0.218363 0.984078
+vt 0.278411 0.959205
+vt 0.324369 0.913247
+vt 0.349242 0.853199
+vt 0.349242 0.788204
+vt 0.324369 0.728156
+vt 0.278411 0.682198
+vt 0.187500 0.515625
+vt 0.250000 0.515625
+vt 0.875000 0.515625
+vt 0.937500 0.515625
+vt 0.750000 0.515625
+vt 0.812500 0.515625
+vt 0.562500 0.515625
+vt 0.625000 0.515625
+vt 0.687500 0.515625
+vt 0.500000 0.515625
+vt 0.437500 0.515625
+vt 0.375000 0.515625
+vt 0.312500 0.515625
+vt 0.125000 0.515625
+vt 0.062500 0.515625
+vt 0.000000 0.515625
+vt 1.000000 0.515625
+s off
+f 54/1 41/2 42/3 55/4
+f 31/5 33/6 50/7
+f 29/8 31/5 50/7
+f 27/9 29/8 50/7
+f 25/10 27/9 50/7
+f 23/11 25/10 50/7
+f 21/12 23/11 50/7
+f 19/13 21/12 50/7
+f 17/14 19/13 50/7
+f 15/15 17/14 50/7
+f 13/16 15/15 50/7
+f 11/17 13/16 50/7
+f 9/18 11/17 50/7
+f 7/19 9/18 50/7
+f 5/20 7/19 50/7
+f 35/21 5/20 50/7
+f 6/22 36/23 49/24
+f 8/25 6/22 49/24
+f 10/26 8/25 49/24
+f 12/27 10/26 49/24
+f 14/28 12/27 49/24
+f 16/29 14/28 49/24
+f 18/30 16/29 49/24
+f 20/31 18/30 49/24
+f 22/32 20/31 49/24
+f 24/33 22/32 49/24
+f 26/34 24/33 49/24
+f 28/35 26/34 49/24
+f 30/36 28/35 49/24
+f 32/37 30/36 49/24
+f 34/38 32/37 49/24
+f 36/23 34/38 49/24
+f 33/6 35/21 50/7
+f 8/39 7/40 5/41 6/42
+f 6/42 5/41 35/43 36/44
+f 10/45 9/46 7/40 8/39
+f 12/47 11/48 9/46 10/45
+f 14/49 13/50 11/51 12/52
+f 16/53 15/54 13/50 14/49
+f 18/55 17/56 15/54 16/53
+f 20/57 19/58 17/56 18/55
+f 22/59 21/60 19/58 20/57
+f 24/61 23/62 21/60 22/59
+f 26/63 25/64 23/62 24/61
+f 28/65 27/66 25/64 26/63
+f 30/67 29/68 27/66 28/65
+f 32/69 31/70 29/68 30/67
+f 34/71 33/72 31/70 32/69
+f 36/44 35/43 33/72 34/71
+f 65/73 1/74 37/75 66/76
+f 63/77 3/78 2/79 62/80
+f 61/81 47/82 48/83 60/84
+f 64/85 4/86 3/78 63/77
+f 62/80 2/79 1/74 65/73
+f 60/84 48/83 4/86 64/85
+f 59/87 46/88 47/82 61/81
+f 58/89 45/90 46/88 59/87
+f 57/91 44/92 45/90 58/89
+f 56/93 43/94 44/92 57/91
+f 55/4 42/3 43/94 56/93
+f 53/95 40/96 41/2 54/1
+f 52/97 39/98 40/96 53/95
+f 51/99 38/100 39/98 52/97
+f 66/76 37/75 38/101 51/102
+f 67/58 69/60 70/59 68/57
+f 69/60 71/62 72/61 70/59
+f 71/62 73/64 74/63 72/61
+f 73/64 75/66 76/65 74/63
+f 75/66 77/68 78/67 76/65
+f 77/68 79/70 80/69 78/67
+f 79/70 81/72 82/71 80/69
+f 81/72 83/43 84/44 82/71
+f 83/43 85/41 86/42 84/44
+f 85/41 87/40 88/39 86/42
+f 87/40 89/46 90/45 88/39
+f 89/46 91/48 92/47 90/45
+f 91/51 93/50 94/49 92/52
+f 93/50 95/54 96/53 94/49
+f 97/56 67/58 68/57 98/55
+f 95/54 97/56 98/55 96/53
+f 70/103 116/104 68/105
+f 67/106 115/107 69/108
+f 69/108 115/107 71/109
+f 71/109 115/107 73/110
+f 73/110 115/107 75/111
+f 75/111 115/107 77/112
+f 77/112 115/107 79/113
+f 79/113 115/107 81/114
+f 81/114 115/107 83/115
+f 83/115 115/107 85/116
+f 85/116 115/107 87/117
+f 87/117 115/107 89/118
+f 89/118 115/107 91/119
+f 91/119 115/107 93/120
+f 93/120 115/107 95/121
+f 95/121 115/107 97/122
+f 97/122 115/107 67/106
+f 68/105 116/104 98/123
+f 98/123 116/104 96/124
+f 96/124 116/104 94/125
+f 94/125 116/104 92/126
+f 92/126 116/104 90/127
+f 90/127 116/104 88/128
+f 88/128 116/104 86/129
+f 86/129 116/104 84/130
+f 84/130 116/104 82/131
+f 82/131 116/104 80/132
+f 80/132 116/104 78/133
+f 78/133 116/104 76/134
+f 76/134 116/104 74/135
+f 74/135 116/104 72/136
+f 72/136 116/104 70/103
+f 107/137 157/2 158/3 108/138
+f 147/5 149/6 166/7
+f 145/8 147/5 166/7
+f 143/9 145/8 166/7
+f 141/10 143/9 166/7
+f 139/11 141/10 166/7
+f 137/12 139/11 166/7
+f 135/13 137/12 166/7
+f 133/14 135/13 166/7
+f 131/15 133/14 166/7
+f 129/16 131/15 166/7
+f 127/17 129/16 166/7
+f 125/18 127/17 166/7
+f 123/19 125/18 166/7
+f 121/20 123/19 166/7
+f 151/21 121/20 166/7
+f 122/22 152/23 165/24
+f 124/25 122/22 165/24
+f 126/26 124/25 165/24
+f 128/27 126/26 165/24
+f 130/28 128/27 165/24
+f 132/29 130/28 165/24
+f 134/30 132/29 165/24
+f 136/31 134/30 165/24
+f 138/32 136/31 165/24
+f 140/33 138/32 165/24
+f 142/34 140/33 165/24
+f 144/35 142/34 165/24
+f 146/36 144/35 165/24
+f 148/37 146/36 165/24
+f 150/38 148/37 165/24
+f 152/23 150/38 165/24
+f 149/6 151/21 166/7
+f 124/39 123/40 121/41 122/42
+f 122/42 121/41 151/43 152/44
+f 126/45 125/46 123/40 124/39
+f 128/47 127/48 125/46 126/45
+f 130/49 129/50 127/51 128/52
+f 132/53 131/54 129/50 130/49
+f 134/55 133/56 131/54 132/53
+f 136/57 135/58 133/56 134/55
+f 138/59 137/60 135/58 136/57
+f 140/61 139/62 137/60 138/59
+f 142/63 141/64 139/62 140/61
+f 144/65 143/66 141/64 142/63
+f 146/67 145/68 143/66 144/65
+f 148/69 147/70 145/68 146/67
+f 150/71 149/72 147/70 148/69
+f 152/44 151/43 149/72 150/71
+f 102/139 117/74 153/75 103/140
+f 100/141 119/78 118/79 101/142
+f 113/143 163/82 164/83 114/144
+f 99/145 120/86 119/78 100/141
+f 101/142 118/79 117/74 102/139
+f 114/144 164/83 120/86 99/145
+f 112/146 162/88 163/82 113/143
+f 111/147 161/90 162/88 112/146
+f 110/148 160/92 161/90 111/147
+f 109/149 159/94 160/92 110/148
+f 108/138 158/3 159/94 109/149
+f 106/150 156/96 157/2 107/137
+f 105/151 155/98 156/96 106/150
+f 104/152 154/100 155/98 105/151
+f 103/140 153/75 154/101 104/153
+f 220/1 207/2 208/3 221/4
+f 197/5 199/6 216/7
+f 195/8 197/5 216/7
+f 193/9 195/8 216/7
+f 191/10 193/9 216/7
+f 189/11 191/10 216/7
+f 187/12 189/11 216/7
+f 185/13 187/12 216/7
+f 183/14 185/13 216/7
+f 181/15 183/14 216/7
+f 179/16 181/15 216/7
+f 177/17 179/16 216/7
+f 175/18 177/17 216/7
+f 173/19 175/18 216/7
+f 171/20 173/19 216/7
+f 201/21 171/20 216/7
+f 172/22 202/23 215/24
+f 174/25 172/22 215/24
+f 176/26 174/25 215/24
+f 178/27 176/26 215/24
+f 180/28 178/27 215/24
+f 182/29 180/28 215/24
+f 184/30 182/29 215/24
+f 186/31 184/30 215/24
+f 188/32 186/31 215/24
+f 190/33 188/32 215/24
+f 192/34 190/33 215/24
+f 194/35 192/34 215/24
+f 196/36 194/35 215/24
+f 198/37 196/36 215/24
+f 200/38 198/37 215/24
+f 202/23 200/38 215/24
+f 199/6 201/21 216/7
+f 174/39 173/40 171/41 172/42
+f 172/42 171/41 201/43 202/44
+f 176/45 175/46 173/40 174/39
+f 178/47 177/48 175/46 176/45
+f 180/49 179/50 177/51 178/52
+f 182/53 181/54 179/50 180/49
+f 184/55 183/56 181/54 182/53
+f 186/57 185/58 183/56 184/55
+f 188/59 187/60 185/58 186/57
+f 190/61 189/62 187/60 188/59
+f 192/63 191/64 189/62 190/61
+f 194/65 193/66 191/64 192/63
+f 196/67 195/68 193/66 194/65
+f 198/69 197/70 195/68 196/67
+f 200/71 199/72 197/70 198/69
+f 202/44 201/43 199/72 200/71
+f 231/73 167/74 203/75 232/76
+f 229/77 169/78 168/79 228/80
+f 227/81 213/82 214/83 226/84
+f 230/85 170/86 169/78 229/77
+f 228/80 168/79 167/74 231/73
+f 226/84 214/83 170/86 230/85
+f 225/87 212/88 213/82 227/81
+f 224/89 211/90 212/88 225/87
+f 223/91 210/92 211/90 224/89
+f 222/93 209/94 210/92 223/91
+f 221/4 208/3 209/94 222/93
+f 219/95 206/96 207/2 220/1
+f 218/97 205/98 206/96 219/95
+f 217/99 204/100 205/98 218/97
+f 232/76 203/75 204/101 217/102
diff --git a/pipeworks/models/pipeworks_pipe_8.obj b/pipeworks/models/pipeworks_pipe_8.obj
new file mode 100644
index 0000000..5dc58f9
--- /dev/null
+++ b/pipeworks/models/pipeworks_pipe_8.obj
@@ -0,0 +1,631 @@
+# Blender v2.69 (sub 0) OBJ File: 'pipe-4way.blend'
+# www.blender.org
+mtllib pipeworks_pipe_8.mtl
+o Cube.000
+v 0.069446 -0.468750 -0.103934
+v 0.103933 -0.468750 -0.069446
+v 0.122598 -0.468750 -0.024386
+v 0.122598 -0.468750 0.024386
+v 0.129917 -0.500000 0.086808
+v 0.129917 -0.468750 0.086808
+v 0.086808 -0.500000 0.129917
+v 0.086808 -0.468750 0.129917
+v 0.030483 -0.500000 0.153247
+v 0.030483 -0.468750 0.153248
+v -0.030483 -0.500000 0.153247
+v -0.030483 -0.468750 0.153248
+v -0.086808 -0.500000 0.129917
+v -0.086808 -0.468750 0.129917
+v -0.129918 -0.500000 0.086808
+v -0.129917 -0.468750 0.086808
+v -0.153248 -0.500000 0.030483
+v -0.153248 -0.468750 0.030483
+v -0.153248 -0.500000 -0.030483
+v -0.153248 -0.468750 -0.030483
+v -0.129918 -0.500000 -0.086808
+v -0.129917 -0.468750 -0.086808
+v -0.086808 -0.500000 -0.129917
+v -0.086808 -0.468750 -0.129917
+v -0.030483 -0.500000 -0.153248
+v -0.030483 -0.468750 -0.153248
+v 0.030482 -0.500000 -0.153248
+v 0.030482 -0.468750 -0.153248
+v 0.086807 -0.500000 -0.129917
+v 0.086807 -0.468750 -0.129917
+v 0.129917 -0.500000 -0.086808
+v 0.129917 -0.468750 -0.086808
+v 0.153247 -0.500000 -0.030483
+v 0.153247 -0.468750 -0.030483
+v 0.153247 -0.500000 0.030483
+v 0.153247 -0.468750 0.030483
+v 0.024386 -0.468750 -0.122598
+v -0.024387 -0.468750 -0.122598
+v -0.069447 -0.468750 -0.103934
+v -0.103934 -0.468750 -0.069446
+v -0.122599 -0.468750 -0.024386
+v -0.122599 -0.468750 0.024386
+v -0.103934 -0.468750 0.069446
+v -0.069447 -0.468750 0.103934
+v -0.024387 -0.468750 0.122598
+v 0.024386 -0.468750 0.122598
+v 0.069446 -0.468750 0.103933
+v 0.103933 -0.468750 0.069446
+v -0.000000 -0.468750 -0.000000
+v -0.000000 -0.500000 -0.000000
+v -0.024386 -0.024391 -0.122598
+v -0.069446 -0.024391 -0.103934
+v -0.103934 -0.024391 -0.069446
+v -0.122598 -0.024391 -0.024386
+v -0.122598 -0.024391 0.024386
+v -0.103934 -0.024391 0.069446
+v -0.069446 -0.024391 0.103934
+v -0.024386 -0.024391 0.122598
+v 0.024386 -0.024391 0.122598
+v 0.103934 -0.024391 0.069446
+v 0.069446 -0.024391 0.103934
+v 0.103934 -0.024391 -0.069446
+v 0.122598 -0.024391 -0.024386
+v 0.122598 -0.024391 0.024386
+v 0.069446 -0.024391 -0.103934
+v 0.024386 -0.024391 -0.122598
+v 0.153248 0.468750 0.030483
+v 0.153248 0.500000 0.030483
+v 0.153248 0.468750 -0.030483
+v 0.153248 0.500000 -0.030483
+v 0.129917 0.468750 -0.086808
+v 0.129917 0.500000 -0.086808
+v 0.086808 0.468750 -0.129917
+v 0.086808 0.500000 -0.129917
+v 0.030483 0.468750 -0.153248
+v 0.030483 0.500000 -0.153248
+v -0.030483 0.468750 -0.153248
+v -0.030483 0.500000 -0.153248
+v -0.086808 0.468750 -0.129917
+v -0.086808 0.500000 -0.129917
+v -0.129917 0.468750 -0.086808
+v -0.129917 0.500000 -0.086808
+v -0.153247 0.468750 -0.030483
+v -0.153247 0.500000 -0.030483
+v -0.153247 0.468750 0.030483
+v -0.153247 0.500000 0.030483
+v -0.129917 0.468750 0.086808
+v -0.129917 0.500000 0.086808
+v -0.086808 0.468750 0.129917
+v -0.086808 0.500000 0.129917
+v -0.030483 0.468750 0.153248
+v -0.030483 0.500000 0.153248
+v 0.030483 0.468750 0.153248
+v 0.030483 0.500000 0.153248
+v 0.086808 0.468750 0.129917
+v 0.086808 0.500000 0.129917
+v 0.129917 0.468750 0.086808
+v 0.129918 0.500000 0.086808
+v 0.122598 0.468750 0.024386
+v 0.122598 0.468750 -0.024386
+v 0.103934 0.468750 -0.069446
+v 0.069447 0.468750 -0.103934
+v 0.024387 0.468750 -0.122598
+v -0.024386 0.468750 -0.122598
+v -0.069446 0.468750 -0.103934
+v -0.103933 0.468750 -0.069446
+v -0.122598 0.468750 -0.024386
+v -0.122598 0.468750 0.024386
+v -0.103933 0.468750 0.069446
+v -0.069446 0.468750 0.103934
+v -0.024386 0.468750 0.122598
+v 0.024387 0.468750 0.122598
+v 0.069447 0.468750 0.103934
+v 0.103934 0.468750 0.069446
+v 0.000000 0.468750 -0.000000
+v 0.000000 0.500000 0.000000
+v -0.024386 0.024390 -0.122598
+v -0.069446 0.024390 -0.103934
+v -0.103934 0.024390 -0.069446
+v -0.122598 0.024390 -0.024386
+v -0.122598 0.024390 0.024386
+v -0.103934 0.024390 0.069446
+v -0.069446 0.024390 0.103934
+v -0.024386 0.024389 0.122598
+v 0.024386 0.024389 0.122598
+v 0.103934 0.024390 0.069446
+v 0.069446 0.024390 0.103934
+v 0.103934 0.024390 -0.069446
+v 0.122598 0.024390 -0.024386
+v 0.122598 0.024390 0.024386
+v 0.069446 0.024390 -0.103934
+v 0.024386 0.024390 -0.122598
+v 0.468750 -0.153248 0.030483
+v 0.500000 -0.153248 0.030483
+v 0.468750 -0.153248 -0.030483
+v 0.500000 -0.153248 -0.030483
+v 0.468750 -0.129917 -0.086808
+v 0.500000 -0.129917 -0.086808
+v 0.468750 -0.086808 -0.129917
+v 0.500000 -0.086808 -0.129917
+v 0.468750 -0.030483 -0.153248
+v 0.500000 -0.030483 -0.153248
+v 0.468750 0.030483 -0.153248
+v 0.500000 0.030483 -0.153248
+v 0.468750 0.086808 -0.129917
+v 0.500000 0.086808 -0.129917
+v 0.468750 0.129917 -0.086808
+v 0.500000 0.129917 -0.086808
+v 0.468750 0.153248 -0.030483
+v 0.500000 0.153247 -0.030483
+v 0.468750 0.153248 0.030483
+v 0.500000 0.153248 0.030483
+v 0.468750 0.129917 0.086808
+v 0.500000 0.129917 0.086808
+v 0.468750 0.086808 0.129917
+v 0.500000 0.086808 0.129917
+v 0.468750 0.030483 0.153248
+v 0.500000 0.030483 0.153248
+v 0.468750 -0.030483 0.153248
+v 0.500000 -0.030483 0.153248
+v 0.468750 -0.086808 0.129917
+v 0.500000 -0.086808 0.129917
+v 0.468750 -0.129917 0.086808
+v 0.500000 -0.129917 0.086808
+v 0.468750 -0.122598 0.024386
+v 0.468750 -0.122598 -0.024386
+v 0.468750 -0.103934 -0.069446
+v 0.468750 -0.069446 -0.103934
+v 0.468750 -0.024386 -0.122598
+v 0.468750 0.024386 -0.122598
+v 0.468750 0.069446 -0.103934
+v 0.468750 0.103934 -0.069446
+v 0.468750 0.122598 -0.024386
+v 0.468750 0.122598 0.024386
+v 0.468750 0.103934 0.069446
+v 0.468750 0.069446 0.103934
+v 0.468750 0.024386 0.122598
+v 0.468750 -0.024387 0.122598
+v 0.468750 -0.069447 0.103934
+v 0.468750 -0.103934 0.069446
+v 0.468750 -0.000000 -0.000000
+v 0.500000 -0.000000 0.000000
+v -0.468750 -0.069446 -0.103934
+v -0.468750 -0.103933 -0.069446
+v -0.468750 -0.122598 -0.024387
+v -0.468750 -0.122598 0.024386
+v -0.500000 -0.129917 0.086808
+v -0.468750 -0.129917 0.086808
+v -0.500000 -0.086808 0.129917
+v -0.468750 -0.086808 0.129917
+v -0.500000 -0.030483 0.153247
+v -0.468750 -0.030483 0.153248
+v -0.500000 0.030483 0.153247
+v -0.468750 0.030483 0.153248
+v -0.500000 0.086808 0.129917
+v -0.468750 0.086808 0.129917
+v -0.500000 0.129917 0.086808
+v -0.468750 0.129917 0.086808
+v -0.500000 0.153248 0.030483
+v -0.468750 0.153248 0.030483
+v -0.500000 0.153248 -0.030483
+v -0.468750 0.153248 -0.030483
+v -0.500000 0.129917 -0.086808
+v -0.468750 0.129917 -0.086808
+v -0.500000 0.086808 -0.129917
+v -0.468750 0.086808 -0.129917
+v -0.500000 0.030483 -0.153248
+v -0.468750 0.030483 -0.153248
+v -0.500000 -0.030483 -0.153248
+v -0.468750 -0.030483 -0.153248
+v -0.500000 -0.086808 -0.129917
+v -0.468750 -0.086808 -0.129917
+v -0.500000 -0.129917 -0.086808
+v -0.468750 -0.129917 -0.086808
+v -0.500000 -0.153247 -0.030483
+v -0.468750 -0.153247 -0.030483
+v -0.500000 -0.153247 0.030483
+v -0.468750 -0.153247 0.030483
+v -0.468750 -0.024386 -0.122598
+v -0.468750 0.024387 -0.122598
+v -0.468750 0.069447 -0.103934
+v -0.468750 0.103934 -0.069446
+v -0.468750 0.122598 -0.024386
+v -0.468750 0.122598 0.024386
+v -0.468750 0.103934 0.069446
+v -0.468750 0.069447 0.103934
+v -0.468750 0.024387 0.122598
+v -0.468750 -0.024386 0.122598
+v -0.468750 -0.069446 0.103933
+v -0.468750 -0.103933 0.069446
+v -0.468750 0.000000 -0.000000
+v -0.500000 0.000000 -0.000000
+vt 0.187500 0.265625
+vt 0.187500 0.015625
+vt 0.250000 0.015625
+vt 0.250000 0.265625
+vt 0.093322 0.682190
+vt 0.153370 0.657318
+vt 0.185867 0.820694
+vt 0.047364 0.728149
+vt 0.022491 0.788196
+vt 0.022491 0.853192
+vt 0.047364 0.913239
+vt 0.093322 0.959198
+vt 0.153370 0.984070
+vt 0.218365 0.984070
+vt 0.278413 0.959198
+vt 0.324371 0.913239
+vt 0.349244 0.853192
+vt 0.349244 0.788196
+vt 0.324371 0.728149
+vt 0.278413 0.682190
+vt 0.218365 0.657318
+vt 0.471785 0.682190
+vt 0.531832 0.657318
+vt 0.564330 0.820694
+vt 0.425826 0.728149
+vt 0.400953 0.788196
+vt 0.400953 0.853192
+vt 0.425826 0.913239
+vt 0.471785 0.959198
+vt 0.531832 0.984070
+vt 0.596827 0.984070
+vt 0.656875 0.959198
+vt 0.702834 0.913239
+vt 0.727706 0.853192
+vt 0.727706 0.788196
+vt 0.702834 0.728149
+vt 0.656875 0.682190
+vt 0.596827 0.657318
+vt 0.125000 0.609375
+vt 0.125000 0.546875
+vt 0.187500 0.546875
+vt 0.187500 0.609375
+vt 0.250000 0.546875
+vt 0.250000 0.609375
+vt 0.062500 0.609375
+vt 0.062500 0.546875
+vt 0.000000 0.609375
+vt 0.000000 0.546875
+vt 0.937500 0.609375
+vt 0.937500 0.546875
+vt 1.000000 0.546875
+vt 1.000000 0.609375
+vt 0.875000 0.609375
+vt 0.875000 0.546875
+vt 0.812500 0.609375
+vt 0.812500 0.546875
+vt 0.750000 0.609375
+vt 0.750000 0.546875
+vt 0.687500 0.609375
+vt 0.687500 0.546875
+vt 0.625000 0.609375
+vt 0.625000 0.546875
+vt 0.562500 0.609375
+vt 0.562500 0.546875
+vt 0.500000 0.609375
+vt 0.500000 0.546875
+vt 0.437500 0.609375
+vt 0.437500 0.546875
+vt 0.375000 0.609375
+vt 0.375000 0.546875
+vt 0.312500 0.609375
+vt 0.312500 0.546875
+vt 0.875000 0.265625
+vt 0.875000 0.015625
+vt 0.937500 0.015625
+vt 0.937500 0.265625
+vt 0.750000 0.265625
+vt 0.750000 0.015625
+vt 0.812500 0.015625
+vt 0.812500 0.265625
+vt 0.562500 0.265625
+vt 0.562500 0.015625
+vt 0.625000 0.015625
+vt 0.625000 0.265625
+vt 0.687500 0.265625
+vt 0.687500 0.015625
+vt 0.500000 0.265625
+vt 0.500000 0.015625
+vt 0.437500 0.265625
+vt 0.437500 0.015625
+vt 0.375000 0.265625
+vt 0.375000 0.015625
+vt 0.312500 0.265625
+vt 0.312500 0.015625
+vt 0.125000 0.265625
+vt 0.125000 0.015625
+vt 0.062500 0.265625
+vt 0.062500 0.015625
+vt 0.000000 0.265625
+vt 0.000000 0.015625
+vt 1.000000 0.015625
+vt 1.000000 0.265625
+vt 0.218363 0.657325
+vt 0.185866 0.820702
+vt 0.153368 0.657325
+vt 0.531836 0.657325
+vt 0.564334 0.820702
+vt 0.596832 0.657325
+vt 0.656879 0.682198
+vt 0.702838 0.728156
+vt 0.727710 0.788204
+vt 0.727710 0.853199
+vt 0.702838 0.913247
+vt 0.656879 0.959205
+vt 0.596831 0.984078
+vt 0.531836 0.984078
+vt 0.471788 0.959205
+vt 0.425830 0.913247
+vt 0.400957 0.853199
+vt 0.400957 0.788204
+vt 0.425830 0.728156
+vt 0.471789 0.682198
+vt 0.093321 0.682198
+vt 0.047362 0.728156
+vt 0.022489 0.788204
+vt 0.022489 0.853199
+vt 0.047362 0.913247
+vt 0.093320 0.959205
+vt 0.153368 0.984078
+vt 0.218363 0.984078
+vt 0.278411 0.959205
+vt 0.324369 0.913247
+vt 0.349242 0.853199
+vt 0.349242 0.788204
+vt 0.324369 0.728156
+vt 0.278411 0.682198
+vt 0.187500 0.515625
+vt 0.250000 0.515625
+vt 0.875000 0.515625
+vt 0.937500 0.515625
+vt 0.750000 0.515625
+vt 0.812500 0.515625
+vt 0.562500 0.515625
+vt 0.625000 0.515625
+vt 0.687500 0.515625
+vt 0.500000 0.515625
+vt 0.437500 0.515625
+vt 0.375000 0.515625
+vt 0.312500 0.515625
+vt 0.125000 0.515625
+vt 0.062500 0.515625
+vt 0.000000 0.515625
+vt 1.000000 0.515625
+usemtl None
+s off
+f 54/1 41/2 42/3 55/4
+f 31/5 33/6 50/7
+f 29/8 31/5 50/7
+f 27/9 29/8 50/7
+f 25/10 27/9 50/7
+f 23/11 25/10 50/7
+f 21/12 23/11 50/7
+f 19/13 21/12 50/7
+f 17/14 19/13 50/7
+f 15/15 17/14 50/7
+f 13/16 15/15 50/7
+f 11/17 13/16 50/7
+f 9/18 11/17 50/7
+f 7/19 9/18 50/7
+f 5/20 7/19 50/7
+f 35/21 5/20 50/7
+f 6/22 36/23 49/24
+f 8/25 6/22 49/24
+f 10/26 8/25 49/24
+f 12/27 10/26 49/24
+f 14/28 12/27 49/24
+f 16/29 14/28 49/24
+f 18/30 16/29 49/24
+f 20/31 18/30 49/24
+f 22/32 20/31 49/24
+f 24/33 22/32 49/24
+f 26/34 24/33 49/24
+f 28/35 26/34 49/24
+f 30/36 28/35 49/24
+f 32/37 30/36 49/24
+f 34/38 32/37 49/24
+f 36/23 34/38 49/24
+f 33/6 35/21 50/7
+f 8/39 7/40 5/41 6/42
+f 6/42 5/41 35/43 36/44
+f 10/45 9/46 7/40 8/39
+f 12/47 11/48 9/46 10/45
+f 14/49 13/50 11/51 12/52
+f 16/53 15/54 13/50 14/49
+f 18/55 17/56 15/54 16/53
+f 20/57 19/58 17/56 18/55
+f 22/59 21/60 19/58 20/57
+f 24/61 23/62 21/60 22/59
+f 26/63 25/64 23/62 24/61
+f 28/65 27/66 25/64 26/63
+f 30/67 29/68 27/66 28/65
+f 32/69 31/70 29/68 30/67
+f 34/71 33/72 31/70 32/69
+f 36/44 35/43 33/72 34/71
+f 65/73 1/74 37/75 66/76
+f 63/77 3/78 2/79 62/80
+f 61/81 47/82 48/83 60/84
+f 64/85 4/86 3/78 63/77
+f 62/80 2/79 1/74 65/73
+f 60/84 48/83 4/86 64/85
+f 59/87 46/88 47/82 61/81
+f 58/89 45/90 46/88 59/87
+f 57/91 44/92 45/90 58/89
+f 56/93 43/94 44/92 57/91
+f 55/4 42/3 43/94 56/93
+f 53/95 40/96 41/2 54/1
+f 52/97 39/98 40/96 53/95
+f 51/99 38/100 39/98 52/97
+f 66/76 37/75 38/101 51/102
+f 67/58 69/60 70/59 68/57
+f 69/60 71/62 72/61 70/59
+f 71/62 73/64 74/63 72/61
+f 73/64 75/66 76/65 74/63
+f 75/66 77/68 78/67 76/65
+f 77/68 79/70 80/69 78/67
+f 79/70 81/72 82/71 80/69
+f 81/72 83/43 84/44 82/71
+f 83/43 85/41 86/42 84/44
+f 85/41 87/40 88/39 86/42
+f 87/40 89/46 90/45 88/39
+f 89/46 91/48 92/47 90/45
+f 91/51 93/50 94/49 92/52
+f 93/50 95/54 96/53 94/49
+f 97/56 67/58 68/57 98/55
+f 95/54 97/56 98/55 96/53
+f 70/103 116/104 68/105
+f 67/106 115/107 69/108
+f 69/108 115/107 71/109
+f 71/109 115/107 73/110
+f 73/110 115/107 75/111
+f 75/111 115/107 77/112
+f 77/112 115/107 79/113
+f 79/113 115/107 81/114
+f 81/114 115/107 83/115
+f 83/115 115/107 85/116
+f 85/116 115/107 87/117
+f 87/117 115/107 89/118
+f 89/118 115/107 91/119
+f 91/119 115/107 93/120
+f 93/120 115/107 95/121
+f 95/121 115/107 97/122
+f 97/122 115/107 67/106
+f 68/105 116/104 98/123
+f 98/123 116/104 96/124
+f 96/124 116/104 94/125
+f 94/125 116/104 92/126
+f 92/126 116/104 90/127
+f 90/127 116/104 88/128
+f 88/128 116/104 86/129
+f 86/129 116/104 84/130
+f 84/130 116/104 82/131
+f 82/131 116/104 80/132
+f 80/132 116/104 78/133
+f 78/133 116/104 76/134
+f 76/134 116/104 74/135
+f 74/135 116/104 72/136
+f 72/136 116/104 70/103
+f 107/137 120/1 121/4 108/138
+f 102/139 131/73 132/76 103/140
+f 100/141 129/77 128/80 101/142
+f 113/143 127/81 126/84 114/144
+f 99/145 130/85 129/77 100/141
+f 101/142 128/80 131/73 102/139
+f 114/144 126/84 130/85 99/145
+f 112/146 125/87 127/81 113/143
+f 111/147 124/89 125/87 112/146
+f 110/148 123/91 124/89 111/147
+f 109/149 122/93 123/91 110/148
+f 108/138 121/4 122/93 109/149
+f 106/150 119/95 120/1 107/137
+f 105/151 118/97 119/95 106/150
+f 104/152 117/99 118/97 105/151
+f 103/140 132/76 117/102 104/153
+f 133/58 135/60 136/59 134/57
+f 135/60 137/62 138/61 136/59
+f 137/62 139/64 140/63 138/61
+f 139/64 141/66 142/65 140/63
+f 141/66 143/68 144/67 142/65
+f 143/68 145/70 146/69 144/67
+f 145/70 147/72 148/71 146/69
+f 147/72 149/43 150/44 148/71
+f 149/43 151/41 152/42 150/44
+f 151/41 153/40 154/39 152/42
+f 153/40 155/46 156/45 154/39
+f 155/46 157/48 158/47 156/45
+f 157/51 159/50 160/49 158/52
+f 159/50 161/54 162/53 160/49
+f 163/56 133/58 134/57 164/55
+f 161/54 163/56 164/55 162/53
+f 136/103 182/104 134/105
+f 133/106 181/107 135/108
+f 135/108 181/107 137/109
+f 137/109 181/107 139/110
+f 139/110 181/107 141/111
+f 141/111 181/107 143/112
+f 143/112 181/107 145/113
+f 145/113 181/107 147/114
+f 147/114 181/107 149/115
+f 149/115 181/107 151/116
+f 151/116 181/107 153/117
+f 153/117 181/107 155/118
+f 155/118 181/107 157/119
+f 157/119 181/107 159/120
+f 159/120 181/107 161/121
+f 161/121 181/107 163/122
+f 163/122 181/107 133/106
+f 134/105 182/104 164/123
+f 164/123 182/104 162/124
+f 162/124 182/104 160/125
+f 160/125 182/104 158/126
+f 158/126 182/104 156/127
+f 156/127 182/104 154/128
+f 154/128 182/104 152/129
+f 152/129 182/104 150/130
+f 150/130 182/104 148/131
+f 148/131 182/104 146/132
+f 146/132 182/104 144/133
+f 144/133 182/104 142/134
+f 142/134 182/104 140/135
+f 140/135 182/104 138/136
+f 138/136 182/104 136/103
+f 173/137 223/2 224/3 174/138
+f 213/5 215/6 232/7
+f 211/8 213/5 232/7
+f 209/9 211/8 232/7
+f 207/10 209/9 232/7
+f 205/11 207/10 232/7
+f 203/12 205/11 232/7
+f 201/13 203/12 232/7
+f 199/14 201/13 232/7
+f 197/15 199/14 232/7
+f 195/16 197/15 232/7
+f 193/17 195/16 232/7
+f 191/18 193/17 232/7
+f 189/19 191/18 232/7
+f 187/20 189/19 232/7
+f 217/21 187/20 232/7
+f 188/22 218/23 231/24
+f 190/25 188/22 231/24
+f 192/26 190/25 231/24
+f 194/27 192/26 231/24
+f 196/28 194/27 231/24
+f 198/29 196/28 231/24
+f 200/30 198/29 231/24
+f 202/31 200/30 231/24
+f 204/32 202/31 231/24
+f 206/33 204/32 231/24
+f 208/34 206/33 231/24
+f 210/35 208/34 231/24
+f 212/36 210/35 231/24
+f 214/37 212/36 231/24
+f 216/38 214/37 231/24
+f 218/23 216/38 231/24
+f 215/6 217/21 232/7
+f 190/39 189/40 187/41 188/42
+f 188/42 187/41 217/43 218/44
+f 192/45 191/46 189/40 190/39
+f 194/47 193/48 191/46 192/45
+f 196/49 195/50 193/51 194/52
+f 198/53 197/54 195/50 196/49
+f 200/55 199/56 197/54 198/53
+f 202/57 201/58 199/56 200/55
+f 204/59 203/60 201/58 202/57
+f 206/61 205/62 203/60 204/59
+f 208/63 207/64 205/62 206/61
+f 210/65 209/66 207/64 208/63
+f 212/67 211/68 209/66 210/65
+f 214/69 213/70 211/68 212/67
+f 216/71 215/72 213/70 214/69
+f 218/44 217/43 215/72 216/71
+f 168/139 183/74 219/75 169/140
+f 166/141 185/78 184/79 167/142
+f 179/143 229/82 230/83 180/144
+f 165/145 186/86 185/78 166/141
+f 167/142 184/79 183/74 168/139
+f 180/144 230/83 186/86 165/145
+f 178/146 228/88 229/82 179/143
+f 177/147 227/90 228/88 178/146
+f 176/148 226/92 227/90 177/147
+f 175/149 225/94 226/92 176/148
+f 174/138 224/3 225/94 175/149
+f 172/150 222/96 223/2 173/137
+f 171/151 221/98 222/96 172/150
+f 170/152 220/100 221/98 171/151
+f 169/140 219/75 220/101 170/153
diff --git a/pipeworks/models/pipeworks_pipe_9.obj b/pipeworks/models/pipeworks_pipe_9.obj
new file mode 100644
index 0000000..8c6e03b
--- /dev/null
+++ b/pipeworks/models/pipeworks_pipe_9.obj
@@ -0,0 +1,759 @@
+# Blender v2.69 (sub 0) OBJ File: 'pipe-5way.blend'
+# www.blender.org
+o Cube.000
+v -0.069446 -0.468750 0.103934
+v -0.103933 -0.468750 0.069446
+v -0.122598 -0.468750 0.024386
+v -0.122598 -0.468750 -0.024386
+v -0.129917 -0.500000 -0.086808
+v -0.129917 -0.468750 -0.086808
+v -0.086808 -0.500000 -0.129917
+v -0.086808 -0.468750 -0.129917
+v -0.030483 -0.500000 -0.153248
+v -0.030483 -0.468750 -0.153248
+v 0.030483 -0.500000 -0.153247
+v 0.030483 -0.468750 -0.153247
+v 0.086808 -0.500000 -0.129917
+v 0.086808 -0.468750 -0.129917
+v 0.129917 -0.500000 -0.086808
+v 0.129917 -0.468750 -0.086808
+v 0.153248 -0.500000 -0.030483
+v 0.153248 -0.468750 -0.030483
+v 0.153248 -0.500000 0.030483
+v 0.153248 -0.468750 0.030483
+v 0.129917 -0.500000 0.086808
+v 0.129917 -0.468750 0.086808
+v 0.086808 -0.500000 0.129917
+v 0.086808 -0.468750 0.129917
+v 0.030483 -0.500000 0.153248
+v 0.030483 -0.468750 0.153248
+v -0.030483 -0.500000 0.153248
+v -0.030483 -0.468750 0.153248
+v -0.086808 -0.500000 0.129917
+v -0.086808 -0.468750 0.129917
+v -0.129917 -0.500000 0.086808
+v -0.129917 -0.468750 0.086808
+v -0.153247 -0.500000 0.030483
+v -0.153248 -0.468750 0.030483
+v -0.153247 -0.500000 -0.030483
+v -0.153248 -0.468750 -0.030483
+v -0.024386 -0.468750 0.122598
+v 0.024386 -0.468750 0.122598
+v 0.069446 -0.468750 0.103934
+v 0.103934 -0.468750 0.069447
+v 0.122598 -0.468750 0.024387
+v 0.122598 -0.468750 -0.024386
+v 0.103934 -0.468750 -0.069446
+v 0.069447 -0.468750 -0.103933
+v 0.024386 -0.468750 -0.122598
+v -0.024386 -0.468750 -0.122598
+v -0.069446 -0.468750 -0.103933
+v -0.103934 -0.468750 -0.069446
+v 0.000000 -0.468750 0.000000
+v 0.000000 -0.500000 0.000000
+v 0.024386 -0.024391 0.122598
+v 0.069446 -0.024391 0.103934
+v 0.103934 -0.024391 0.069446
+v 0.122598 -0.024391 0.024386
+v 0.122598 -0.024391 -0.024386
+v 0.103934 -0.024391 -0.069446
+v 0.069446 -0.024391 -0.103934
+v 0.024386 -0.024391 -0.122598
+v -0.024386 -0.024391 -0.122598
+v -0.103934 -0.024391 -0.069446
+v -0.069446 -0.024391 -0.103934
+v -0.103934 -0.024391 0.069446
+v -0.122598 -0.024391 0.024386
+v -0.122598 -0.024391 -0.024386
+v -0.069446 -0.024391 0.103934
+v -0.024386 -0.024391 0.122598
+v -0.153248 0.468750 -0.030483
+v -0.153248 0.500000 -0.030483
+v -0.153248 0.468750 0.030483
+v -0.153248 0.500000 0.030483
+v -0.129917 0.468750 0.086808
+v -0.129917 0.500000 0.086808
+v -0.086808 0.468750 0.129917
+v -0.086808 0.500000 0.129917
+v -0.030483 0.468750 0.153248
+v -0.030483 0.500000 0.153248
+v 0.030483 0.468750 0.153248
+v 0.030483 0.500000 0.153248
+v 0.086808 0.468750 0.129917
+v 0.086808 0.500000 0.129917
+v 0.129917 0.468750 0.086808
+v 0.129917 0.500000 0.086808
+v 0.153248 0.468750 0.030483
+v 0.153248 0.500000 0.030483
+v 0.153248 0.468750 -0.030483
+v 0.153248 0.500000 -0.030483
+v 0.129917 0.468750 -0.086808
+v 0.129917 0.500000 -0.086808
+v 0.086808 0.468750 -0.129917
+v 0.086808 0.500000 -0.129917
+v 0.030483 0.468750 -0.153248
+v 0.030483 0.500000 -0.153248
+v -0.030483 0.468750 -0.153248
+v -0.030483 0.500000 -0.153248
+v -0.086808 0.468750 -0.129917
+v -0.086808 0.500000 -0.129917
+v -0.129917 0.468750 -0.086808
+v -0.129917 0.500000 -0.086808
+v -0.122598 0.468750 -0.024386
+v -0.122598 0.468750 0.024386
+v -0.103934 0.468750 0.069446
+v -0.069446 0.468750 0.103934
+v -0.024386 0.468750 0.122598
+v 0.024386 0.468750 0.122598
+v 0.069446 0.468750 0.103934
+v 0.103934 0.468750 0.069446
+v 0.122598 0.468750 0.024386
+v 0.122598 0.468750 -0.024386
+v 0.103934 0.468750 -0.069446
+v 0.069446 0.468750 -0.103934
+v 0.024386 0.468750 -0.122598
+v -0.024386 0.468750 -0.122598
+v -0.069446 0.468750 -0.103934
+v -0.103934 0.468750 -0.069446
+v -0.000000 0.468750 0.000000
+v -0.000000 0.500000 -0.000000
+v 0.024386 0.024390 0.122598
+v 0.069446 0.024390 0.103934
+v 0.103934 0.024390 0.069446
+v 0.122598 0.024390 0.024386
+v 0.122598 0.024390 -0.024386
+v 0.103934 0.024390 -0.069446
+v 0.069446 0.024390 -0.103934
+v 0.024386 0.024389 -0.122598
+v -0.024386 0.024389 -0.122598
+v -0.103934 0.024390 -0.069446
+v -0.069446 0.024390 -0.103934
+v -0.103934 0.024390 0.069446
+v -0.122598 0.024390 0.024386
+v -0.122598 0.024390 -0.024386
+v -0.069446 0.024390 0.103934
+v -0.024386 0.024390 0.122598
+v -0.468750 -0.153248 -0.030483
+v -0.500000 -0.153248 -0.030483
+v -0.468750 -0.153248 0.030483
+v -0.500000 -0.153248 0.030483
+v -0.468750 -0.129917 0.086808
+v -0.500000 -0.129917 0.086808
+v -0.468750 -0.086808 0.129917
+v -0.500000 -0.086808 0.129917
+v -0.468750 -0.030483 0.153248
+v -0.500000 -0.030483 0.153248
+v -0.468750 0.030483 0.153248
+v -0.500000 0.030483 0.153248
+v -0.468750 0.086808 0.129917
+v -0.500000 0.086808 0.129917
+v -0.468750 0.129917 0.086808
+v -0.500000 0.129917 0.086808
+v -0.468750 0.153248 0.030483
+v -0.500000 0.153248 0.030483
+v -0.468750 0.153248 -0.030483
+v -0.500000 0.153248 -0.030483
+v -0.468750 0.129917 -0.086808
+v -0.500000 0.129917 -0.086808
+v -0.468750 0.086808 -0.129917
+v -0.500000 0.086808 -0.129917
+v -0.468750 0.030483 -0.153248
+v -0.500000 0.030483 -0.153248
+v -0.468750 -0.030483 -0.153248
+v -0.500000 -0.030483 -0.153248
+v -0.468750 -0.086808 -0.129917
+v -0.500000 -0.086808 -0.129917
+v -0.468750 -0.129917 -0.086808
+v -0.500000 -0.129917 -0.086808
+v -0.468750 -0.122598 -0.024386
+v -0.468750 -0.122598 0.024386
+v -0.468750 -0.103934 0.069446
+v -0.468750 -0.069446 0.103934
+v -0.468750 -0.024386 0.122598
+v -0.468750 0.024386 0.122598
+v -0.468750 0.069446 0.103934
+v -0.468750 0.103934 0.069446
+v -0.468750 0.122598 0.024386
+v -0.468750 0.122598 -0.024386
+v -0.468750 0.103934 -0.069446
+v -0.468750 0.069446 -0.103934
+v -0.468750 0.024386 -0.122598
+v -0.468750 -0.024386 -0.122598
+v -0.468750 -0.069446 -0.103934
+v -0.468750 -0.103934 -0.069446
+v -0.468750 0.000000 -0.000000
+v -0.500000 -0.000000 -0.000000
+v 0.468750 -0.069446 0.103934
+v 0.468750 -0.103934 0.069447
+v 0.468750 -0.122598 0.024387
+v 0.468750 -0.122598 -0.024386
+v 0.500000 -0.129917 -0.086807
+v 0.468750 -0.129917 -0.086807
+v 0.500000 -0.086808 -0.129917
+v 0.468750 -0.086808 -0.129917
+v 0.500000 -0.030483 -0.153247
+v 0.468750 -0.030483 -0.153247
+v 0.500000 0.030483 -0.153247
+v 0.468750 0.030483 -0.153247
+v 0.500000 0.086808 -0.129917
+v 0.468750 0.086808 -0.129917
+v 0.500000 0.129917 -0.086808
+v 0.468750 0.129917 -0.086808
+v 0.500000 0.153248 -0.030483
+v 0.468750 0.153248 -0.030483
+v 0.500000 0.153248 0.030483
+v 0.468750 0.153248 0.030483
+v 0.500000 0.129917 0.086808
+v 0.468750 0.129917 0.086808
+v 0.500000 0.086808 0.129917
+v 0.468750 0.086808 0.129917
+v 0.500000 0.030483 0.153248
+v 0.468750 0.030483 0.153248
+v 0.500000 -0.030483 0.153248
+v 0.468750 -0.030483 0.153248
+v 0.500000 -0.086808 0.129917
+v 0.468750 -0.086808 0.129917
+v 0.500000 -0.129917 0.086808
+v 0.468750 -0.129917 0.086808
+v 0.500000 -0.153248 0.030483
+v 0.468750 -0.153248 0.030483
+v 0.500000 -0.153248 -0.030482
+v 0.468750 -0.153248 -0.030483
+v 0.468750 -0.024386 0.122598
+v 0.468750 0.024386 0.122598
+v 0.468750 0.069446 0.103934
+v 0.468750 0.103934 0.069447
+v 0.468750 0.122598 0.024387
+v 0.468750 0.122598 -0.024386
+v 0.468750 0.103934 -0.069446
+v 0.468750 0.069446 -0.103933
+v 0.468750 0.024386 -0.122598
+v 0.468750 -0.024386 -0.122598
+v 0.468750 -0.069446 -0.103933
+v 0.468750 -0.103934 -0.069446
+v 0.468750 0.000000 0.000000
+v 0.500000 0.000000 0.000000
+v -0.069446 -0.103934 -0.468750
+v -0.103933 -0.069447 -0.468750
+v -0.122598 -0.024387 -0.468750
+v -0.122598 0.024386 -0.468750
+v -0.129917 0.086808 -0.500000
+v -0.129917 0.086808 -0.468750
+v -0.086807 0.129917 -0.500000
+v -0.086807 0.129917 -0.468750
+v -0.030482 0.153247 -0.500000
+v -0.030482 0.153247 -0.468750
+v 0.030483 0.153247 -0.500000
+v 0.030483 0.153247 -0.468750
+v 0.086808 0.129917 -0.500000
+v 0.086808 0.129917 -0.468750
+v 0.129918 0.086808 -0.500000
+v 0.129918 0.086808 -0.468750
+v 0.153248 0.030483 -0.500000
+v 0.153248 0.030483 -0.468750
+v 0.153248 -0.030483 -0.500000
+v 0.153248 -0.030483 -0.468750
+v 0.129918 -0.086808 -0.500000
+v 0.129918 -0.086808 -0.468750
+v 0.086808 -0.129917 -0.500000
+v 0.086808 -0.129917 -0.468750
+v 0.030483 -0.153248 -0.500000
+v 0.030483 -0.153248 -0.468750
+v -0.030482 -0.153248 -0.500000
+v -0.030482 -0.153248 -0.468750
+v -0.086807 -0.129917 -0.500000
+v -0.086807 -0.129917 -0.468750
+v -0.129917 -0.086808 -0.500000
+v -0.129917 -0.086808 -0.468750
+v -0.153247 -0.030483 -0.500000
+v -0.153247 -0.030483 -0.468750
+v -0.153247 0.030483 -0.500000
+v -0.153247 0.030483 -0.468750
+v -0.024386 -0.122598 -0.468750
+v 0.024387 -0.122598 -0.468750
+v 0.069447 -0.103934 -0.468750
+v 0.103934 -0.069447 -0.468750
+v 0.122599 -0.024387 -0.468750
+v 0.122599 0.024386 -0.468750
+v 0.103934 0.069446 -0.468750
+v 0.069447 0.103933 -0.468750
+v 0.024387 0.122598 -0.468750
+v -0.024386 0.122598 -0.468750
+v -0.069446 0.103933 -0.468750
+v -0.103933 0.069446 -0.468750
+v 0.000000 -0.000000 -0.468750
+v 0.000001 -0.000000 -0.500000
+v 0.024386 -0.122598 -0.024391
+v 0.069446 -0.103934 -0.024391
+v 0.103934 -0.069446 -0.024391
+v 0.122598 -0.024386 -0.024391
+v 0.122598 0.024386 -0.024391
+v 0.103934 0.069446 -0.024391
+v 0.069446 0.103934 -0.024391
+v 0.024386 0.122598 -0.024391
+v -0.024386 0.122598 -0.024391
+v -0.103934 0.069446 -0.024391
+v -0.069446 0.103934 -0.024391
+v -0.103934 -0.069446 -0.024391
+v -0.122598 -0.024386 -0.024391
+v -0.122598 0.024386 -0.024391
+v -0.069446 -0.103934 -0.024391
+v -0.024386 -0.122598 -0.024391
+vt 0.187500 0.265625
+vt 0.187500 0.015625
+vt 0.250000 0.015625
+vt 0.250000 0.265625
+vt 0.093322 0.682190
+vt 0.153370 0.657318
+vt 0.185867 0.820694
+vt 0.047364 0.728149
+vt 0.022491 0.788196
+vt 0.022491 0.853192
+vt 0.047364 0.913239
+vt 0.093322 0.959198
+vt 0.153370 0.984070
+vt 0.218365 0.984070
+vt 0.278413 0.959198
+vt 0.324371 0.913239
+vt 0.349244 0.853192
+vt 0.349244 0.788196
+vt 0.324371 0.728149
+vt 0.278413 0.682190
+vt 0.218365 0.657318
+vt 0.471785 0.682190
+vt 0.531832 0.657318
+vt 0.564330 0.820694
+vt 0.425826 0.728149
+vt 0.400953 0.788196
+vt 0.400953 0.853192
+vt 0.425826 0.913239
+vt 0.471785 0.959198
+vt 0.531832 0.984070
+vt 0.596827 0.984070
+vt 0.656875 0.959198
+vt 0.702834 0.913239
+vt 0.727706 0.853192
+vt 0.727706 0.788196
+vt 0.702834 0.728149
+vt 0.656875 0.682190
+vt 0.596827 0.657318
+vt 0.125000 0.609375
+vt 0.125000 0.546875
+vt 0.187500 0.546875
+vt 0.187500 0.609375
+vt 0.250000 0.546875
+vt 0.250000 0.609375
+vt 0.062500 0.609375
+vt 0.062500 0.546875
+vt 0.000000 0.609375
+vt 0.000000 0.546875
+vt 0.937500 0.609375
+vt 0.937500 0.546875
+vt 1.000000 0.546875
+vt 1.000000 0.609375
+vt 0.875000 0.609375
+vt 0.875000 0.546875
+vt 0.812500 0.609375
+vt 0.812500 0.546875
+vt 0.750000 0.609375
+vt 0.750000 0.546875
+vt 0.687500 0.609375
+vt 0.687500 0.546875
+vt 0.625000 0.609375
+vt 0.625000 0.546875
+vt 0.562500 0.609375
+vt 0.562500 0.546875
+vt 0.500000 0.609375
+vt 0.500000 0.546875
+vt 0.437500 0.609375
+vt 0.437500 0.546875
+vt 0.375000 0.609375
+vt 0.375000 0.546875
+vt 0.312500 0.609375
+vt 0.312500 0.546875
+vt 0.875000 0.265625
+vt 0.875000 0.015625
+vt 0.937500 0.015625
+vt 0.937500 0.265625
+vt 0.750000 0.265625
+vt 0.750000 0.015625
+vt 0.812500 0.015625
+vt 0.812500 0.265625
+vt 0.562500 0.265625
+vt 0.562500 0.015625
+vt 0.625000 0.015625
+vt 0.625000 0.265625
+vt 0.687500 0.265625
+vt 0.687500 0.015625
+vt 0.500000 0.265625
+vt 0.500000 0.015625
+vt 0.437500 0.265625
+vt 0.437500 0.015625
+vt 0.375000 0.265625
+vt 0.375000 0.015625
+vt 0.312500 0.265625
+vt 0.312500 0.015625
+vt 0.125000 0.265625
+vt 0.125000 0.015625
+vt 0.062500 0.265625
+vt 0.062500 0.015625
+vt 0.000000 0.265625
+vt 0.000000 0.015625
+vt 1.000000 0.015625
+vt 1.000000 0.265625
+vt 0.218363 0.657325
+vt 0.185866 0.820702
+vt 0.153368 0.657325
+vt 0.531836 0.657325
+vt 0.564334 0.820702
+vt 0.596832 0.657325
+vt 0.656879 0.682198
+vt 0.702838 0.728156
+vt 0.727710 0.788204
+vt 0.727710 0.853199
+vt 0.702838 0.913247
+vt 0.656879 0.959205
+vt 0.596831 0.984078
+vt 0.531836 0.984078
+vt 0.471788 0.959205
+vt 0.425830 0.913247
+vt 0.400957 0.853199
+vt 0.400957 0.788204
+vt 0.425830 0.728156
+vt 0.471789 0.682198
+vt 0.093321 0.682198
+vt 0.047362 0.728156
+vt 0.022489 0.788204
+vt 0.022489 0.853199
+vt 0.047362 0.913247
+vt 0.093320 0.959205
+vt 0.153368 0.984078
+vt 0.218363 0.984078
+vt 0.278411 0.959205
+vt 0.324369 0.913247
+vt 0.349242 0.853199
+vt 0.349242 0.788204
+vt 0.324369 0.728156
+vt 0.278411 0.682198
+vt 0.187500 0.515625
+vt 0.250000 0.515625
+vt 0.875000 0.515625
+vt 0.937500 0.515625
+vt 0.750000 0.515625
+vt 0.812500 0.515625
+vt 0.562500 0.515625
+vt 0.625000 0.515625
+vt 0.687500 0.515625
+vt 0.500000 0.515625
+vt 0.437500 0.515625
+vt 0.375000 0.515625
+vt 0.312500 0.515625
+vt 0.125000 0.515625
+vt 0.062500 0.515625
+vt 0.000000 0.515625
+vt 1.000000 0.515625
+s off
+f 54/1 41/2 42/3 55/4
+f 31/5 33/6 50/7
+f 29/8 31/5 50/7
+f 27/9 29/8 50/7
+f 25/10 27/9 50/7
+f 23/11 25/10 50/7
+f 21/12 23/11 50/7
+f 19/13 21/12 50/7
+f 17/14 19/13 50/7
+f 15/15 17/14 50/7
+f 13/16 15/15 50/7
+f 11/17 13/16 50/7
+f 9/18 11/17 50/7
+f 7/19 9/18 50/7
+f 5/20 7/19 50/7
+f 35/21 5/20 50/7
+f 6/22 36/23 49/24
+f 8/25 6/22 49/24
+f 10/26 8/25 49/24
+f 12/27 10/26 49/24
+f 14/28 12/27 49/24
+f 16/29 14/28 49/24
+f 18/30 16/29 49/24
+f 20/31 18/30 49/24
+f 22/32 20/31 49/24
+f 24/33 22/32 49/24
+f 26/34 24/33 49/24
+f 28/35 26/34 49/24
+f 30/36 28/35 49/24
+f 32/37 30/36 49/24
+f 34/38 32/37 49/24
+f 36/23 34/38 49/24
+f 33/6 35/21 50/7
+f 8/39 7/40 5/41 6/42
+f 6/42 5/41 35/43 36/44
+f 10/45 9/46 7/40 8/39
+f 12/47 11/48 9/46 10/45
+f 14/49 13/50 11/51 12/52
+f 16/53 15/54 13/50 14/49
+f 18/55 17/56 15/54 16/53
+f 20/57 19/58 17/56 18/55
+f 22/59 21/60 19/58 20/57
+f 24/61 23/62 21/60 22/59
+f 26/63 25/64 23/62 24/61
+f 28/65 27/66 25/64 26/63
+f 30/67 29/68 27/66 28/65
+f 32/69 31/70 29/68 30/67
+f 34/71 33/72 31/70 32/69
+f 36/44 35/43 33/72 34/71
+f 65/73 1/74 37/75 66/76
+f 63/77 3/78 2/79 62/80
+f 61/81 47/82 48/83 60/84
+f 64/85 4/86 3/78 63/77
+f 62/80 2/79 1/74 65/73
+f 60/84 48/83 4/86 64/85
+f 59/87 46/88 47/82 61/81
+f 58/89 45/90 46/88 59/87
+f 57/91 44/92 45/90 58/89
+f 56/93 43/94 44/92 57/91
+f 55/4 42/3 43/94 56/93
+f 53/95 40/96 41/2 54/1
+f 52/97 39/98 40/96 53/95
+f 51/99 38/100 39/98 52/97
+f 66/76 37/75 38/101 51/102
+f 67/58 69/60 70/59 68/57
+f 69/60 71/62 72/61 70/59
+f 71/62 73/64 74/63 72/61
+f 73/64 75/66 76/65 74/63
+f 75/66 77/68 78/67 76/65
+f 77/68 79/70 80/69 78/67
+f 79/70 81/72 82/71 80/69
+f 81/72 83/43 84/44 82/71
+f 83/43 85/41 86/42 84/44
+f 85/41 87/40 88/39 86/42
+f 87/40 89/46 90/45 88/39
+f 89/46 91/48 92/47 90/45
+f 91/51 93/50 94/49 92/52
+f 93/50 95/54 96/53 94/49
+f 97/56 67/58 68/57 98/55
+f 95/54 97/56 98/55 96/53
+f 70/103 116/104 68/105
+f 67/106 115/107 69/108
+f 69/108 115/107 71/109
+f 71/109 115/107 73/110
+f 73/110 115/107 75/111
+f 75/111 115/107 77/112
+f 77/112 115/107 79/113
+f 79/113 115/107 81/114
+f 81/114 115/107 83/115
+f 83/115 115/107 85/116
+f 85/116 115/107 87/117
+f 87/117 115/107 89/118
+f 89/118 115/107 91/119
+f 91/119 115/107 93/120
+f 93/120 115/107 95/121
+f 95/121 115/107 97/122
+f 97/122 115/107 67/106
+f 68/105 116/104 98/123
+f 98/123 116/104 96/124
+f 96/124 116/104 94/125
+f 94/125 116/104 92/126
+f 92/126 116/104 90/127
+f 90/127 116/104 88/128
+f 88/128 116/104 86/129
+f 86/129 116/104 84/130
+f 84/130 116/104 82/131
+f 82/131 116/104 80/132
+f 80/132 116/104 78/133
+f 78/133 116/104 76/134
+f 76/134 116/104 74/135
+f 74/135 116/104 72/136
+f 72/136 116/104 70/103
+f 107/137 120/1 121/4 108/138
+f 102/139 131/73 132/76 103/140
+f 100/141 129/77 128/80 101/142
+f 113/143 127/81 126/84 114/144
+f 99/145 130/85 129/77 100/141
+f 101/142 128/80 131/73 102/139
+f 114/144 126/84 130/85 99/145
+f 112/146 125/87 127/81 113/143
+f 111/147 124/89 125/87 112/146
+f 110/148 123/91 124/89 111/147
+f 109/149 122/93 123/91 110/148
+f 108/138 121/4 122/93 109/149
+f 106/150 119/95 120/1 107/137
+f 105/151 118/97 119/95 106/150
+f 104/152 117/99 118/97 105/151
+f 103/140 132/76 117/102 104/153
+f 133/58 135/60 136/59 134/57
+f 135/60 137/62 138/61 136/59
+f 137/62 139/64 140/63 138/61
+f 139/64 141/66 142/65 140/63
+f 141/66 143/68 144/67 142/65
+f 143/68 145/70 146/69 144/67
+f 145/70 147/72 148/71 146/69
+f 147/72 149/43 150/44 148/71
+f 149/43 151/41 152/42 150/44
+f 151/41 153/40 154/39 152/42
+f 153/40 155/46 156/45 154/39
+f 155/46 157/48 158/47 156/45
+f 157/51 159/50 160/49 158/52
+f 159/50 161/54 162/53 160/49
+f 163/56 133/58 134/57 164/55
+f 161/54 163/56 164/55 162/53
+f 136/103 182/104 134/105
+f 133/106 181/107 135/108
+f 135/108 181/107 137/109
+f 137/109 181/107 139/110
+f 139/110 181/107 141/111
+f 141/111 181/107 143/112
+f 143/112 181/107 145/113
+f 145/113 181/107 147/114
+f 147/114 181/107 149/115
+f 149/115 181/107 151/116
+f 151/116 181/107 153/117
+f 153/117 181/107 155/118
+f 155/118 181/107 157/119
+f 157/119 181/107 159/120
+f 159/120 181/107 161/121
+f 161/121 181/107 163/122
+f 163/122 181/107 133/106
+f 134/105 182/104 164/123
+f 164/123 182/104 162/124
+f 162/124 182/104 160/125
+f 160/125 182/104 158/126
+f 158/126 182/104 156/127
+f 156/127 182/104 154/128
+f 154/128 182/104 152/129
+f 152/129 182/104 150/130
+f 150/130 182/104 148/131
+f 148/131 182/104 146/132
+f 146/132 182/104 144/133
+f 144/133 182/104 142/134
+f 142/134 182/104 140/135
+f 140/135 182/104 138/136
+f 138/136 182/104 136/103
+f 173/137 223/2 224/3 174/138
+f 213/5 215/6 232/7
+f 211/8 213/5 232/7
+f 209/9 211/8 232/7
+f 207/10 209/9 232/7
+f 205/11 207/10 232/7
+f 203/12 205/11 232/7
+f 201/13 203/12 232/7
+f 199/14 201/13 232/7
+f 197/15 199/14 232/7
+f 195/16 197/15 232/7
+f 193/17 195/16 232/7
+f 191/18 193/17 232/7
+f 189/19 191/18 232/7
+f 187/20 189/19 232/7
+f 217/21 187/20 232/7
+f 188/22 218/23 231/24
+f 190/25 188/22 231/24
+f 192/26 190/25 231/24
+f 194/27 192/26 231/24
+f 196/28 194/27 231/24
+f 198/29 196/28 231/24
+f 200/30 198/29 231/24
+f 202/31 200/30 231/24
+f 204/32 202/31 231/24
+f 206/33 204/32 231/24
+f 208/34 206/33 231/24
+f 210/35 208/34 231/24
+f 212/36 210/35 231/24
+f 214/37 212/36 231/24
+f 216/38 214/37 231/24
+f 218/23 216/38 231/24
+f 215/6 217/21 232/7
+f 190/39 189/40 187/41 188/42
+f 188/42 187/41 217/43 218/44
+f 192/45 191/46 189/40 190/39
+f 194/47 193/48 191/46 192/45
+f 196/49 195/50 193/51 194/52
+f 198/53 197/54 195/50 196/49
+f 200/55 199/56 197/54 198/53
+f 202/57 201/58 199/56 200/55
+f 204/59 203/60 201/58 202/57
+f 206/61 205/62 203/60 204/59
+f 208/63 207/64 205/62 206/61
+f 210/65 209/66 207/64 208/63
+f 212/67 211/68 209/66 210/65
+f 214/69 213/70 211/68 212/67
+f 216/71 215/72 213/70 214/69
+f 218/44 217/43 215/72 216/71
+f 168/139 183/74 219/75 169/140
+f 166/141 185/78 184/79 167/142
+f 179/143 229/82 230/83 180/144
+f 165/145 186/86 185/78 166/141
+f 167/142 184/79 183/74 168/139
+f 180/144 230/83 186/86 165/145
+f 178/146 228/88 229/82 179/143
+f 177/147 227/90 228/88 178/146
+f 176/148 226/92 227/90 177/147
+f 175/149 225/94 226/92 176/148
+f 174/138 224/3 225/94 175/149
+f 172/150 222/96 223/2 173/137
+f 171/151 221/98 222/96 172/150
+f 170/152 220/100 221/98 171/151
+f 169/140 219/75 220/101 170/153
+f 286/1 273/2 274/3 287/4
+f 263/5 265/6 282/7
+f 261/8 263/5 282/7
+f 259/9 261/8 282/7
+f 257/10 259/9 282/7
+f 255/11 257/10 282/7
+f 253/12 255/11 282/7
+f 251/13 253/12 282/7
+f 249/14 251/13 282/7
+f 247/15 249/14 282/7
+f 245/16 247/15 282/7
+f 243/17 245/16 282/7
+f 241/18 243/17 282/7
+f 239/19 241/18 282/7
+f 237/20 239/19 282/7
+f 267/21 237/20 282/7
+f 238/22 268/23 281/24
+f 240/25 238/22 281/24
+f 242/26 240/25 281/24
+f 244/27 242/26 281/24
+f 246/28 244/27 281/24
+f 248/29 246/28 281/24
+f 250/30 248/29 281/24
+f 252/31 250/30 281/24
+f 254/32 252/31 281/24
+f 256/33 254/32 281/24
+f 258/34 256/33 281/24
+f 260/35 258/34 281/24
+f 262/36 260/35 281/24
+f 264/37 262/36 281/24
+f 266/38 264/37 281/24
+f 268/23 266/38 281/24
+f 265/6 267/21 282/7
+f 240/39 239/40 237/41 238/42
+f 238/42 237/41 267/43 268/44
+f 242/45 241/46 239/40 240/39
+f 244/47 243/48 241/46 242/45
+f 246/49 245/50 243/51 244/52
+f 248/53 247/54 245/50 246/49
+f 250/55 249/56 247/54 248/53
+f 252/57 251/58 249/56 250/55
+f 254/59 253/60 251/58 252/57
+f 256/61 255/62 253/60 254/59
+f 258/63 257/64 255/62 256/61
+f 260/65 259/66 257/64 258/63
+f 262/67 261/68 259/66 260/65
+f 264/69 263/70 261/68 262/67
+f 266/71 265/72 263/70 264/69
+f 268/44 267/43 265/72 266/71
+f 297/73 233/74 269/75 298/76
+f 295/77 235/78 234/79 294/80
+f 293/81 279/82 280/83 292/84
+f 296/85 236/86 235/78 295/77
+f 294/80 234/79 233/74 297/73
+f 292/84 280/83 236/86 296/85
+f 291/87 278/88 279/82 293/81
+f 290/89 277/90 278/88 291/87
+f 289/91 276/92 277/90 290/89
+f 288/93 275/94 276/92 289/91
+f 287/4 274/3 275/94 288/93
+f 285/95 272/96 273/2 286/1
+f 284/97 271/98 272/96 285/95
+f 283/99 270/100 271/98 284/97
+f 298/76 269/75 270/101 283/102
diff --git a/pipeworks/models/pipeworks_pump.obj b/pipeworks/models/pipeworks_pump.obj
new file mode 100644
index 0000000..f05dd02
--- /dev/null
+++ b/pipeworks/models/pipeworks_pump.obj
@@ -0,0 +1,282 @@
+# Blender v2.69 (sub 0) OBJ File: 'pipe-pump.blend'
+# www.blender.org
+mtllib pipeworks_pump.mtl
+o Cube
+v -0.500000 -0.500000 0.500000
+v -0.500000 -0.500000 -0.500000
+v 0.500000 -0.500000 -0.500000
+v 0.500000 -0.500000 0.500000
+v -0.500000 -0.375000 0.500000
+v -0.500000 -0.375000 -0.500000
+v 0.500000 -0.375000 -0.500000
+v 0.500000 -0.375000 0.500000
+v -0.437500 -0.375000 0.437500
+v -0.437500 -0.375000 -0.437500
+v 0.437500 -0.375000 -0.437500
+v 0.437500 -0.375000 0.437500
+v -0.437500 0.375000 0.437500
+v -0.437500 0.375000 -0.437500
+v 0.437500 0.375000 -0.437500
+v 0.437500 0.375000 0.437500
+v 0.153248 0.468750 0.030483
+v 0.153248 0.500000 0.030483
+v 0.153248 0.468750 -0.030483
+v 0.153248 0.500000 -0.030483
+v 0.129917 0.468750 -0.086808
+v 0.129917 0.500000 -0.086808
+v 0.086808 0.468750 -0.129917
+v 0.086808 0.500000 -0.129917
+v 0.030483 0.468750 -0.153248
+v 0.030483 0.500000 -0.153248
+v -0.030483 0.468750 -0.153248
+v -0.030483 0.500000 -0.153248
+v -0.086808 0.468750 -0.129917
+v -0.086808 0.500000 -0.129917
+v -0.129917 0.468750 -0.086808
+v -0.129917 0.500000 -0.086808
+v -0.153247 0.468750 -0.030483
+v -0.153247 0.500000 -0.030483
+v -0.153247 0.468750 0.030483
+v -0.153247 0.500000 0.030483
+v -0.129917 0.468750 0.086808
+v -0.129917 0.500000 0.086808
+v -0.086808 0.468750 0.129917
+v -0.086808 0.500000 0.129917
+v -0.030483 0.468750 0.153248
+v -0.030483 0.500000 0.153248
+v 0.030483 0.468750 0.153248
+v 0.030483 0.500000 0.153248
+v 0.086808 0.468750 0.129917
+v 0.086808 0.500000 0.129917
+v 0.129917 0.468750 0.086808
+v 0.129918 0.500000 0.086808
+v 0.122598 0.468750 0.024386
+v 0.122598 0.468750 -0.024386
+v 0.103934 0.468750 -0.069446
+v 0.069447 0.468750 -0.103934
+v 0.024387 0.468750 -0.122598
+v -0.024386 0.468750 -0.122598
+v -0.069446 0.468750 -0.103934
+v -0.103933 0.468750 -0.069446
+v -0.122598 0.468750 -0.024386
+v -0.122598 0.468750 0.024386
+v -0.103933 0.468750 0.069446
+v -0.069446 0.468750 0.103934
+v -0.024386 0.468750 0.122598
+v 0.024387 0.468750 0.122598
+v 0.069447 0.468750 0.103934
+v 0.103934 0.468750 0.069446
+v 0.000000 0.468750 -0.000000
+v 0.000000 0.500000 0.000000
+v 0.122598 0.375003 0.024386
+v 0.122598 0.375003 -0.024386
+v 0.103934 0.375003 -0.069446
+v 0.069446 0.375003 0.103934
+v 0.103934 0.375003 0.069446
+v 0.024386 0.375003 0.122598
+v -0.024386 0.375003 0.122598
+v -0.069446 0.375003 0.103934
+v -0.103934 0.375003 0.069446
+v -0.122598 0.375003 0.024386
+v -0.122598 0.375003 -0.024386
+v -0.103934 0.375003 -0.069446
+v -0.069446 0.375003 -0.103934
+v -0.024386 0.375003 -0.122598
+v 0.069446 0.375003 -0.103934
+v 0.024386 0.375003 -0.122598
+vt 0.714844 0.761719
+vt 0.714844 0.511719
+vt 0.746094 0.511719
+vt 0.746094 0.761719
+vt 0.621094 0.761719
+vt 0.621094 0.511719
+vt 0.652344 0.511719
+vt 0.652344 0.761719
+vt 0.683594 0.761719
+vt 0.683594 0.511719
+vt 0.996094 0.511719
+vt 0.996094 0.761719
+vt 0.996094 0.261719
+vt 0.746094 0.261719
+vt 0.230469 0.261719
+vt 0.449219 0.261719
+vt 0.449219 0.433594
+vt 0.230469 0.433594
+vt 0.222656 0.613281
+vt 0.003906 0.613281
+vt 0.003906 0.441406
+vt 0.222656 0.441406
+vt 0.222656 0.433594
+vt 0.003906 0.433594
+vt 0.003906 0.261719
+vt 0.222656 0.261719
+vt 0.675781 0.433594
+vt 0.457031 0.433594
+vt 0.457031 0.261719
+vt 0.675781 0.261719
+vt 0.230469 0.660156
+vt 0.230469 0.441406
+vt 0.449219 0.441406
+vt 0.449219 0.660156
+vt 0.750000 0.996094
+vt 0.812500 0.996094
+vt 0.812500 0.945313
+vt 0.750000 0.945313
+vt 0.875000 0.996094
+vt 0.875000 0.945313
+vt 0.937500 0.996094
+vt 0.937500 0.945313
+vt 1.000000 0.996094
+vt 1.000000 0.945313
+vt 0.000000 0.996094
+vt 0.062500 0.996094
+vt 0.062500 0.945313
+vt 0.000000 0.945313
+vt 0.125000 0.996094
+vt 0.125000 0.945313
+vt 0.187500 0.996094
+vt 0.187500 0.945313
+vt 0.250000 0.996094
+vt 0.250000 0.945313
+vt 0.312500 0.996094
+vt 0.312500 0.945313
+vt 0.375000 0.996094
+vt 0.375000 0.945313
+vt 0.437500 0.996094
+vt 0.437500 0.945313
+vt 0.500000 0.996094
+vt 0.500000 0.945313
+vt 0.562500 0.996094
+vt 0.562500 0.945313
+vt 0.625000 0.996094
+vt 0.625000 0.945313
+vt 0.687500 0.996094
+vt 0.687500 0.945313
+vt 0.007550 0.738767
+vt 0.046892 0.730976
+vt 0.007550 0.723186
+vt 0.101275 0.738767
+vt 0.140617 0.730976
+vt 0.101275 0.723186
+vt 0.107265 0.708790
+vt 0.118332 0.697773
+vt 0.132792 0.691810
+vt 0.148443 0.691810
+vt 0.162903 0.697773
+vt 0.173970 0.708790
+vt 0.179959 0.723186
+vt 0.179959 0.738767
+vt 0.173970 0.753163
+vt 0.162903 0.764180
+vt 0.148443 0.770143
+vt 0.132792 0.770143
+vt 0.118332 0.764180
+vt 0.107265 0.753163
+vt 0.013540 0.708790
+vt 0.024607 0.697773
+vt 0.039067 0.691810
+vt 0.054718 0.691810
+vt 0.069178 0.697773
+vt 0.080245 0.708790
+vt 0.086234 0.723186
+vt 0.086234 0.738767
+vt 0.080245 0.753162
+vt 0.069178 0.764180
+vt 0.054718 0.770143
+vt 0.039067 0.770143
+vt 0.024607 0.764180
+vt 0.013540 0.753162
+vt 0.250000 0.777344
+vt 0.312500 0.777344
+vt 0.937500 0.777344
+vt 1.000000 0.777344
+vt 0.812500 0.777344
+vt 0.875000 0.777344
+vt 0.625000 0.777344
+vt 0.687500 0.777344
+vt 0.750000 0.777344
+vt 0.562500 0.777344
+vt 0.500000 0.777344
+vt 0.437500 0.777344
+vt 0.375000 0.777344
+vt 0.187500 0.777344
+vt 0.125000 0.777344
+vt 0.062500 0.777344
+vt 0.000000 0.777344
+usemtl None
+s off
+f 5/1 6/2 2/3 1/4
+f 6/5 7/6 3/7 2/8
+f 7/9 8/10 4/2 3/1
+f 8/10 5/9 1/8 4/7
+f 1/4 2/3 3/11 4/12
+f 8/13 7/11 6/3 5/14
+f 13/15 14/16 10/17 9/18
+f 14/19 15/20 11/21 10/22
+f 15/23 16/24 12/25 11/26
+f 16/27 13/28 9/29 12/30
+f 16/31 15/32 14/33 13/34
+f 17/35 19/36 20/37 18/38
+f 19/36 21/39 22/40 20/37
+f 21/39 23/41 24/42 22/40
+f 23/41 25/43 26/44 24/42
+f 25/45 27/46 28/47 26/48
+f 27/46 29/49 30/50 28/47
+f 29/49 31/51 32/52 30/50
+f 31/51 33/53 34/54 32/52
+f 33/53 35/55 36/56 34/54
+f 35/55 37/57 38/58 36/56
+f 37/57 39/59 40/60 38/58
+f 39/59 41/61 42/62 40/60
+f 41/61 43/63 44/64 42/62
+f 43/63 45/65 46/66 44/64
+f 47/67 17/35 18/38 48/68
+f 45/65 47/67 48/68 46/66
+f 20/69 66/70 18/71
+f 17/72 65/73 19/74
+f 19/74 65/73 21/75
+f 21/75 65/73 23/76
+f 23/76 65/73 25/77
+f 25/77 65/73 27/78
+f 27/78 65/73 29/79
+f 29/79 65/73 31/80
+f 31/80 65/73 33/81
+f 33/81 65/73 35/82
+f 35/82 65/73 37/83
+f 37/83 65/73 39/84
+f 39/84 65/73 41/85
+f 41/85 65/73 43/86
+f 43/86 65/73 45/87
+f 45/87 65/73 47/88
+f 47/88 65/73 17/72
+f 18/71 66/70 48/89
+f 48/89 66/70 46/90
+f 46/90 66/70 44/91
+f 44/91 66/70 42/92
+f 42/92 66/70 40/93
+f 40/93 66/70 38/94
+f 38/94 66/70 36/95
+f 36/95 66/70 34/96
+f 34/96 66/70 32/97
+f 32/97 66/70 30/98
+f 30/98 66/70 28/99
+f 28/99 66/70 26/100
+f 26/100 66/70 24/101
+f 24/101 66/70 22/102
+f 22/102 66/70 20/69
+f 57/54 77/103 76/104 58/56
+f 52/42 81/105 82/106 53/44
+f 50/37 68/107 69/108 51/40
+f 63/66 70/109 71/110 64/68
+f 49/38 67/111 68/107 50/37
+f 51/40 69/108 81/105 52/42
+f 64/68 71/110 67/111 49/38
+f 62/64 72/112 70/109 63/66
+f 61/62 73/113 72/112 62/64
+f 60/60 74/114 73/113 61/62
+f 59/58 75/115 74/114 60/60
+f 58/56 76/104 75/115 59/58
+f 56/52 78/116 77/103 57/54
+f 55/50 79/117 78/116 56/52
+f 54/47 80/118 79/117 55/50
+f 53/48 82/119 80/118 54/47
diff --git a/pipeworks/models/pipeworks_spigot.obj b/pipeworks/models/pipeworks_spigot.obj
new file mode 100644
index 0000000..f6e80c9
--- /dev/null
+++ b/pipeworks/models/pipeworks_spigot.obj
@@ -0,0 +1,512 @@
+# Blender v2.69 (sub 0) OBJ File: 'pipe-spigot.blend'
+# www.blender.org
+mtllib pipeworks_spigot.mtl
+o pipe.000_Cylinder.001
+v -0.122598 -0.024391 -0.024386
+v -0.122598 -0.024391 0.024386
+v 0.129917 -0.250000 -0.086808
+v 0.153247 -0.250000 -0.030483
+v -0.000000 -0.250000 -0.000000
+v 0.086808 -0.250000 -0.129917
+v 0.030483 -0.250000 -0.153248
+v -0.030483 -0.250000 -0.153248
+v -0.086808 -0.250000 -0.129917
+v -0.129917 -0.250000 -0.086808
+v -0.153248 -0.250000 -0.030483
+v -0.153248 -0.250000 0.030483
+v -0.129917 -0.250000 0.086808
+v -0.086808 -0.250000 0.129917
+v -0.030483 -0.250000 0.153247
+v 0.030483 -0.250000 0.153248
+v 0.086808 -0.250000 0.129917
+v 0.129917 -0.250000 0.086808
+v 0.153247 -0.250000 0.030483
+v 0.129917 -0.187500 0.086808
+v 0.153248 -0.187500 0.030483
+v -0.000000 -0.187500 -0.000000
+v 0.086808 -0.187500 0.129917
+v 0.030483 -0.187500 0.153248
+v -0.030483 -0.187500 0.153247
+v -0.086808 -0.187500 0.129917
+v -0.129917 -0.187500 0.086808
+v -0.153248 -0.187500 0.030483
+v -0.153248 -0.187500 -0.030483
+v -0.129917 -0.187500 -0.086808
+v -0.086808 -0.187500 -0.129917
+v -0.030483 -0.187500 -0.153248
+v 0.030483 -0.187500 -0.153248
+v 0.086808 -0.187500 -0.129917
+v 0.129917 -0.187500 -0.086808
+v 0.153248 -0.187500 -0.030483
+v 0.069446 -0.024391 -0.103934
+v 0.024386 -0.024391 -0.122598
+v 0.122598 -0.024391 -0.024386
+v 0.103934 -0.024391 -0.069446
+v 0.069446 -0.024391 0.103934
+v 0.103934 -0.024391 0.069446
+v 0.122598 -0.024391 0.024386
+v 0.024386 -0.024391 0.122598
+v -0.024386 -0.024391 0.122598
+v -0.069446 -0.024391 0.103934
+v -0.103934 -0.024391 0.069446
+v -0.103934 -0.024391 -0.069446
+v -0.069446 -0.024391 -0.103934
+v -0.024386 -0.024391 -0.122598
+v -0.103934 0.041589 -0.041924
+v 0.103934 0.041589 -0.041925
+v 0.122598 0.009727 -0.010062
+v 0.024386 0.079173 -0.079509
+v 0.069446 0.065976 -0.066311
+v 0.069446 0.094826 -0.024663
+v -0.103934 0.062964 -0.011464
+v -0.069446 0.094827 -0.024662
+v -0.024386 0.112070 -0.031805
+v 0.024386 0.112070 -0.031805
+v 0.122598 0.021334 0.005779
+v 0.103934 0.062964 -0.011464
+v -0.122598 0.021334 0.005780
+v -0.024386 0.079173 -0.079509
+v -0.069446 0.065976 -0.066311
+v -0.122599 -0.024387 0.468750
+v -0.122599 0.024386 0.468750
+v -0.122598 0.024386 0.024391
+v 0.129917 -0.086808 0.500000
+v 0.153247 -0.030483 0.500000
+v -0.000001 0.000000 0.500000
+v 0.086807 -0.129917 0.500000
+v 0.030482 -0.153248 0.500000
+v -0.030483 -0.153248 0.500000
+v -0.086808 -0.129917 0.500000
+v -0.129918 -0.086808 0.500000
+v -0.153248 -0.030483 0.500000
+v -0.153248 0.030483 0.500000
+v -0.129918 0.086808 0.500000
+v -0.086808 0.129917 0.500000
+v -0.030483 0.153247 0.500000
+v 0.030482 0.153247 0.500000
+v 0.086807 0.129917 0.500000
+v 0.129917 0.086808 0.500000
+v 0.153247 0.030483 0.500000
+v 0.129917 0.086808 0.468750
+v 0.153247 0.030483 0.468750
+v 0.000000 0.000000 0.468750
+v 0.086807 0.129917 0.468750
+v 0.030482 0.153247 0.468750
+v -0.030483 0.153247 0.468750
+v -0.086808 0.129917 0.468750
+v -0.129918 0.086808 0.468750
+v -0.153248 0.030483 0.468750
+v -0.153248 -0.030483 0.468750
+v -0.129918 -0.086808 0.468750
+v -0.086808 -0.129917 0.468750
+v -0.030483 -0.153248 0.468750
+v 0.030482 -0.153248 0.468750
+v 0.086807 -0.129917 0.468750
+v 0.129917 -0.086808 0.468750
+v 0.153247 -0.030483 0.468750
+v 0.069446 -0.103934 0.024391
+v 0.069446 -0.103934 0.468750
+v 0.024386 -0.122598 0.468750
+v 0.024386 -0.122598 0.024391
+v 0.122598 -0.024387 0.468750
+v 0.103933 -0.069447 0.468750
+v 0.103934 -0.069446 0.024391
+v 0.069446 0.103933 0.468750
+v 0.103933 0.069446 0.468750
+v 0.103934 0.069446 0.024391
+v 0.122598 0.024386 0.024391
+v 0.122598 0.024386 0.468750
+v 0.024386 0.122598 0.024391
+v 0.024386 0.122598 0.468750
+v -0.024386 0.122598 0.024391
+v -0.024387 0.122598 0.468750
+v -0.069446 0.103934 0.024391
+v -0.069447 0.103933 0.468750
+v -0.103934 0.069446 0.024391
+v -0.103934 0.069446 0.468750
+v -0.103934 -0.069446 0.024391
+v -0.103934 -0.069447 0.468750
+v -0.069446 -0.103934 0.024391
+v -0.069447 -0.103934 0.468750
+v -0.024386 -0.122598 0.024391
+v -0.024387 -0.122598 0.468750
+v 0.069446 0.103934 0.024390
+v -0.122598 -0.005780 -0.020763
+v -0.024386 0.031804 -0.111499
+v -0.069446 0.024662 -0.094256
+v -0.103934 0.011464 -0.062393
+v 0.103934 0.011464 -0.062393
+v 0.122598 -0.005780 -0.020763
+v 0.024386 0.031804 -0.111499
+v 0.069446 0.024662 -0.094256
+v -0.122598 0.009727 -0.010062
+v -0.122598 -0.246570 0.024386
+v -0.103934 -0.246570 0.069446
+v -0.069447 -0.246570 0.103934
+v -0.122598 -0.246570 -0.024386
+v 0.069446 -0.246571 0.103933
+v 0.122598 -0.246571 0.024386
+v 0.103934 -0.246571 0.069446
+v 0.103933 -0.246571 -0.069446
+v -0.024386 -0.246570 0.122598
+v 0.122598 -0.246571 -0.024386
+v -0.024386 -0.246571 -0.122598
+v 0.024386 -0.246571 -0.122598
+v 0.069446 -0.246571 -0.103934
+v -0.103934 -0.246570 -0.069446
+v -0.069446 -0.246570 -0.103934
+v 0.024386 -0.246570 0.122598
+vt 0.139725 0.682190
+vt 0.199773 0.657318
+vt 0.232270 0.820694
+vt 0.093767 0.728149
+vt 0.068894 0.788196
+vt 0.068894 0.853192
+vt 0.093767 0.913239
+vt 0.139725 0.959198
+vt 0.199773 0.984070
+vt 0.264768 0.984070
+vt 0.324816 0.959198
+vt 0.370774 0.913239
+vt 0.395647 0.853192
+vt 0.395647 0.788196
+vt 0.370774 0.728149
+vt 0.324816 0.682190
+vt 0.264768 0.657318
+vt 0.487410 0.682190
+vt 0.547457 0.657318
+vt 0.579955 0.820694
+vt 0.441451 0.728149
+vt 0.416578 0.788196
+vt 0.416578 0.853192
+vt 0.441451 0.913239
+vt 0.487410 0.959198
+vt 0.547457 0.984070
+vt 0.612452 0.984070
+vt 0.672500 0.959198
+vt 0.718459 0.913239
+vt 0.743331 0.853192
+vt 0.743331 0.788196
+vt 0.718459 0.728149
+vt 0.672500 0.682190
+vt 0.612452 0.657318
+vt 0.125000 0.640625
+vt 0.125000 0.578125
+vt 0.187500 0.578125
+vt 0.187500 0.640625
+vt 0.250000 0.578125
+vt 0.250000 0.640625
+vt 0.062500 0.640625
+vt 0.062500 0.578125
+vt 0.000000 0.640625
+vt 0.000000 0.578125
+vt 0.937500 0.640625
+vt 0.937500 0.578125
+vt 1.000000 0.578125
+vt 1.000000 0.640625
+vt 0.875000 0.640625
+vt 0.875000 0.578125
+vt 0.812500 0.640625
+vt 0.812500 0.578125
+vt 0.750000 0.640625
+vt 0.750000 0.578125
+vt 0.687500 0.640625
+vt 0.687500 0.578125
+vt 0.625000 0.640625
+vt 0.625000 0.578125
+vt 0.562500 0.640625
+vt 0.562500 0.578125
+vt 0.500000 0.640625
+vt 0.500000 0.578125
+vt 0.437500 0.640625
+vt 0.437500 0.578125
+vt 0.375000 0.640625
+vt 0.375000 0.578125
+vt 0.312500 0.640625
+vt 0.312500 0.578125
+vt 0.187500 0.453125
+vt 0.125000 0.453125
+vt 0.139892 0.682190
+vt 0.199940 0.657318
+vt 0.232437 0.820694
+vt 0.093934 0.728149
+vt 0.069061 0.788196
+vt 0.069061 0.853192
+vt 0.093934 0.913239
+vt 0.139892 0.959198
+vt 0.199940 0.984070
+vt 0.264935 0.984070
+vt 0.324983 0.959198
+vt 0.370941 0.913239
+vt 0.395814 0.853192
+vt 0.395814 0.788196
+vt 0.370941 0.728149
+vt 0.324983 0.682190
+vt 0.264935 0.657318
+vt 0.875000 0.265625
+vt 0.875000 0.015625
+vt 0.937500 0.015625
+vt 0.937500 0.265625
+vt 0.812500 0.265625
+vt 0.812500 0.015625
+vt 0.625000 0.265625
+vt 0.625000 0.015625
+vt 0.687500 0.015625
+vt 0.687500 0.265625
+vt 0.437500 0.265625
+vt 0.437500 0.015625
+vt 0.500000 0.015625
+vt 0.500000 0.265625
+vt 0.375000 0.265625
+vt 0.375000 0.015625
+vt 0.312500 0.265625
+vt 0.312500 0.015625
+vt 0.250000 0.265625
+vt 0.250000 0.015625
+vt 0.062500 0.265625
+vt 0.062500 0.015625
+vt 0.125000 0.015625
+vt 0.125000 0.265625
+vt 0.000000 0.265625
+vt 0.000000 0.015625
+vt 1.000000 0.015625
+vt 1.000000 0.265625
+vt 0.187500 0.265625
+vt 0.187500 0.015625
+vt 0.750000 0.265625
+vt 0.750000 0.015625
+vt 0.562500 0.265625
+vt 0.562500 0.015625
+vt 0.000000 0.999989
+vt 0.000000 0.890943
+vt 0.041611 0.899043
+vt 0.941956 0.794823
+vt 0.941956 0.841698
+vt 0.895081 0.841698
+vt 0.895081 0.794823
+vt 0.848206 0.841698
+vt 0.848206 0.794823
+vt 0.801331 0.794823
+vt 0.801331 0.841698
+vt 0.754456 0.841698
+vt 0.754456 0.794823
+vt 0.988831 0.794823
+vt 0.988831 0.841698
+vt 0.941956 0.701073
+vt 0.941956 0.747948
+vt 0.895081 0.747948
+vt 0.895081 0.701073
+vt 0.041611 0.741571
+vt 0.000000 0.749671
+vt 0.076282 0.717645
+vt 0.102233 0.682226
+vt 0.109057 0.640614
+vt 0.754456 0.747948
+vt 0.801331 0.747948
+vt 0.848206 0.747948
+vt 0.848206 0.701073
+vt 0.941956 0.888573
+vt 0.988831 0.888573
+vt 0.895081 0.888573
+vt 0.848206 0.888573
+vt 0.076282 0.922969
+vt 0.102233 0.958388
+vt 0.109057 1.000000
+vt 0.801331 0.888573
+vt 0.754456 0.888573
+vt 0.801331 0.935448
+vt 0.754456 0.935448
+vt 0.754456 0.982323
+vt 0.801331 0.982323
+vt 0.848206 0.935448
+vt 0.848206 0.982323
+vt 0.895081 0.935448
+vt 0.895081 0.982323
+vt 0.941956 0.935448
+vt 0.941956 0.982323
+vt 0.988831 0.982323
+vt 0.988831 0.935448
+vt 0.801331 0.701073
+vt 0.754456 0.701073
+vt 0.250000 0.453125
+vt 0.875000 0.453125
+vt 0.937500 0.453125
+vt 0.750000 0.453125
+vt 0.812500 0.453125
+vt 0.562500 0.453125
+vt 0.625000 0.453125
+vt 0.687500 0.453125
+vt 0.500000 0.453125
+vt 0.437500 0.453125
+vt 0.375000 0.453125
+vt 0.312500 0.453125
+vt 0.062500 0.453125
+vt 0.000000 0.453125
+vt 1.000000 0.453125
+g pipe.000_Cylinder.001_metal
+usemtl metal
+s off
+f 3/1 4/2 5/3
+f 6/4 3/1 5/3
+f 7/5 6/4 5/3
+f 8/6 7/5 5/3
+f 9/7 8/6 5/3
+f 10/8 9/7 5/3
+f 11/9 10/8 5/3
+f 12/10 11/9 5/3
+f 13/11 12/10 5/3
+f 14/12 13/11 5/3
+f 15/13 14/12 5/3
+f 16/14 15/13 5/3
+f 17/15 16/14 5/3
+f 18/16 17/15 5/3
+f 19/17 18/16 5/3
+f 20/18 21/19 22/20
+f 23/21 20/18 22/20
+f 24/22 23/21 22/20
+f 25/23 24/22 22/20
+f 26/24 25/23 22/20
+f 27/25 26/24 22/20
+f 28/26 27/25 22/20
+f 29/27 28/26 22/20
+f 30/28 29/27 22/20
+f 31/29 30/28 22/20
+f 32/30 31/29 22/20
+f 33/31 32/30 22/20
+f 34/32 33/31 22/20
+f 35/33 34/32 22/20
+f 36/34 35/33 22/20
+f 21/19 36/34 22/20
+f 4/2 19/17 5/3
+f 23/35 17/36 18/37 20/38
+f 20/38 18/37 19/39 21/40
+f 24/41 16/42 17/36 23/35
+f 25/43 15/44 16/42 24/41
+f 26/45 14/46 15/47 25/48
+f 27/49 13/50 14/46 26/45
+f 28/51 12/52 13/50 27/49
+f 29/53 11/54 12/52 28/51
+f 30/55 10/56 11/54 29/53
+f 31/57 9/58 10/56 30/55
+f 32/59 8/60 9/58 31/57
+f 33/61 7/62 8/60 32/59
+f 34/63 6/64 7/62 33/61
+f 35/65 3/66 6/64 34/63
+f 36/67 4/68 3/66 35/65
+f 21/40 19/39 4/68 36/67
+f 142/69 1/37 48/36 152/70
+f 69/71 70/72 71/73
+f 72/74 69/71 71/73
+f 73/75 72/74 71/73
+f 74/76 73/75 71/73
+f 75/77 74/76 71/73
+f 76/78 75/77 71/73
+f 77/79 76/78 71/73
+f 78/80 77/79 71/73
+f 79/81 78/80 71/73
+f 80/82 79/81 71/73
+f 81/83 80/82 71/73
+f 82/84 81/83 71/73
+f 83/85 82/84 71/73
+f 84/86 83/85 71/73
+f 85/87 84/86 71/73
+f 86/18 87/19 88/20
+f 89/21 86/18 88/20
+f 90/22 89/21 88/20
+f 91/23 90/22 88/20
+f 92/24 91/23 88/20
+f 93/25 92/24 88/20
+f 94/26 93/25 88/20
+f 95/27 94/26 88/20
+f 96/28 95/27 88/20
+f 97/29 96/28 88/20
+f 98/30 97/29 88/20
+f 99/31 98/30 88/20
+f 100/32 99/31 88/20
+f 101/33 100/32 88/20
+f 102/34 101/33 88/20
+f 87/19 102/34 88/20
+f 70/72 85/87 71/73
+f 89/35 83/36 84/37 86/38
+f 86/38 84/37 85/39 87/40
+f 90/41 82/42 83/36 89/35
+f 91/43 81/44 82/42 90/41
+f 92/45 80/46 81/47 91/48
+f 93/49 79/50 80/46 92/45
+f 94/51 78/52 79/50 93/49
+f 95/53 77/54 78/52 94/51
+f 96/55 76/56 77/54 95/53
+f 97/57 75/58 76/56 96/55
+f 98/59 74/60 75/58 97/57
+f 99/61 73/62 74/60 98/59
+f 100/63 72/64 73/62 99/61
+f 101/65 69/66 72/64 100/63
+f 102/67 70/68 69/66 101/65
+f 87/40 85/39 70/68 102/67
+f 103/88 104/89 105/90 106/91
+f 109/92 108/93 104/89 103/88
+f 112/94 111/95 114/96 113/97
+f 117/98 118/99 116/100 115/101
+f 119/102 120/103 118/99 117/98
+f 121/104 122/105 120/103 119/102
+f 68/106 67/107 122/105 121/104
+f 125/108 126/109 124/110 123/111
+f 127/112 128/113 126/109 125/108
+f 106/91 105/90 128/114 127/115
+f 2/116 66/117 67/107 68/106
+f 43/118 107/119 108/93 109/92
+f 129/120 110/121 111/95 112/94
+f 113/97 114/96 107/119 43/118
+f 115/101 116/100 110/121 129/120
+f 123/111 124/110 66/117 2/116
+f 43/122 39/123 135/124
+f 50/125 131/126 136/127 38/128
+f 38/128 136/127 137/129 37/130
+f 40/131 37/130 137/129 134/132
+f 40/131 134/132 135/133 39/134
+f 50/125 49/135 132/136 131/126
+f 49/137 48/138 133/139 132/140
+f 48/138 1/125 130/128 133/139
+f 2/43 130/141 1/142
+f 2/43 138/143 130/141
+f 2/43 63/144 138/143
+f 63/144 2/43 68/145
+f 121/146 57/147 63/131 68/134
+f 57/147 51/148 138/130 63/131
+f 133/139 130/128 138/130 51/148
+f 65/149 132/140 133/139 51/148
+f 64/150 131/126 132/136 65/151
+f 64/150 54/152 136/127 131/126
+f 54/152 55/153 137/129 136/127
+f 43/122 135/124 53/154
+f 43/122 53/154 61/155
+f 61/155 113/156 43/122
+f 134/132 52/157 53/158 135/133
+f 62/159 61/160 53/158 52/157
+f 52/157 134/132 137/129 55/153
+f 113/161 61/160 62/159 112/162
+f 62/159 52/157 55/153 56/163
+f 62/159 56/163 129/164 112/162
+f 60/165 56/163 55/153 54/152
+f 60/165 115/166 129/164 56/163
+f 64/150 59/167 60/165 54/152
+f 117/168 115/166 60/165 59/167
+f 119/169 117/168 59/167 58/170
+f 59/167 64/150 65/151 58/170
+f 58/171 65/149 51/148 57/147
+f 121/146 119/172 58/171 57/147
+f 1/37 142/69 139/173 2/39
+f 37/50 151/174 150/175 38/46
+f 39/54 148/176 146/177 40/52
+f 41/60 143/178 145/179 42/58
+f 43/56 144/180 148/176 39/54
+f 40/52 146/177 151/174 37/50
+f 42/58 145/179 144/180 43/56
+f 44/62 154/181 143/178 41/60
+f 45/64 147/182 154/181 44/62
+f 46/66 141/183 147/182 45/64
+f 47/68 140/184 141/183 46/66
+f 2/39 139/173 140/184 47/68
+f 49/42 153/185 152/70 48/36
+f 50/44 149/186 153/185 49/42
+f 38/46 150/175 149/187 50/47
diff --git a/pipeworks/models/pipeworks_spigot_pouring.obj b/pipeworks/models/pipeworks_spigot_pouring.obj
new file mode 100644
index 0000000..50f653c
--- /dev/null
+++ b/pipeworks/models/pipeworks_spigot_pouring.obj
@@ -0,0 +1,634 @@
+# Blender v2.69 (sub 0) OBJ File: 'pipe-spigot-pouring.blend'
+# www.blender.org
+mtllib pipeworks_spigot_pouring.mtl
+o pipe.001_Cylinder.000
+v -0.094401 -0.559070 0.018777
+v -0.080029 -0.559070 0.053473
+v -0.053474 -0.559070 0.080029
+v -0.094401 -0.559070 -0.018778
+v 0.053473 -0.559070 0.080029
+v 0.094400 -0.559070 0.018777
+v 0.080029 -0.559070 0.053473
+v 0.080029 -0.559071 -0.053474
+v -0.018777 -0.559070 0.094400
+v 0.094400 -0.559071 -0.018777
+v -0.018777 -0.559071 -0.094401
+v 0.018777 -0.559071 -0.094401
+v 0.053473 -0.559071 -0.080029
+v -0.080029 -0.559070 -0.053474
+v -0.053474 -0.559070 -0.080029
+v 0.018777 -0.559070 0.094400
+v -0.000000 -0.559070 -0.000000
+v -0.094401 -0.243141 0.018777
+v -0.080029 -0.243141 0.053473
+v -0.053474 -0.243141 0.080029
+v -0.094401 -0.243141 -0.018778
+v 0.053473 -0.243141 0.080029
+v 0.094400 -0.243141 0.018777
+v 0.080029 -0.243141 0.053473
+v 0.080029 -0.243141 -0.053474
+v -0.018777 -0.243141 0.094400
+v 0.094400 -0.243141 -0.018777
+v -0.018777 -0.243141 -0.094401
+v 0.018777 -0.243141 -0.094401
+v 0.053473 -0.243141 -0.080029
+v -0.080029 -0.243141 -0.053474
+v -0.053474 -0.243141 -0.080029
+v 0.018777 -0.243141 0.094400
+vt 0.499995 0.000000
+vt 0.374998 0.000000
+vt 0.375003 1.000000
+vt 0.500001 1.000000
+vt 0.249999 0.000000
+vt 0.250003 1.000000
+vt 0.124999 0.000000
+vt 0.125002 1.000000
+vt 0.874999 0.000000
+vt 0.750001 0.000000
+vt 0.750000 1.000000
+vt 0.874999 1.000000
+vt 0.625002 0.000000
+vt 0.624999 1.000000
+vt 0.500003 0.000000
+vt 0.499998 1.000000
+vt 0.375006 0.000000
+vt 0.375000 1.000000
+vt 0.250008 0.000000
+vt 0.250001 1.000000
+vt 0.125008 0.000000
+vt 0.000010 0.000000
+vt 0.000000 1.000000
+vt 0.125000 1.000000
+vt 0.749993 0.000000
+vt 0.624993 0.000000
+vt 0.625001 1.000000
+vt 0.750002 1.000000
+vt 0.999987 0.000000
+vt 0.874991 0.000000
+vt 0.875002 1.000000
+vt 1.000000 1.000000
+vt 0.999997 0.000000
+vt 0.999998 1.000000
+vt 0.000003 1.000000
+vt 0.000002 0.000000
+vt 0.000000 0.400543
+vt 0.076119 0.216772
+vt 0.500000 0.500000
+vt 0.216773 0.076119
+vt 0.400545 0.000000
+vt 0.599455 0.000000
+vt 0.783226 0.076119
+vt 0.923879 0.216773
+vt 1.000000 0.400544
+vt 1.000000 0.599455
+vt 0.923881 0.783226
+vt 0.783227 0.923879
+vt 0.599455 1.000000
+vt 0.400545 1.000000
+vt 0.216772 0.923879
+vt 0.076119 0.783227
+vt 0.000000 0.599455
+g pipe.001_Cylinder.000_water
+usemtl water
+s off
+f 12/1 11/2 28/3 29/4
+f 11/2 15/5 32/6 28/3
+f 15/5 14/7 31/8 32/6
+f 1/9 2/10 19/11 18/12
+f 2/10 3/13 20/14 19/11
+f 3/13 9/15 26/16 20/14
+f 9/15 16/17 33/18 26/16
+f 16/17 5/19 22/20 33/18
+f 7/21 6/22 23/23 24/24
+f 8/25 13/26 30/27 25/28
+f 6/29 10/30 27/31 23/32
+f 5/19 7/21 24/24 22/20
+f 10/30 8/25 25/28 27/31
+f 13/26 12/1 29/4 30/27
+f 4/33 1/9 18/12 21/34
+f 21/35 31/8 14/7 4/36
+f 4/37 14/38 17/39
+f 14/38 15/40 17/39
+f 15/40 11/41 17/39
+f 11/41 12/42 17/39
+f 12/42 13/43 17/39
+f 13/43 8/44 17/39
+f 8/44 10/45 17/39
+f 10/45 6/46 17/39
+f 6/46 7/47 17/39
+f 7/47 5/48 17/39
+f 5/48 16/49 17/39
+f 16/49 9/50 17/39
+f 9/50 3/51 17/39
+f 3/51 2/52 17/39
+f 2/52 1/53 17/39
+f 1/53 4/37 17/39
+o pipe.000_Cylinder.001
+v -0.122598 -0.024391 -0.024386
+v -0.122598 -0.024391 0.024386
+v 0.129917 -0.250000 -0.086808
+v 0.153247 -0.250000 -0.030483
+v -0.000000 -0.250000 -0.000000
+v 0.086808 -0.250000 -0.129917
+v 0.030483 -0.250000 -0.153248
+v -0.030483 -0.250000 -0.153248
+v -0.086808 -0.250000 -0.129917
+v -0.129917 -0.250000 -0.086808
+v -0.153248 -0.250000 -0.030483
+v -0.153248 -0.250000 0.030483
+v -0.129917 -0.250000 0.086808
+v -0.086808 -0.250000 0.129917
+v -0.030483 -0.250000 0.153247
+v 0.030483 -0.250000 0.153248
+v 0.086808 -0.250000 0.129917
+v 0.129917 -0.250000 0.086808
+v 0.153247 -0.250000 0.030483
+v 0.129917 -0.187500 0.086808
+v 0.153248 -0.187500 0.030483
+v -0.000000 -0.187500 -0.000000
+v 0.086808 -0.187500 0.129917
+v 0.030483 -0.187500 0.153248
+v -0.030483 -0.187500 0.153247
+v -0.086808 -0.187500 0.129917
+v -0.129917 -0.187500 0.086808
+v -0.153248 -0.187500 0.030483
+v -0.153248 -0.187500 -0.030483
+v -0.129917 -0.187500 -0.086808
+v -0.086808 -0.187500 -0.129917
+v -0.030483 -0.187500 -0.153248
+v 0.030483 -0.187500 -0.153248
+v 0.086808 -0.187500 -0.129917
+v 0.129917 -0.187500 -0.086808
+v 0.153248 -0.187500 -0.030483
+v 0.069446 -0.024391 -0.103934
+v 0.024386 -0.024391 -0.122598
+v 0.122598 -0.024391 -0.024386
+v 0.103934 -0.024391 -0.069446
+v 0.069446 -0.024391 0.103934
+v 0.103934 -0.024391 0.069446
+v 0.122598 -0.024391 0.024386
+v 0.024386 -0.024391 0.122598
+v -0.024386 -0.024391 0.122598
+v -0.069446 -0.024391 0.103934
+v -0.103934 -0.024391 0.069446
+v -0.103934 -0.024391 -0.069446
+v -0.069446 -0.024391 -0.103934
+v -0.024386 -0.024391 -0.122598
+v -0.103934 0.041589 -0.041924
+v 0.103934 0.041589 -0.041925
+v 0.122598 0.009727 -0.010062
+v 0.024386 0.079173 -0.079509
+v 0.069446 0.065976 -0.066311
+v 0.069446 0.094826 -0.024663
+v -0.103934 0.062964 -0.011464
+v -0.069446 0.094827 -0.024662
+v -0.024386 0.112070 -0.031805
+v 0.024386 0.112070 -0.031805
+v 0.122598 0.021334 0.005779
+v 0.103934 0.062964 -0.011464
+v -0.122598 0.021334 0.005780
+v -0.024386 0.079173 -0.079509
+v -0.069446 0.065976 -0.066311
+v -0.122599 -0.024387 0.468750
+v -0.122599 0.024386 0.468750
+v -0.122598 0.024386 0.024391
+v 0.129917 -0.086808 0.500000
+v 0.153247 -0.030483 0.500000
+v -0.000001 0.000000 0.500000
+v 0.086807 -0.129917 0.500000
+v 0.030482 -0.153248 0.500000
+v -0.030483 -0.153248 0.500000
+v -0.086808 -0.129917 0.500000
+v -0.129918 -0.086808 0.500000
+v -0.153248 -0.030483 0.500000
+v -0.153248 0.030483 0.500000
+v -0.129918 0.086808 0.500000
+v -0.086808 0.129917 0.500000
+v -0.030483 0.153247 0.500000
+v 0.030482 0.153247 0.500000
+v 0.086807 0.129917 0.500000
+v 0.129917 0.086808 0.500000
+v 0.153247 0.030483 0.500000
+v 0.129917 0.086808 0.468750
+v 0.153247 0.030483 0.468750
+v 0.000000 0.000000 0.468750
+v 0.086807 0.129917 0.468750
+v 0.030482 0.153247 0.468750
+v -0.030483 0.153247 0.468750
+v -0.086808 0.129917 0.468750
+v -0.129918 0.086808 0.468750
+v -0.153248 0.030483 0.468750
+v -0.153248 -0.030483 0.468750
+v -0.129918 -0.086808 0.468750
+v -0.086808 -0.129917 0.468750
+v -0.030483 -0.153248 0.468750
+v 0.030482 -0.153248 0.468750
+v 0.086807 -0.129917 0.468750
+v 0.129917 -0.086808 0.468750
+v 0.153247 -0.030483 0.468750
+v 0.069446 -0.103934 0.024391
+v 0.069446 -0.103934 0.468750
+v 0.024386 -0.122598 0.468750
+v 0.024386 -0.122598 0.024391
+v 0.122598 -0.024387 0.468750
+v 0.103933 -0.069447 0.468750
+v 0.103934 -0.069446 0.024391
+v 0.069446 0.103933 0.468750
+v 0.103933 0.069446 0.468750
+v 0.103934 0.069446 0.024391
+v 0.122598 0.024386 0.024391
+v 0.122598 0.024386 0.468750
+v 0.024386 0.122598 0.024391
+v 0.024386 0.122598 0.468750
+v -0.024386 0.122598 0.024391
+v -0.024387 0.122598 0.468750
+v -0.069446 0.103934 0.024391
+v -0.069447 0.103933 0.468750
+v -0.103934 0.069446 0.024391
+v -0.103934 0.069446 0.468750
+v -0.103934 -0.069446 0.024391
+v -0.103934 -0.069447 0.468750
+v -0.069446 -0.103934 0.024391
+v -0.069447 -0.103934 0.468750
+v -0.024386 -0.122598 0.024391
+v -0.024387 -0.122598 0.468750
+v 0.069446 0.103934 0.024390
+v -0.122598 -0.005780 -0.020763
+v -0.024386 0.031804 -0.111499
+v -0.069446 0.024662 -0.094256
+v -0.103934 0.011464 -0.062393
+v 0.103934 0.011464 -0.062393
+v 0.122598 -0.005780 -0.020763
+v 0.024386 0.031804 -0.111499
+v 0.069446 0.024662 -0.094256
+v -0.122598 0.009727 -0.010062
+v -0.122598 -0.246570 0.024386
+v -0.103934 -0.246570 0.069446
+v -0.069447 -0.246570 0.103934
+v -0.122598 -0.246570 -0.024386
+v 0.069446 -0.246571 0.103933
+v 0.122598 -0.246571 0.024386
+v 0.103934 -0.246571 0.069446
+v 0.103933 -0.246571 -0.069446
+v -0.024386 -0.246570 0.122598
+v 0.122598 -0.246571 -0.024386
+v -0.024386 -0.246571 -0.122598
+v 0.024386 -0.246571 -0.122598
+v 0.069446 -0.246571 -0.103934
+v -0.103934 -0.246570 -0.069446
+v -0.069446 -0.246570 -0.103934
+v 0.024386 -0.246570 0.122598
+vt 0.139725 0.682190
+vt 0.199773 0.657318
+vt 0.232270 0.820694
+vt 0.093767 0.728149
+vt 0.068894 0.788196
+vt 0.068894 0.853192
+vt 0.093767 0.913239
+vt 0.139725 0.959198
+vt 0.199773 0.984070
+vt 0.264768 0.984070
+vt 0.324816 0.959198
+vt 0.370774 0.913239
+vt 0.395647 0.853192
+vt 0.395647 0.788196
+vt 0.370774 0.728149
+vt 0.324816 0.682190
+vt 0.264768 0.657318
+vt 0.487410 0.682190
+vt 0.547457 0.657318
+vt 0.579955 0.820694
+vt 0.441451 0.728149
+vt 0.416578 0.788196
+vt 0.416578 0.853192
+vt 0.441451 0.913239
+vt 0.487410 0.959198
+vt 0.547457 0.984070
+vt 0.612452 0.984070
+vt 0.672500 0.959198
+vt 0.718459 0.913239
+vt 0.743331 0.853192
+vt 0.743331 0.788196
+vt 0.718459 0.728149
+vt 0.672500 0.682190
+vt 0.612452 0.657318
+vt 0.125000 0.640625
+vt 0.125000 0.578125
+vt 0.187500 0.578125
+vt 0.187500 0.640625
+vt 0.250000 0.578125
+vt 0.250000 0.640625
+vt 0.062500 0.640625
+vt 0.062500 0.578125
+vt 0.000000 0.640625
+vt 0.000000 0.578125
+vt 0.937500 0.640625
+vt 0.937500 0.578125
+vt 1.000000 0.578125
+vt 1.000000 0.640625
+vt 0.875000 0.640625
+vt 0.875000 0.578125
+vt 0.812500 0.640625
+vt 0.812500 0.578125
+vt 0.750000 0.640625
+vt 0.750000 0.578125
+vt 0.687500 0.640625
+vt 0.687500 0.578125
+vt 0.625000 0.640625
+vt 0.625000 0.578125
+vt 0.562500 0.640625
+vt 0.562500 0.578125
+vt 0.500000 0.640625
+vt 0.500000 0.578125
+vt 0.437500 0.640625
+vt 0.437500 0.578125
+vt 0.375000 0.640625
+vt 0.375000 0.578125
+vt 0.312500 0.640625
+vt 0.312500 0.578125
+vt 0.187500 0.453125
+vt 0.125000 0.453125
+vt 0.139892 0.682190
+vt 0.199940 0.657318
+vt 0.232437 0.820694
+vt 0.093934 0.728149
+vt 0.069061 0.788196
+vt 0.069061 0.853192
+vt 0.093934 0.913239
+vt 0.139892 0.959198
+vt 0.199940 0.984070
+vt 0.264935 0.984070
+vt 0.324983 0.959198
+vt 0.370941 0.913239
+vt 0.395814 0.853192
+vt 0.395814 0.788196
+vt 0.370941 0.728149
+vt 0.324983 0.682190
+vt 0.264935 0.657318
+vt 0.875000 0.265625
+vt 0.875000 0.015625
+vt 0.937500 0.015625
+vt 0.937500 0.265625
+vt 0.812500 0.265625
+vt 0.812500 0.015625
+vt 0.625000 0.265625
+vt 0.625000 0.015625
+vt 0.687500 0.015625
+vt 0.687500 0.265625
+vt 0.437500 0.265625
+vt 0.437500 0.015625
+vt 0.500000 0.015625
+vt 0.500000 0.265625
+vt 0.375000 0.265625
+vt 0.375000 0.015625
+vt 0.312500 0.265625
+vt 0.312500 0.015625
+vt 0.250000 0.265625
+vt 0.250000 0.015625
+vt 0.062500 0.265625
+vt 0.062500 0.015625
+vt 0.125000 0.015625
+vt 0.125000 0.265625
+vt 0.000000 0.265625
+vt 0.000000 0.015625
+vt 1.000000 0.015625
+vt 1.000000 0.265625
+vt 0.187500 0.265625
+vt 0.187500 0.015625
+vt 0.750000 0.265625
+vt 0.750000 0.015625
+vt 0.562500 0.265625
+vt 0.562500 0.015625
+vt 0.000000 0.999989
+vt 0.000000 0.890943
+vt 0.041611 0.899043
+vt 0.941956 0.794823
+vt 0.941956 0.841698
+vt 0.895081 0.841698
+vt 0.895081 0.794823
+vt 0.848206 0.841698
+vt 0.848206 0.794823
+vt 0.801331 0.794823
+vt 0.801331 0.841698
+vt 0.754456 0.841698
+vt 0.754456 0.794823
+vt 0.988831 0.794823
+vt 0.988831 0.841698
+vt 0.941956 0.701073
+vt 0.941956 0.747948
+vt 0.895081 0.747948
+vt 0.895081 0.701073
+vt 0.041611 0.741571
+vt 0.000000 0.749671
+vt 0.076282 0.717645
+vt 0.102233 0.682226
+vt 0.109057 0.640614
+vt 0.754456 0.747948
+vt 0.801331 0.747948
+vt 0.848206 0.747948
+vt 0.848206 0.701073
+vt 0.941956 0.888573
+vt 0.988831 0.888573
+vt 0.895081 0.888573
+vt 0.848206 0.888573
+vt 0.076282 0.922969
+vt 0.102233 0.958388
+vt 0.109057 1.000000
+vt 0.801331 0.888573
+vt 0.754456 0.888573
+vt 0.801331 0.935448
+vt 0.754456 0.935448
+vt 0.754456 0.982323
+vt 0.801331 0.982323
+vt 0.848206 0.935448
+vt 0.848206 0.982323
+vt 0.895081 0.935448
+vt 0.895081 0.982323
+vt 0.941956 0.935448
+vt 0.941956 0.982323
+vt 0.988831 0.982323
+vt 0.988831 0.935448
+vt 0.801331 0.701073
+vt 0.754456 0.701073
+vt 0.250000 0.453125
+vt 0.875000 0.453125
+vt 0.937500 0.453125
+vt 0.750000 0.453125
+vt 0.812500 0.453125
+vt 0.562500 0.453125
+vt 0.625000 0.453125
+vt 0.687500 0.453125
+vt 0.500000 0.453125
+vt 0.437500 0.453125
+vt 0.375000 0.453125
+vt 0.312500 0.453125
+vt 0.062500 0.453125
+vt 0.000000 0.453125
+vt 1.000000 0.453125
+g pipe.000_Cylinder.001_metal
+usemtl metal
+s off
+f 36/54 37/55 38/56
+f 39/57 36/54 38/56
+f 40/58 39/57 38/56
+f 41/59 40/58 38/56
+f 42/60 41/59 38/56
+f 43/61 42/60 38/56
+f 44/62 43/61 38/56
+f 45/63 44/62 38/56
+f 46/64 45/63 38/56
+f 47/65 46/64 38/56
+f 48/66 47/65 38/56
+f 49/67 48/66 38/56
+f 50/68 49/67 38/56
+f 51/69 50/68 38/56
+f 52/70 51/69 38/56
+f 53/71 54/72 55/73
+f 56/74 53/71 55/73
+f 57/75 56/74 55/73
+f 58/76 57/75 55/73
+f 59/77 58/76 55/73
+f 60/78 59/77 55/73
+f 61/79 60/78 55/73
+f 62/80 61/79 55/73
+f 63/81 62/80 55/73
+f 64/82 63/81 55/73
+f 65/83 64/82 55/73
+f 66/84 65/83 55/73
+f 67/85 66/84 55/73
+f 68/86 67/85 55/73
+f 69/87 68/86 55/73
+f 54/72 69/87 55/73
+f 37/55 52/70 38/56
+f 56/88 50/89 51/90 53/91
+f 53/91 51/90 52/92 54/93
+f 57/94 49/95 50/89 56/88
+f 58/96 48/97 49/95 57/94
+f 59/98 47/99 48/100 58/101
+f 60/102 46/103 47/99 59/98
+f 61/104 45/105 46/103 60/102
+f 62/106 44/107 45/105 61/104
+f 63/108 43/109 44/107 62/106
+f 64/110 42/111 43/109 63/108
+f 65/112 41/113 42/111 64/110
+f 66/114 40/115 41/113 65/112
+f 67/116 39/117 40/115 66/114
+f 68/118 36/119 39/117 67/116
+f 69/120 37/121 36/119 68/118
+f 54/93 52/92 37/121 69/120
+f 175/122 34/90 81/89 185/123
+f 102/124 103/125 104/126
+f 105/127 102/124 104/126
+f 106/128 105/127 104/126
+f 107/129 106/128 104/126
+f 108/130 107/129 104/126
+f 109/131 108/130 104/126
+f 110/132 109/131 104/126
+f 111/133 110/132 104/126
+f 112/134 111/133 104/126
+f 113/135 112/134 104/126
+f 114/136 113/135 104/126
+f 115/137 114/136 104/126
+f 116/138 115/137 104/126
+f 117/139 116/138 104/126
+f 118/140 117/139 104/126
+f 119/71 120/72 121/73
+f 122/74 119/71 121/73
+f 123/75 122/74 121/73
+f 124/76 123/75 121/73
+f 125/77 124/76 121/73
+f 126/78 125/77 121/73
+f 127/79 126/78 121/73
+f 128/80 127/79 121/73
+f 129/81 128/80 121/73
+f 130/82 129/81 121/73
+f 131/83 130/82 121/73
+f 132/84 131/83 121/73
+f 133/85 132/84 121/73
+f 134/86 133/85 121/73
+f 135/87 134/86 121/73
+f 120/72 135/87 121/73
+f 103/125 118/140 104/126
+f 122/88 116/89 117/90 119/91
+f 119/91 117/90 118/92 120/93
+f 123/94 115/95 116/89 122/88
+f 124/96 114/97 115/95 123/94
+f 125/98 113/99 114/100 124/101
+f 126/102 112/103 113/99 125/98
+f 127/104 111/105 112/103 126/102
+f 128/106 110/107 111/105 127/104
+f 129/108 109/109 110/107 128/106
+f 130/110 108/111 109/109 129/108
+f 131/112 107/113 108/111 130/110
+f 132/114 106/115 107/113 131/112
+f 133/116 105/117 106/115 132/114
+f 134/118 102/119 105/117 133/116
+f 135/120 103/121 102/119 134/118
+f 120/93 118/92 103/121 135/120
+f 136/141 137/142 138/143 139/144
+f 142/145 141/146 137/142 136/141
+f 145/147 144/148 147/149 146/150
+f 150/151 151/152 149/153 148/154
+f 152/155 153/156 151/152 150/151
+f 154/157 155/158 153/156 152/155
+f 101/159 100/160 155/158 154/157
+f 158/161 159/162 157/163 156/164
+f 160/165 161/166 159/162 158/161
+f 139/144 138/143 161/167 160/168
+f 35/169 99/170 100/160 101/159
+f 76/171 140/172 141/146 142/145
+f 162/173 143/174 144/148 145/147
+f 146/150 147/149 140/172 76/171
+f 148/154 149/153 143/174 162/173
+f 156/164 157/163 99/170 35/169
+f 76/175 72/176 168/177
+f 83/178 164/179 169/180 71/181
+f 71/181 169/180 170/182 70/183
+f 73/184 70/183 170/182 167/185
+f 73/184 167/185 168/186 72/187
+f 83/178 82/188 165/189 164/179
+f 82/190 81/191 166/192 165/193
+f 81/191 34/178 163/181 166/192
+f 35/96 163/194 34/195
+f 35/96 171/196 163/194
+f 35/96 96/197 171/196
+f 96/197 35/96 101/198
+f 154/199 90/200 96/184 101/187
+f 90/200 84/201 171/183 96/184
+f 166/192 163/181 171/183 84/201
+f 98/202 165/193 166/192 84/201
+f 97/203 164/179 165/189 98/204
+f 97/203 87/205 169/180 164/179
+f 87/205 88/206 170/182 169/180
+f 76/175 168/177 86/207
+f 76/175 86/207 94/208
+f 94/208 146/209 76/175
+f 167/185 85/210 86/211 168/186
+f 95/212 94/213 86/211 85/210
+f 85/210 167/185 170/182 88/206
+f 146/214 94/213 95/212 145/215
+f 95/212 85/210 88/206 89/216
+f 95/212 89/216 162/217 145/215
+f 93/218 89/216 88/206 87/205
+f 93/218 148/219 162/217 89/216
+f 97/203 92/220 93/218 87/205
+f 150/221 148/219 93/218 92/220
+f 152/222 150/221 92/220 91/223
+f 92/220 97/203 98/204 91/223
+f 91/224 98/202 84/201 90/200
+f 154/199 152/225 91/224 90/200
+f 34/90 175/122 172/226 35/92
+f 70/103 184/227 183/228 71/99
+f 72/107 181/229 179/230 73/105
+f 74/113 176/231 178/232 75/111
+f 76/109 177/233 181/229 72/107
+f 73/105 179/230 184/227 70/103
+f 75/111 178/232 177/233 76/109
+f 77/115 187/234 176/231 74/113
+f 78/117 180/235 187/234 77/115
+f 79/119 174/236 180/235 78/117
+f 80/121 173/237 174/236 79/119
+f 35/92 172/226 173/237 80/121
+f 82/95 186/238 185/123 81/89
+f 83/97 182/239 186/238 82/95
+f 71/99 183/228 182/240 83/100
diff --git a/pipeworks/models/pipeworks_valve_off.obj b/pipeworks/models/pipeworks_valve_off.obj
new file mode 100644
index 0000000..c5f71be
--- /dev/null
+++ b/pipeworks/models/pipeworks_valve_off.obj
@@ -0,0 +1,458 @@
+# Blender v2.69 (sub 0) OBJ File: 'pipe-valve-off.blend'
+# www.blender.org
+mtllib pipeworks_valve_off.mtl
+o Cube.003
+v 0.062500 0.281250 -0.312500
+v 0.062500 0.281250 0.093750
+v -0.062500 0.281250 0.093750
+v -0.062500 0.281250 -0.312500
+v 0.062500 0.343750 -0.312500
+v 0.062500 0.343750 0.093750
+v -0.062500 0.343750 0.093750
+v -0.062500 0.343750 -0.312500
+v 0.031250 0.250000 -0.031250
+v 0.031250 0.250000 0.031250
+v -0.031250 0.250000 0.031250
+v -0.031250 0.250000 -0.031250
+v 0.031250 0.281250 -0.031250
+v 0.031250 0.281250 0.031250
+v -0.031250 0.281250 0.031250
+v -0.031250 0.281250 -0.031250
+v 0.250000 -0.250000 -0.250000
+v 0.250000 -0.250000 0.250000
+v -0.250000 -0.250000 0.250000
+v -0.250000 -0.250000 -0.250000
+v 0.250000 0.250000 -0.250000
+v 0.250000 0.250000 0.250000
+v -0.250000 0.250000 0.250000
+v -0.250000 0.250000 -0.250000
+v -0.468750 -0.153248 -0.030483
+v -0.500000 -0.153248 -0.030483
+v -0.468750 -0.153248 0.030483
+v -0.500000 -0.153248 0.030483
+v -0.468750 -0.129917 0.086808
+v -0.500000 -0.129917 0.086808
+v -0.468750 -0.086808 0.129917
+v -0.500000 -0.086808 0.129917
+v -0.468750 -0.030483 0.153248
+v -0.500000 -0.030483 0.153248
+v -0.468750 0.030483 0.153248
+v -0.500000 0.030483 0.153248
+v -0.468750 0.086808 0.129917
+v -0.500000 0.086808 0.129917
+v -0.468750 0.129917 0.086808
+v -0.500000 0.129917 0.086808
+v -0.468750 0.153248 0.030483
+v -0.500000 0.153247 0.030483
+v -0.468750 0.153248 -0.030483
+v -0.500000 0.153248 -0.030483
+v -0.468750 0.129917 -0.086808
+v -0.500000 0.129917 -0.086808
+v -0.468750 0.086808 -0.129917
+v -0.500000 0.086808 -0.129917
+v -0.468750 0.030483 -0.153248
+v -0.500000 0.030483 -0.153248
+v -0.468750 -0.030483 -0.153248
+v -0.500000 -0.030483 -0.153248
+v -0.468750 -0.086808 -0.129917
+v -0.500000 -0.086808 -0.129917
+v -0.468750 -0.129917 -0.086808
+v -0.500000 -0.129917 -0.086808
+v -0.468750 -0.122598 -0.024386
+v -0.468750 -0.122598 0.024386
+v -0.468750 -0.103934 0.069446
+v -0.468750 -0.069446 0.103934
+v -0.468750 -0.024386 0.122598
+v -0.468750 0.024386 0.122598
+v -0.468750 0.069446 0.103934
+v -0.468750 0.103934 0.069446
+v -0.468750 0.122598 0.024386
+v -0.468750 0.122598 -0.024386
+v -0.468750 0.103934 -0.069446
+v -0.468750 0.069446 -0.103934
+v -0.468750 0.024386 -0.122598
+v -0.468750 -0.024387 -0.122598
+v -0.468750 -0.069447 -0.103934
+v -0.468750 -0.103934 -0.069446
+v -0.468750 -0.000000 -0.000000
+v -0.500000 -0.000000 -0.000000
+v 0.468750 -0.069446 0.103934
+v 0.468750 -0.103933 0.069447
+v 0.468750 -0.122598 0.024387
+v 0.468750 -0.122598 -0.024386
+v 0.500000 -0.129917 -0.086807
+v 0.468750 -0.129917 -0.086807
+v 0.500000 -0.086808 -0.129917
+v 0.468750 -0.086808 -0.129917
+v 0.500000 -0.030483 -0.153247
+v 0.468750 -0.030483 -0.153247
+v 0.500000 0.030483 -0.153247
+v 0.468750 0.030483 -0.153247
+v 0.500000 0.086808 -0.129917
+v 0.468750 0.086808 -0.129917
+v 0.500000 0.129917 -0.086808
+v 0.468750 0.129917 -0.086808
+v 0.500000 0.153248 -0.030483
+v 0.468750 0.153248 -0.030483
+v 0.500000 0.153248 0.030483
+v 0.468750 0.153248 0.030483
+v 0.500000 0.129917 0.086808
+v 0.468750 0.129917 0.086808
+v 0.500000 0.086808 0.129917
+v 0.468750 0.086808 0.129917
+v 0.500000 0.030483 0.153248
+v 0.468750 0.030483 0.153248
+v 0.500000 -0.030483 0.153248
+v 0.468750 -0.030483 0.153248
+v 0.500000 -0.086807 0.129917
+v 0.468750 -0.086808 0.129917
+v 0.500000 -0.129917 0.086808
+v 0.468750 -0.129917 0.086808
+v 0.500000 -0.153247 0.030483
+v 0.468750 -0.153247 0.030483
+v 0.500000 -0.153247 -0.030483
+v 0.468750 -0.153247 -0.030483
+v 0.468750 -0.024386 0.122598
+v 0.468750 0.024387 0.122598
+v 0.468750 0.069447 0.103934
+v 0.468750 0.103934 0.069447
+v 0.468750 0.122598 0.024387
+v 0.468750 0.122598 -0.024386
+v 0.468750 0.103934 -0.069446
+v 0.468750 0.069447 -0.103933
+v 0.468750 0.024387 -0.122598
+v 0.468750 -0.024386 -0.122598
+v 0.468750 -0.069446 -0.103933
+v 0.468750 -0.103933 -0.069446
+v 0.468750 0.000000 0.000000
+v 0.500000 0.000000 0.000000
+vt 0.265625 0.234375
+vt 0.468750 0.234375
+vt 0.468750 0.265625
+vt 0.265625 0.265625
+vt 0.265625 0.187500
+vt 0.328125 0.187500
+vt 0.328125 0.218750
+vt 0.265625 0.218750
+vt 0.468750 0.312500
+vt 0.265625 0.312500
+vt 0.265625 0.281250
+vt 0.468750 0.281250
+vt 0.406250 0.218750
+vt 0.343750 0.218750
+vt 0.343750 0.187500
+vt 0.406250 0.187500
+vt 0.468750 0.468750
+vt 0.265625 0.468750
+vt 0.265625 0.406250
+vt 0.468750 0.406250
+vt 0.468750 0.390625
+vt 0.265625 0.390625
+vt 0.265625 0.328125
+vt 0.468750 0.328125
+vt 0.039062 0.203125
+vt 0.007812 0.203125
+vt 0.007812 0.187500
+vt 0.039062 0.187500
+vt 0.085938 0.203125
+vt 0.054688 0.203125
+vt 0.054688 0.187500
+vt 0.085938 0.187500
+vt 0.148438 0.187500
+vt 0.179688 0.187500
+vt 0.179688 0.203125
+vt 0.148438 0.203125
+vt 0.132812 0.203125
+vt 0.101562 0.203125
+vt 0.101562 0.187500
+vt 0.132812 0.187500
+vt 0.515625 0.484375
+vt 0.515625 0.734375
+vt 0.265625 0.734375
+vt 0.265625 0.484375
+vt 0.000000 0.468750
+vt 0.000000 0.218750
+vt 0.250000 0.218750
+vt 0.250000 0.468750
+vt 0.515625 1.000000
+vt 0.265625 1.000000
+vt 0.265625 0.750000
+vt 0.515625 0.750000
+vt 0.250000 0.734375
+vt 0.000000 0.734375
+vt 0.000000 0.484375
+vt 0.250000 0.484375
+vt 0.781250 1.000000
+vt 0.531250 1.000000
+vt 0.531250 0.750000
+vt 0.781250 0.750000
+vt 0.000847 0.750015
+vt 0.250216 0.750015
+vt 0.250216 0.999385
+vt 0.000847 0.999385
+vt 0.867188 0.273438
+vt 0.835938 0.273438
+vt 0.835938 0.304688
+vt 0.867188 0.304688
+vt 0.804688 0.273438
+vt 0.804688 0.304688
+vt 0.773438 0.273438
+vt 0.773438 0.304688
+vt 0.742188 0.273438
+vt 0.742188 0.304688
+vt 0.710938 0.273438
+vt 0.710938 0.304688
+vt 0.679688 0.273438
+vt 0.679688 0.304688
+vt 0.648438 0.273438
+vt 0.648438 0.304688
+vt 0.617188 0.273438
+vt 0.617188 0.304688
+vt 0.585938 0.273438
+vt 0.585938 0.304688
+vt 0.554688 0.273438
+vt 0.554688 0.304688
+vt 0.523438 0.273438
+vt 0.523438 0.304688
+vt 0.492188 0.273438
+vt 0.492188 0.304688
+vt 0.992188 0.273438
+vt 0.960938 0.273438
+vt 0.960938 0.304688
+vt 0.992188 0.304688
+vt 0.929688 0.273438
+vt 0.929688 0.304688
+vt 0.898438 0.273438
+vt 0.898438 0.304688
+vt 0.600936 0.328499
+vt 0.584692 0.410164
+vt 0.568448 0.328499
+vt 0.757628 0.328499
+vt 0.773872 0.410164
+vt 0.790117 0.328499
+vt 0.820132 0.340932
+vt 0.843105 0.363905
+vt 0.855537 0.393920
+vt 0.855537 0.426408
+vt 0.843105 0.456424
+vt 0.820132 0.479396
+vt 0.790117 0.491829
+vt 0.757628 0.491829
+vt 0.727613 0.479396
+vt 0.704640 0.456424
+vt 0.692207 0.426408
+vt 0.692207 0.393920
+vt 0.704640 0.363905
+vt 0.727613 0.340932
+vt 0.538432 0.340932
+vt 0.515460 0.363905
+vt 0.503027 0.393920
+vt 0.503027 0.426408
+vt 0.515460 0.456424
+vt 0.538432 0.479396
+vt 0.568448 0.491829
+vt 0.600936 0.491829
+vt 0.630951 0.479396
+vt 0.653924 0.456424
+vt 0.666357 0.426408
+vt 0.666357 0.393920
+vt 0.653924 0.363905
+vt 0.630951 0.340932
+vt 0.585938 0.257812
+vt 0.585938 0.007812
+vt 0.617188 0.007812
+vt 0.617188 0.257812
+vt 0.538433 0.340928
+vt 0.568449 0.328495
+vt 0.584693 0.410160
+vt 0.515460 0.363901
+vt 0.503028 0.393916
+vt 0.503028 0.426405
+vt 0.515460 0.456420
+vt 0.538433 0.479393
+vt 0.568449 0.491826
+vt 0.600937 0.491826
+vt 0.630952 0.479393
+vt 0.653925 0.456420
+vt 0.666358 0.426405
+vt 0.666358 0.393916
+vt 0.653925 0.363901
+vt 0.630952 0.340928
+vt 0.600937 0.328495
+vt 0.727611 0.340928
+vt 0.757626 0.328495
+vt 0.773870 0.410160
+vt 0.704638 0.363901
+vt 0.692205 0.393916
+vt 0.692205 0.426405
+vt 0.704638 0.456420
+vt 0.727611 0.479393
+vt 0.757626 0.491826
+vt 0.790115 0.491826
+vt 0.820130 0.479393
+vt 0.843103 0.456420
+vt 0.855535 0.426405
+vt 0.855535 0.393916
+vt 0.843103 0.363901
+vt 0.820130 0.340928
+vt 0.790115 0.328495
+vt 0.929688 0.257812
+vt 0.929688 0.007812
+vt 0.960938 0.007812
+vt 0.960938 0.257812
+vt 0.867188 0.257812
+vt 0.867188 0.007812
+vt 0.898438 0.007812
+vt 0.898438 0.257812
+vt 0.773438 0.257812
+vt 0.773438 0.007812
+vt 0.804688 0.007812
+vt 0.804688 0.257812
+vt 0.835938 0.257812
+vt 0.835938 0.007812
+vt 0.742188 0.257812
+vt 0.742188 0.007812
+vt 0.710938 0.257812
+vt 0.710938 0.007812
+vt 0.679688 0.257812
+vt 0.679688 0.007812
+vt 0.648438 0.257812
+vt 0.648438 0.007812
+vt 0.554688 0.257812
+vt 0.554688 0.007812
+vt 0.523438 0.257812
+vt 0.523438 0.007812
+vt 0.492188 0.257812
+vt 0.492188 0.007812
+vt 0.992188 0.007812
+vt 0.992188 0.257812
+usemtl None
+s off
+f 5/1 6/2 2/3 1/4
+f 6/5 7/6 3/7 2/8
+f 7/9 8/10 4/11 3/12
+f 8/13 5/14 1/15 4/16
+f 1/17 2/18 3/19 4/20
+f 8/21 7/22 6/23 5/24
+f 13/25 14/26 10/27 9/28
+f 14/29 15/30 11/31 10/32
+f 15/33 16/34 12/35 11/36
+f 16/37 13/38 9/39 12/40
+f 21/41 22/42 18/43 17/44
+f 22/45 23/46 19/47 18/48
+f 23/49 24/50 20/51 19/52
+f 24/53 21/54 17/55 20/56
+f 17/57 18/58 19/59 20/60
+f 24/61 23/62 22/63 21/64
+f 25/65 27/66 28/67 26/68
+f 27/66 29/69 30/70 28/67
+f 29/69 31/71 32/72 30/70
+f 31/71 33/73 34/74 32/72
+f 33/73 35/75 36/76 34/74
+f 35/75 37/77 38/78 36/76
+f 37/77 39/79 40/80 38/78
+f 39/79 41/81 42/82 40/80
+f 41/81 43/83 44/84 42/82
+f 43/83 45/85 46/86 44/84
+f 45/85 47/87 48/88 46/86
+f 47/87 49/89 50/90 48/88
+f 49/91 51/92 52/93 50/94
+f 51/92 53/95 54/96 52/93
+f 55/97 25/65 26/68 56/98
+f 53/95 55/97 56/98 54/96
+f 28/99 74/100 26/101
+f 25/102 73/103 27/104
+f 27/104 73/103 29/105
+f 29/105 73/103 31/106
+f 31/106 73/103 33/107
+f 33/107 73/103 35/108
+f 35/108 73/103 37/109
+f 37/109 73/103 39/110
+f 39/110 73/103 41/111
+f 41/111 73/103 43/112
+f 43/112 73/103 45/113
+f 45/113 73/103 47/114
+f 47/114 73/103 49/115
+f 49/115 73/103 51/116
+f 51/116 73/103 53/117
+f 53/117 73/103 55/118
+f 55/118 73/103 25/102
+f 26/101 74/100 56/119
+f 56/119 74/100 54/120
+f 54/120 74/100 52/121
+f 52/121 74/100 50/122
+f 50/122 74/100 48/123
+f 48/123 74/100 46/124
+f 46/124 74/100 44/125
+f 44/125 74/100 42/126
+f 42/126 74/100 40/127
+f 40/127 74/100 38/128
+f 38/128 74/100 36/129
+f 36/129 74/100 34/130
+f 34/130 74/100 32/131
+f 32/131 74/100 30/132
+f 30/132 74/100 28/99
+f 65/133 115/134 116/135 66/136
+f 105/137 107/138 124/139
+f 103/140 105/137 124/139
+f 101/141 103/140 124/139
+f 99/142 101/141 124/139
+f 97/143 99/142 124/139
+f 95/144 97/143 124/139
+f 93/145 95/144 124/139
+f 91/146 93/145 124/139
+f 89/147 91/146 124/139
+f 87/148 89/147 124/139
+f 85/149 87/148 124/139
+f 83/150 85/149 124/139
+f 81/151 83/150 124/139
+f 79/152 81/151 124/139
+f 109/153 79/152 124/139
+f 80/154 110/155 123/156
+f 82/157 80/154 123/156
+f 84/158 82/157 123/156
+f 86/159 84/158 123/156
+f 88/160 86/159 123/156
+f 90/161 88/160 123/156
+f 92/162 90/161 123/156
+f 94/163 92/162 123/156
+f 96/164 94/163 123/156
+f 98/165 96/164 123/156
+f 100/166 98/165 123/156
+f 102/167 100/166 123/156
+f 104/168 102/167 123/156
+f 106/169 104/168 123/156
+f 108/170 106/169 123/156
+f 110/155 108/170 123/156
+f 107/138 109/153 124/139
+f 82/86 81/85 79/83 80/84
+f 80/84 79/83 109/81 110/82
+f 84/88 83/87 81/85 82/86
+f 86/90 85/89 83/87 84/88
+f 88/93 87/92 85/91 86/94
+f 90/96 89/95 87/92 88/93
+f 92/98 91/97 89/95 90/96
+f 94/68 93/65 91/97 92/98
+f 96/67 95/66 93/65 94/68
+f 98/70 97/69 95/66 96/67
+f 100/72 99/71 97/69 98/70
+f 102/74 101/73 99/71 100/72
+f 104/76 103/75 101/73 102/74
+f 106/78 105/77 103/75 104/76
+f 108/80 107/79 105/77 106/78
+f 110/82 109/81 107/79 108/80
+f 60/171 75/172 111/173 61/174
+f 58/175 77/176 76/177 59/178
+f 71/179 121/180 122/181 72/182
+f 57/183 78/184 77/176 58/175
+f 59/178 76/177 75/172 60/171
+f 72/182 122/181 78/184 57/183
+f 70/185 120/186 121/180 71/179
+f 69/187 119/188 120/186 70/185
+f 68/189 118/190 119/188 69/187
+f 67/191 117/192 118/190 68/189
+f 66/136 116/135 117/192 67/191
+f 64/193 114/194 115/134 65/133
+f 63/195 113/196 114/194 64/193
+f 62/197 112/198 113/196 63/195
+f 61/174 111/173 112/199 62/200
diff --git a/pipeworks/models/pipeworks_valve_on.obj b/pipeworks/models/pipeworks_valve_on.obj
new file mode 100644
index 0000000..ba08b30
--- /dev/null
+++ b/pipeworks/models/pipeworks_valve_on.obj
@@ -0,0 +1,458 @@
+# Blender v2.69 (sub 0) OBJ File: 'pipe-valve-on.blend'
+# www.blender.org
+mtllib pipeworks_valve_on.mtl
+o Cube.003
+v 0.312500 0.281250 0.062500
+v -0.093750 0.281250 0.062500
+v -0.093750 0.281250 -0.062500
+v 0.312500 0.281250 -0.062500
+v 0.312500 0.343750 0.062500
+v -0.093750 0.343750 0.062500
+v -0.093750 0.343750 -0.062500
+v 0.312500 0.343750 -0.062500
+v 0.031250 0.250000 -0.031250
+v 0.031250 0.250000 0.031250
+v -0.031250 0.250000 0.031250
+v -0.031250 0.250000 -0.031250
+v 0.031250 0.281250 -0.031250
+v 0.031250 0.281250 0.031250
+v -0.031250 0.281250 0.031250
+v -0.031250 0.281250 -0.031250
+v 0.250000 -0.250000 -0.250000
+v 0.250000 -0.250000 0.250000
+v -0.250000 -0.250000 0.250000
+v -0.250000 -0.250000 -0.250000
+v 0.250000 0.250000 -0.250000
+v 0.250000 0.250000 0.250000
+v -0.250000 0.250000 0.250000
+v -0.250000 0.250000 -0.250000
+v -0.468750 -0.153248 -0.030483
+v -0.500000 -0.153248 -0.030483
+v -0.468750 -0.153248 0.030483
+v -0.500000 -0.153248 0.030483
+v -0.468750 -0.129917 0.086808
+v -0.500000 -0.129917 0.086808
+v -0.468750 -0.086808 0.129917
+v -0.500000 -0.086808 0.129917
+v -0.468750 -0.030483 0.153248
+v -0.500000 -0.030483 0.153248
+v -0.468750 0.030483 0.153248
+v -0.500000 0.030483 0.153248
+v -0.468750 0.086808 0.129917
+v -0.500000 0.086808 0.129917
+v -0.468750 0.129917 0.086808
+v -0.500000 0.129917 0.086808
+v -0.468750 0.153248 0.030483
+v -0.500000 0.153247 0.030483
+v -0.468750 0.153248 -0.030483
+v -0.500000 0.153248 -0.030483
+v -0.468750 0.129917 -0.086808
+v -0.500000 0.129917 -0.086808
+v -0.468750 0.086808 -0.129917
+v -0.500000 0.086808 -0.129917
+v -0.468750 0.030483 -0.153248
+v -0.500000 0.030483 -0.153248
+v -0.468750 -0.030483 -0.153248
+v -0.500000 -0.030483 -0.153248
+v -0.468750 -0.086808 -0.129917
+v -0.500000 -0.086808 -0.129917
+v -0.468750 -0.129917 -0.086808
+v -0.500000 -0.129917 -0.086808
+v -0.468750 -0.122598 -0.024386
+v -0.468750 -0.122598 0.024386
+v -0.468750 -0.103934 0.069446
+v -0.468750 -0.069446 0.103934
+v -0.468750 -0.024386 0.122598
+v -0.468750 0.024386 0.122598
+v -0.468750 0.069446 0.103934
+v -0.468750 0.103934 0.069446
+v -0.468750 0.122598 0.024386
+v -0.468750 0.122598 -0.024386
+v -0.468750 0.103934 -0.069446
+v -0.468750 0.069446 -0.103934
+v -0.468750 0.024386 -0.122598
+v -0.468750 -0.024387 -0.122598
+v -0.468750 -0.069447 -0.103934
+v -0.468750 -0.103934 -0.069446
+v -0.468750 -0.000000 -0.000000
+v -0.500000 -0.000000 -0.000000
+v 0.468750 -0.069446 0.103934
+v 0.468750 -0.103933 0.069447
+v 0.468750 -0.122598 0.024387
+v 0.468750 -0.122598 -0.024386
+v 0.500000 -0.129917 -0.086807
+v 0.468750 -0.129917 -0.086807
+v 0.500000 -0.086808 -0.129917
+v 0.468750 -0.086808 -0.129917
+v 0.500000 -0.030483 -0.153247
+v 0.468750 -0.030483 -0.153247
+v 0.500000 0.030483 -0.153247
+v 0.468750 0.030483 -0.153247
+v 0.500000 0.086808 -0.129917
+v 0.468750 0.086808 -0.129917
+v 0.500000 0.129917 -0.086808
+v 0.468750 0.129917 -0.086808
+v 0.500000 0.153248 -0.030483
+v 0.468750 0.153248 -0.030483
+v 0.500000 0.153248 0.030483
+v 0.468750 0.153248 0.030483
+v 0.500000 0.129917 0.086808
+v 0.468750 0.129917 0.086808
+v 0.500000 0.086808 0.129917
+v 0.468750 0.086808 0.129917
+v 0.500000 0.030483 0.153248
+v 0.468750 0.030483 0.153248
+v 0.500000 -0.030483 0.153248
+v 0.468750 -0.030483 0.153248
+v 0.500000 -0.086807 0.129917
+v 0.468750 -0.086808 0.129917
+v 0.500000 -0.129917 0.086808
+v 0.468750 -0.129917 0.086808
+v 0.500000 -0.153247 0.030483
+v 0.468750 -0.153247 0.030483
+v 0.500000 -0.153247 -0.030483
+v 0.468750 -0.153247 -0.030483
+v 0.468750 -0.024386 0.122598
+v 0.468750 0.024387 0.122598
+v 0.468750 0.069447 0.103934
+v 0.468750 0.103934 0.069447
+v 0.468750 0.122598 0.024387
+v 0.468750 0.122598 -0.024386
+v 0.468750 0.103934 -0.069446
+v 0.468750 0.069447 -0.103933
+v 0.468750 0.024387 -0.122598
+v 0.468750 -0.024386 -0.122598
+v 0.468750 -0.069446 -0.103933
+v 0.468750 -0.103933 -0.069446
+v 0.468750 0.000000 0.000000
+v 0.500000 0.000000 0.000000
+vt 0.265625 0.234375
+vt 0.468750 0.234375
+vt 0.468750 0.265625
+vt 0.265625 0.265625
+vt 0.265625 0.187500
+vt 0.328125 0.187500
+vt 0.328125 0.218750
+vt 0.265625 0.218750
+vt 0.468750 0.312500
+vt 0.265625 0.312500
+vt 0.265625 0.281250
+vt 0.468750 0.281250
+vt 0.406250 0.218750
+vt 0.343750 0.218750
+vt 0.343750 0.187500
+vt 0.406250 0.187500
+vt 0.468750 0.468750
+vt 0.265625 0.468750
+vt 0.265625 0.406250
+vt 0.468750 0.406250
+vt 0.468750 0.390625
+vt 0.265625 0.390625
+vt 0.265625 0.328125
+vt 0.468750 0.328125
+vt 0.039062 0.203125
+vt 0.007812 0.203125
+vt 0.007812 0.187500
+vt 0.039062 0.187500
+vt 0.085938 0.203125
+vt 0.054688 0.203125
+vt 0.054688 0.187500
+vt 0.085938 0.187500
+vt 0.148438 0.187500
+vt 0.179688 0.187500
+vt 0.179688 0.203125
+vt 0.148438 0.203125
+vt 0.132812 0.203125
+vt 0.101562 0.203125
+vt 0.101562 0.187500
+vt 0.132812 0.187500
+vt 0.515625 0.484375
+vt 0.515625 0.734375
+vt 0.265625 0.734375
+vt 0.265625 0.484375
+vt 0.000000 0.468750
+vt 0.000000 0.218750
+vt 0.250000 0.218750
+vt 0.250000 0.468750
+vt 0.515625 1.000000
+vt 0.265625 1.000000
+vt 0.265625 0.750000
+vt 0.515625 0.750000
+vt 0.250000 0.734375
+vt 0.000000 0.734375
+vt 0.000000 0.484375
+vt 0.250000 0.484375
+vt 0.781250 1.000000
+vt 0.531250 1.000000
+vt 0.531250 0.750000
+vt 0.781250 0.750000
+vt 0.000847 0.750015
+vt 0.250216 0.750015
+vt 0.250216 0.999385
+vt 0.000847 0.999385
+vt 0.867188 0.273438
+vt 0.835938 0.273438
+vt 0.835938 0.304688
+vt 0.867188 0.304688
+vt 0.804688 0.273438
+vt 0.804688 0.304688
+vt 0.773438 0.273438
+vt 0.773438 0.304688
+vt 0.742188 0.273438
+vt 0.742188 0.304688
+vt 0.710938 0.273438
+vt 0.710938 0.304688
+vt 0.679688 0.273438
+vt 0.679688 0.304688
+vt 0.648438 0.273438
+vt 0.648438 0.304688
+vt 0.617188 0.273438
+vt 0.617188 0.304688
+vt 0.585938 0.273438
+vt 0.585938 0.304688
+vt 0.554688 0.273438
+vt 0.554688 0.304688
+vt 0.523438 0.273438
+vt 0.523438 0.304688
+vt 0.492188 0.273438
+vt 0.492188 0.304688
+vt 0.992188 0.273438
+vt 0.960938 0.273438
+vt 0.960938 0.304688
+vt 0.992188 0.304688
+vt 0.929688 0.273438
+vt 0.929688 0.304688
+vt 0.898438 0.273438
+vt 0.898438 0.304688
+vt 0.600936 0.328499
+vt 0.584692 0.410164
+vt 0.568448 0.328499
+vt 0.757628 0.328499
+vt 0.773872 0.410164
+vt 0.790117 0.328499
+vt 0.820132 0.340932
+vt 0.843105 0.363905
+vt 0.855537 0.393920
+vt 0.855537 0.426408
+vt 0.843105 0.456424
+vt 0.820132 0.479396
+vt 0.790117 0.491829
+vt 0.757628 0.491829
+vt 0.727613 0.479396
+vt 0.704640 0.456424
+vt 0.692207 0.426408
+vt 0.692207 0.393920
+vt 0.704640 0.363905
+vt 0.727613 0.340932
+vt 0.538432 0.340932
+vt 0.515460 0.363905
+vt 0.503027 0.393920
+vt 0.503027 0.426408
+vt 0.515460 0.456424
+vt 0.538432 0.479396
+vt 0.568448 0.491829
+vt 0.600936 0.491829
+vt 0.630951 0.479396
+vt 0.653924 0.456424
+vt 0.666357 0.426408
+vt 0.666357 0.393920
+vt 0.653924 0.363905
+vt 0.630951 0.340932
+vt 0.585938 0.257812
+vt 0.585938 0.007812
+vt 0.617188 0.007812
+vt 0.617188 0.257812
+vt 0.538433 0.340928
+vt 0.568449 0.328495
+vt 0.584693 0.410160
+vt 0.515460 0.363901
+vt 0.503028 0.393916
+vt 0.503028 0.426405
+vt 0.515460 0.456420
+vt 0.538433 0.479393
+vt 0.568449 0.491826
+vt 0.600937 0.491826
+vt 0.630952 0.479393
+vt 0.653925 0.456420
+vt 0.666358 0.426405
+vt 0.666358 0.393916
+vt 0.653925 0.363901
+vt 0.630952 0.340928
+vt 0.600937 0.328495
+vt 0.727611 0.340928
+vt 0.757626 0.328495
+vt 0.773870 0.410160
+vt 0.704638 0.363901
+vt 0.692205 0.393916
+vt 0.692205 0.426405
+vt 0.704638 0.456420
+vt 0.727611 0.479393
+vt 0.757626 0.491826
+vt 0.790115 0.491826
+vt 0.820130 0.479393
+vt 0.843103 0.456420
+vt 0.855535 0.426405
+vt 0.855535 0.393916
+vt 0.843103 0.363901
+vt 0.820130 0.340928
+vt 0.790115 0.328495
+vt 0.929688 0.257812
+vt 0.929688 0.007812
+vt 0.960938 0.007812
+vt 0.960938 0.257812
+vt 0.867188 0.257812
+vt 0.867188 0.007812
+vt 0.898438 0.007812
+vt 0.898438 0.257812
+vt 0.773438 0.257812
+vt 0.773438 0.007812
+vt 0.804688 0.007812
+vt 0.804688 0.257812
+vt 0.835938 0.257812
+vt 0.835938 0.007812
+vt 0.742188 0.257812
+vt 0.742188 0.007812
+vt 0.710938 0.257812
+vt 0.710938 0.007812
+vt 0.679688 0.257812
+vt 0.679688 0.007812
+vt 0.648438 0.257812
+vt 0.648438 0.007812
+vt 0.554688 0.257812
+vt 0.554688 0.007812
+vt 0.523438 0.257812
+vt 0.523438 0.007812
+vt 0.492188 0.257812
+vt 0.492188 0.007812
+vt 0.992188 0.007812
+vt 0.992188 0.257812
+usemtl None
+s off
+f 5/1 6/2 2/3 1/4
+f 6/5 7/6 3/7 2/8
+f 7/9 8/10 4/11 3/12
+f 8/13 5/14 1/15 4/16
+f 1/17 2/18 3/19 4/20
+f 8/21 7/22 6/23 5/24
+f 13/25 14/26 10/27 9/28
+f 14/29 15/30 11/31 10/32
+f 15/33 16/34 12/35 11/36
+f 16/37 13/38 9/39 12/40
+f 21/41 22/42 18/43 17/44
+f 22/45 23/46 19/47 18/48
+f 23/49 24/50 20/51 19/52
+f 24/53 21/54 17/55 20/56
+f 17/57 18/58 19/59 20/60
+f 24/61 23/62 22/63 21/64
+f 25/65 27/66 28/67 26/68
+f 27/66 29/69 30/70 28/67
+f 29/69 31/71 32/72 30/70
+f 31/71 33/73 34/74 32/72
+f 33/73 35/75 36/76 34/74
+f 35/75 37/77 38/78 36/76
+f 37/77 39/79 40/80 38/78
+f 39/79 41/81 42/82 40/80
+f 41/81 43/83 44/84 42/82
+f 43/83 45/85 46/86 44/84
+f 45/85 47/87 48/88 46/86
+f 47/87 49/89 50/90 48/88
+f 49/91 51/92 52/93 50/94
+f 51/92 53/95 54/96 52/93
+f 55/97 25/65 26/68 56/98
+f 53/95 55/97 56/98 54/96
+f 28/99 74/100 26/101
+f 25/102 73/103 27/104
+f 27/104 73/103 29/105
+f 29/105 73/103 31/106
+f 31/106 73/103 33/107
+f 33/107 73/103 35/108
+f 35/108 73/103 37/109
+f 37/109 73/103 39/110
+f 39/110 73/103 41/111
+f 41/111 73/103 43/112
+f 43/112 73/103 45/113
+f 45/113 73/103 47/114
+f 47/114 73/103 49/115
+f 49/115 73/103 51/116
+f 51/116 73/103 53/117
+f 53/117 73/103 55/118
+f 55/118 73/103 25/102
+f 26/101 74/100 56/119
+f 56/119 74/100 54/120
+f 54/120 74/100 52/121
+f 52/121 74/100 50/122
+f 50/122 74/100 48/123
+f 48/123 74/100 46/124
+f 46/124 74/100 44/125
+f 44/125 74/100 42/126
+f 42/126 74/100 40/127
+f 40/127 74/100 38/128
+f 38/128 74/100 36/129
+f 36/129 74/100 34/130
+f 34/130 74/100 32/131
+f 32/131 74/100 30/132
+f 30/132 74/100 28/99
+f 65/133 115/134 116/135 66/136
+f 105/137 107/138 124/139
+f 103/140 105/137 124/139
+f 101/141 103/140 124/139
+f 99/142 101/141 124/139
+f 97/143 99/142 124/139
+f 95/144 97/143 124/139
+f 93/145 95/144 124/139
+f 91/146 93/145 124/139
+f 89/147 91/146 124/139
+f 87/148 89/147 124/139
+f 85/149 87/148 124/139
+f 83/150 85/149 124/139
+f 81/151 83/150 124/139
+f 79/152 81/151 124/139
+f 109/153 79/152 124/139
+f 80/154 110/155 123/156
+f 82/157 80/154 123/156
+f 84/158 82/157 123/156
+f 86/159 84/158 123/156
+f 88/160 86/159 123/156
+f 90/161 88/160 123/156
+f 92/162 90/161 123/156
+f 94/163 92/162 123/156
+f 96/164 94/163 123/156
+f 98/165 96/164 123/156
+f 100/166 98/165 123/156
+f 102/167 100/166 123/156
+f 104/168 102/167 123/156
+f 106/169 104/168 123/156
+f 108/170 106/169 123/156
+f 110/155 108/170 123/156
+f 107/138 109/153 124/139
+f 82/86 81/85 79/83 80/84
+f 80/84 79/83 109/81 110/82
+f 84/88 83/87 81/85 82/86
+f 86/90 85/89 83/87 84/88
+f 88/93 87/92 85/91 86/94
+f 90/96 89/95 87/92 88/93
+f 92/98 91/97 89/95 90/96
+f 94/68 93/65 91/97 92/98
+f 96/67 95/66 93/65 94/68
+f 98/70 97/69 95/66 96/67
+f 100/72 99/71 97/69 98/70
+f 102/74 101/73 99/71 100/72
+f 104/76 103/75 101/73 102/74
+f 106/78 105/77 103/75 104/76
+f 108/80 107/79 105/77 106/78
+f 110/82 109/81 107/79 108/80
+f 60/171 75/172 111/173 61/174
+f 58/175 77/176 76/177 59/178
+f 71/179 121/180 122/181 72/182
+f 57/183 78/184 77/176 58/175
+f 59/178 76/177 75/172 60/171
+f 72/182 122/181 78/184 57/183
+f 70/185 120/186 121/180 71/179
+f 69/187 119/188 120/186 70/185
+f 68/189 118/190 119/188 69/187
+f 67/191 117/192 118/190 68/189
+f 66/136 116/135 117/192 67/191
+f 64/193 114/194 115/134 65/133
+f 63/195 113/196 114/194 64/193
+f 62/197 112/198 113/196 63/195
+f 61/174 111/173 112/199 62/200
diff --git a/pipeworks/pipes.lua b/pipeworks/pipes.lua
new file mode 100644
index 0000000..2056fdf
--- /dev/null
+++ b/pipeworks/pipes.lua
@@ -0,0 +1,222 @@
+-- This file supplies the steel pipes
+
+local REGISTER_COMPATIBILITY = true
+
+local pipes_empty_nodenames = {}
+local pipes_full_nodenames = {}
+
+local vti = {4, 3, 2, 1, 6, 5}
+local cconnects = {{}, {1}, {1, 2}, {1, 3}, {1, 3, 5}, {1, 2, 3}, {1, 2, 3, 5}, {1, 2, 3, 4}, {1, 2, 3, 4, 5}, {1, 2, 3, 4, 5, 6}}
+for index, connects in ipairs(cconnects) do
+ local outsel = {}
+
+ local jx = 0
+ local jy = 0
+ local jz = 0
+ for _, v in ipairs(connects) do
+ if v == 1 or v == 2 then
+ jx = jx + 1
+ elseif v == 3 or v == 4 then
+ jy = jy + 1
+ else
+ jz = jz + 1
+ end
+ table.insert(outsel, pipeworks.pipe_selectboxes[v])
+ end
+
+ if #connects == 1 then
+ local v = connects[1]
+ v = v-1 + 2*(v%2) -- Opposite side
+ end
+
+ local pgroups = {snappy = 3, pipe = 1, not_in_creative_inventory = 1}
+ local pipedesc = "Pipe segement".." "..dump(connects).."... You hacker, you."
+ local image = nil
+
+ if #connects == 0 then
+ pgroups = {snappy = 3, tube = 1}
+ pipedesc = "Pipe segment"
+ image = "pipeworks_pipe_inv.png"
+ end
+
+ local outimg_e = { "pipeworks_pipe_plain.png" }
+ local outimg_l = { "pipeworks_pipe_plain.png" }
+
+ if index == 3 then
+ outimg_e = { "pipeworks_pipe_3_empty.png" }
+ outimg_l = { "pipeworks_pipe_3_loaded.png" }
+ end
+
+ local mesh = "pipeworks_pipe_"..index..".obj"
+
+ if index == 1 then
+ mesh = "pipeworks_pipe_3.obj"
+ end
+
+ minetest.register_node("pipeworks:pipe_"..index.."_empty", {
+ description = pipedesc,
+ drawtype = "mesh",
+ mesh = mesh,
+ tiles = outimg_e,
+ sunlight_propagates = true,
+ inventory_image = image,
+ wield_image = image,
+ paramtype = "light",
+ paramtype2 = "facedir",
+ selection_box = {
+ type = "fixed",
+ fixed = outsel
+ },
+ collision_box = {
+ type = "fixed",
+ fixed = outsel
+ },
+ groups = pgroups,
+ sounds = default.node_sound_wood_defaults(),
+ walkable = true,
+ drop = "pipeworks:pipe_1_empty",
+ after_place_node = function(pos)
+ pipeworks.scan_for_pipe_objects(pos)
+ end,
+ after_dig_node = function(pos)
+ pipeworks.scan_for_pipe_objects(pos)
+ end
+ })
+
+ local pgroups = {snappy = 3, pipe = 1, not_in_creative_inventory = 1}
+
+ minetest.register_node("pipeworks:pipe_"..index.."_loaded", {
+ description = pipedesc,
+ drawtype = "mesh",
+ mesh = mesh,
+ tiles = outimg_l,
+ sunlight_propagates = true,
+ paramtype = "light",
+ paramtype2 = "facedir",
+ selection_box = {
+ type = "fixed",
+ fixed = outsel
+ },
+ collision_box = {
+ type = "fixed",
+ fixed = outsel
+ },
+ groups = pgroups,
+ sounds = default.node_sound_wood_defaults(),
+ walkable = true,
+ drop = "pipeworks:pipe_1_empty",
+ after_place_node = function(pos)
+ pipeworks.scan_for_pipe_objects(pos)
+ end,
+ after_dig_node = function(pos)
+ pipeworks.scan_for_pipe_objects(pos)
+ end
+ })
+
+ table.insert(pipes_empty_nodenames, "pipeworks:pipe_"..index.."_empty")
+ table.insert(pipes_full_nodenames, "pipeworks:pipe_"..index.."_loaded")
+end
+
+
+
+if REGISTER_COMPATIBILITY then
+ local cempty = "pipeworks:pipe_compatibility_empty"
+ local cloaded = "pipeworks:pipe_compatibility_loaded"
+ minetest.register_node(cempty, {
+ drawtype = "airlike",
+ sunlight_propagates = true,
+ paramtype = "light",
+ inventory_image = "pipeworks_pipe_inv.png",
+ wield_image = "pipeworks_pipe_inv.png",
+ description = "Pipe Segment (legacy)",
+ groups = {not_in_creative_inventory = 1, pipe_to_update = 1},
+ drop = "pipeworks:pipe_1_empty",
+ after_place_node = function(pos)
+ pipeworks.scan_for_pipe_objects(pos)
+ end,
+ })
+ minetest.register_node(cloaded, {
+ drawtype = "airlike",
+ sunlight_propagates = true,
+ paramtype = "light",
+ inventory_image = "pipeworks_pipe_inv.png",
+ groups = {not_in_creative_inventory = 1, pipe_to_update = 1},
+ drop = "pipeworks:pipe_1_empty",
+ after_place_node = function(pos)
+ pipeworks.scan_for_pipe_objects(pos)
+ end,
+ })
+ for xm = 0, 1 do
+ for xp = 0, 1 do
+ for ym = 0, 1 do
+ for yp = 0, 1 do
+ for zm = 0, 1 do
+ for zp = 0, 1 do
+ local pname = xm..xp..ym..yp..zm..zp
+ minetest.register_alias("pipeworks:pipe_"..pname.."_empty", cempty)
+ minetest.register_alias("pipeworks:pipe_"..pname.."_loaded", cloaded)
+ end
+ end
+ end
+ end
+ end
+ end
+ minetest.register_abm({
+ nodenames = {"group:pipe_to_update"},
+ interval = 1,
+ chance = 1,
+ action = function(pos, node, active_object_count, active_object_count_wider)
+ local minp = {x = pos.x-1, y = pos.y-1, z = pos.z-1}
+ local maxp = {x = pos.x+1, y = pos.y+1, z = pos.z+1}
+ if table.getn(minetest.find_nodes_in_area(minp, maxp, "ignore")) == 0 then
+ pipeworks.scan_for_pipe_objects(pos)
+ end
+ end
+ })
+end
+
+table.insert(pipes_empty_nodenames,"pipeworks:valve_on_empty")
+table.insert(pipes_empty_nodenames,"pipeworks:valve_off_empty")
+table.insert(pipes_empty_nodenames,"pipeworks:entry_panel_empty")
+table.insert(pipes_empty_nodenames,"pipeworks:flow_sensor_empty")
+
+table.insert(pipes_full_nodenames,"pipeworks:valve_on_loaded")
+table.insert(pipes_full_nodenames,"pipeworks:entry_panel_loaded")
+table.insert(pipes_full_nodenames,"pipeworks:flow_sensor_loaded")
+
+minetest.register_abm({
+ nodenames = pipes_empty_nodenames,
+ interval = 1,
+ chance = 1,
+ action = function(pos, node, active_object_count, active_object_count_wider)
+ pipeworks.check_for_inflows(pos,node)
+ end
+})
+
+minetest.register_abm({
+ nodenames = pipes_full_nodenames,
+ interval = 1,
+ chance = 1,
+ action = function(pos, node, active_object_count, active_object_count_wider)
+ pipeworks.check_sources(pos,node)
+ end
+})
+
+minetest.register_abm({
+ nodenames = {"pipeworks:spigot","pipeworks:spigot_pouring"},
+ interval = 1,
+ chance = 1,
+ action = function(pos, node, active_object_count, active_object_count_wider)
+ pipeworks.spigot_check(pos,node)
+ end
+})
+
+minetest.register_abm({
+ nodenames = {"pipeworks:fountainhead","pipeworks:fountainhead_pouring"},
+ interval = 1,
+ chance = 1,
+ action = function(pos, node, active_object_count, active_object_count_wider)
+ pipeworks.fountainhead_check(pos,node)
+ end
+})
+
diff --git a/pipeworks/routing_tubes.lua b/pipeworks/routing_tubes.lua
new file mode 100644
index 0000000..8620d20
--- /dev/null
+++ b/pipeworks/routing_tubes.lua
@@ -0,0 +1,119 @@
+-- the default tube and default textures
+pipeworks.register_tube("pipeworks:tube", "Pneumatic tube segment")
+minetest.register_craft( {
+ output = "pipeworks:tube_1 6",
+ recipe = {
+ { "homedecor:plastic_sheeting", "homedecor:plastic_sheeting", "homedecor:plastic_sheeting" },
+ { "", "", "" },
+ { "homedecor:plastic_sheeting", "homedecor:plastic_sheeting", "homedecor:plastic_sheeting" }
+ },
+})
+
+-- the high priority tube is a low-cpu replacement for sorting tubes in situations
+-- where players would use them for simple routing (turning off paths)
+-- without doing actual sorting, like at outputs of tubedevices that might both accept and eject items
+if pipeworks.enable_priority_tube then
+ local color = "#ff3030:128"
+ pipeworks.register_tube("pipeworks:priority_tube", {
+ description = "High Priority Tube Segment",
+ inventory_image = "pipeworks_tube_inv.png^[colorize:" .. color,
+ plain = { "pipeworks_tube_plain.png^[colorize:" .. color },
+ noctr = { "pipeworks_tube_noctr.png^[colorize:" .. color },
+ ends = { "pipeworks_tube_end.png^[colorize:" .. color },
+ short = "pipeworks_tube_short.png^[colorize:" .. color,
+ node_def = {
+ tube = { priority = 150 } -- higher than tubedevices (100)
+ },
+ })
+ minetest.register_craft( {
+ output = "pipeworks:priority_tube_1 6",
+ recipe = {
+ { "homedecor:plastic_sheeting", "homedecor:plastic_sheeting", "homedecor:plastic_sheeting" },
+ { "default:gold_ingot", "", "default:gold_ingot" },
+ { "homedecor:plastic_sheeting", "homedecor:plastic_sheeting", "homedecor:plastic_sheeting" }
+ },
+ })
+end
+
+if pipeworks.enable_accelerator_tube then
+ pipeworks.register_tube("pipeworks:accelerator_tube", {
+ description = "Accelerating Pneumatic Tube Segment",
+ inventory_image = "pipeworks_accelerator_tube_inv.png",
+ plain = { "pipeworks_accelerator_tube_plain.png" },
+ noctr = { "pipeworks_accelerator_tube_noctr.png" },
+ ends = { "pipeworks_accelerator_tube_end.png" },
+ short = "pipeworks_accelerator_tube_short.png",
+ node_def = {
+ tube = {can_go = function(pos, node, velocity, stack)
+ velocity.speed = velocity.speed+1
+ return pipeworks.notvel(pipeworks.meseadjlist, velocity)
+ end}
+ },
+ })
+ minetest.register_craft( {
+ output = "pipeworks:accelerator_tube_1 2",
+ recipe = {
+ { "homedecor:plastic_sheeting", "homedecor:plastic_sheeting", "homedecor:plastic_sheeting" },
+ { "default:mese_crystal_fragment", "default:steel_ingot", "default:mese_crystal_fragment" },
+ { "homedecor:plastic_sheeting", "homedecor:plastic_sheeting", "homedecor:plastic_sheeting" }
+ },
+ })
+end
+
+if pipeworks.enable_crossing_tube then
+ pipeworks.register_tube("pipeworks:crossing_tube", {
+ description = "Crossing Pneumatic Tube Segment",
+ inventory_image = "pipeworks_crossing_tube_inv.png",
+ plain = { "pipeworks_crossing_tube_plain.png" },
+ noctr = { "pipeworks_crossing_tube_noctr.png" },
+ ends = { "pipeworks_crossing_tube_end.png" },
+ short = "pipeworks_crossing_tube_short.png",
+ node_def = {
+ tube = {can_go = function(pos, node, velocity, stack) return {velocity} end }
+ },
+ })
+ minetest.register_craft( {
+ output = "pipeworks:crossing_tube_1 5",
+ recipe = {
+ { "", "pipeworks:tube_1", "" },
+ { "pipeworks:tube_1", "pipeworks:tube_1", "pipeworks:tube_1" },
+ { "", "pipeworks:tube_1", "" }
+ },
+ })
+end
+
+if pipeworks.enable_one_way_tube then
+ minetest.register_node("pipeworks:one_way_tube", {
+ description = "One way tube",
+ tiles = {"pipeworks_one_way_tube_top.png", "pipeworks_one_way_tube_top.png", "pipeworks_one_way_tube_output.png",
+ "pipeworks_one_way_tube_input.png", "pipeworks_one_way_tube_side.png", "pipeworks_one_way_tube_top.png"},
+ paramtype2 = "facedir",
+ drawtype = "nodebox",
+ paramtype = "light",
+ node_box = {type = "fixed",
+ fixed = {{-1/2, -9/64, -9/64, 1/2, 9/64, 9/64}}},
+ groups = {snappy = 2, choppy = 2, oddly_breakable_by_hand = 2, tubedevice = 1},
+ sounds = default.node_sound_wood_defaults(),
+ tube = {
+ connect_sides = {left = 1, right = 1},
+ can_go = function(pos, node, velocity, stack)
+ return {velocity}
+ end,
+ can_insert = function(pos, node, stack, direction)
+ local dir = minetest.facedir_to_right_dir(node.param2)
+ return vector.equals(dir, direction)
+ end,
+ priority = 75 -- Higher than normal tubes, but lower than receivers
+ },
+ after_place_node = pipeworks.after_place,
+ after_dig_node = pipeworks.after_dig,
+ })
+ minetest.register_craft({
+ output = "pipeworks:one_way_tube 2",
+ recipe = {
+ { "homedecor:plastic_sheeting", "homedecor:plastic_sheeting", "homedecor:plastic_sheeting" },
+ { "group:stick", "default:mese_crystal", "homedecor:plastic_sheeting" },
+ { "homedecor:plastic_sheeting", "homedecor:plastic_sheeting", "homedecor:plastic_sheeting" }
+ },
+ })
+end
diff --git a/pipeworks/signal_tubes.lua b/pipeworks/signal_tubes.lua
new file mode 100644
index 0000000..bfce14a
--- /dev/null
+++ b/pipeworks/signal_tubes.lua
@@ -0,0 +1,111 @@
+if pipeworks.enable_detector_tube then
+ local detector_tube_step = 2 * tonumber(minetest.setting_get("dedicated_server_step"))
+ pipeworks.register_tube("pipeworks:detector_tube_on", {
+ description = "Detecting Pneumatic Tube Segment on (you hacker you)",
+ inventory_image = "pipeworks_detector_tube_inv.png",
+ plain = { "pipeworks_detector_tube_plain.png" },
+ node_def = {
+ tube = {can_go = function(pos, node, velocity, stack)
+ local meta = minetest.get_meta(pos)
+ local name = minetest.get_node(pos).name
+ local nitems = meta:get_int("nitems")+1
+ meta:set_int("nitems", nitems)
+ local saved_pos = vector.new(pos)
+ minetest.after(detector_tube_step, minetest.registered_nodes[name].item_exit, saved_pos)
+ return pipeworks.notvel(pipeworks.meseadjlist,velocity)
+ end},
+ groups = {mesecon = 2, not_in_creative_inventory = 1},
+ drop = "pipeworks:detector_tube_off_1",
+ mesecons = {receptor = {state = "on", rules = pipeworks.mesecons_rules}},
+ item_exit = function(pos)
+ local meta = minetest.get_meta(pos)
+ local nitems = meta:get_int("nitems")-1
+ local node = minetest.get_node(pos)
+ local name = node.name
+ local fdir = node.param2
+ if nitems == 0 then
+ minetest.set_node(pos, {name = string.gsub(name, "on", "off"), param2 = fdir})
+ mesecon.receptor_off(pos, pipeworks.mesecons_rules)
+ else
+ meta:set_int("nitems", nitems)
+ end
+ end,
+ on_construct = function(pos)
+ local meta = minetest.get_meta(pos)
+ meta:set_int("nitems", 1)
+ local name = minetest.get_node(pos).name
+ local saved_pos = vector.new(pos)
+ minetest.after(detector_tube_step, minetest.registered_nodes[name].item_exit, saved_pos)
+ end,
+ },
+ })
+ pipeworks.register_tube("pipeworks:detector_tube_off", {
+ description = "Detecting Pneumatic Tube Segment",
+ inventory_image = "pipeworks_detector_tube_inv.png",
+ plain = { "pipeworks_detector_tube_plain.png" },
+ node_def = {
+ tube = {can_go = function(pos, node, velocity, stack)
+ local node = minetest.get_node(pos)
+ local name = node.name
+ local fdir = node.param2
+ minetest.set_node(pos,{name = string.gsub(name, "off", "on"), param2 = fdir})
+ mesecon.receptor_on(pos, pipeworks.mesecons_rules)
+ return pipeworks.notvel(pipeworks.meseadjlist, velocity)
+ end},
+ groups = {mesecon = 2},
+ mesecons = {receptor = {state = "off", rules = pipeworks.mesecons_rules }},
+ },
+ })
+
+ minetest.register_craft( {
+ output = "pipeworks:conductor_tube_off_1 6",
+ recipe = {
+ { "homedecor:plastic_sheeting", "homedecor:plastic_sheeting", "homedecor:plastic_sheeting" },
+ { "mesecons:mesecon", "mesecons:mesecon", "mesecons:mesecon" },
+ { "homedecor:plastic_sheeting", "homedecor:plastic_sheeting", "homedecor:plastic_sheeting" }
+ },
+ })
+end
+
+if pipeworks.enable_conductor_tube then
+ pipeworks.register_tube("pipeworks:conductor_tube_off", {
+ description = "Conducting Pneumatic Tube Segment",
+ inventory_image = "pipeworks_conductor_tube_inv.png",
+ short = "pipeworks_conductor_tube_short.png",
+ plain = { "pipeworks_conductor_tube_plain.png" },
+ noctr = { "pipeworks_conductor_tube_noctr.png" },
+ ends = { "pipeworks_conductor_tube_end.png" },
+ node_def = {
+ groups = {mesecon = 2},
+ mesecons = {conductor = {state = "off",
+ rules = pipeworks.mesecons_rules,
+ onstate = "pipeworks:conductor_tube_on_#id"}}
+ },
+ })
+ pipeworks.register_tube("pipeworks:conductor_tube_on", {
+ description = "Conducting Pneumatic Tube Segment on (you hacker you)",
+ inventory_image = "pipeworks_conductor_tube_inv.png",
+ short = "pipeworks_conductor_tube_short.png",
+ plain = { "pipeworks_conductor_tube_on_plain.png" },
+ noctr = { "pipeworks_conductor_tube_on_noctr.png" },
+ ends = { "pipeworks_conductor_tube_on_end.png" },
+ node_def = {
+ groups = {mesecon = 2, not_in_creative_inventory = 1},
+ drop = "pipeworks:conductor_tube_off_1",
+ mesecons = {conductor = {state = "on",
+ rules = pipeworks.mesecons_rules,
+ offstate = "pipeworks:conductor_tube_off_#id"}}
+ },
+ })
+
+ minetest.register_craft( {
+ output = "pipeworks:detector_tube_off_1 2",
+ recipe = {
+ { "homedecor:plastic_sheeting", "homedecor:plastic_sheeting", "homedecor:plastic_sheeting" },
+ { "mesecons:mesecon", "mesecons_materials:silicon", "mesecons:mesecon" },
+ { "homedecor:plastic_sheeting", "homedecor:plastic_sheeting", "homedecor:plastic_sheeting" }
+ },
+ })
+end
+
+
diff --git a/pipeworks/sorting_tubes.lua b/pipeworks/sorting_tubes.lua
new file mode 100644
index 0000000..795291b
--- /dev/null
+++ b/pipeworks/sorting_tubes.lua
@@ -0,0 +1,148 @@
+if pipeworks.enable_mese_tube then
+ local function update_formspec(pos)
+ local meta = minetest.get_meta(pos)
+ local old_formspec = meta:get_string("formspec")
+ if string.find(old_formspec, "button1") then -- Old version
+ local inv = meta:get_inventory()
+ for i = 1, 6 do
+ for _, stack in ipairs(inv:get_list("line"..i)) do
+ minetest.item_drop(stack, nil, pos)
+ end
+ end
+ end
+ local buttons_formspec = ""
+ for i = 0, 5 do
+ buttons_formspec = buttons_formspec .. fs_helpers.cycling_button(meta,
+ "image_button[7,"..(i)..";1,1", "l"..(i+1).."s",
+ {{text="",texture="pipeworks_button_off.png", addopts="false;false;pipeworks_button_interm.png"}, {text="",texture="pipeworks_button_on.png", addopts="false;false;pipeworks_button_interm.png"}})
+ end
+ meta:set_string("formspec",
+ "size[8,11]"..
+ "list[context;line1;1,0;6,1;]"..
+ "list[context;line2;1,1;6,1;]"..
+ "list[context;line3;1,2;6,1;]"..
+ "list[context;line4;1,3;6,1;]"..
+ "list[context;line5;1,4;6,1;]"..
+ "list[context;line6;1,5;6,1;]"..
+ "image[0,0;1,1;pipeworks_white.png]"..
+ "image[0,1;1,1;pipeworks_black.png]"..
+ "image[0,2;1,1;pipeworks_green.png]"..
+ "image[0,3;1,1;pipeworks_yellow.png]"..
+ "image[0,4;1,1;pipeworks_blue.png]"..
+ "image[0,5;1,1;pipeworks_red.png]"..
+ buttons_formspec..
+ "list[current_player;main;0,7;8,4;]")
+ end
+
+ pipeworks.register_tube("pipeworks:mese_tube", {
+ description = "Sorting Pneumatic Tube Segment",
+ inventory_image = "pipeworks_mese_tube_inv.png",
+ noctr = {"pipeworks_mese_tube_noctr_1.png", "pipeworks_mese_tube_noctr_2.png", "pipeworks_mese_tube_noctr_3.png",
+ "pipeworks_mese_tube_noctr_4.png", "pipeworks_mese_tube_noctr_5.png", "pipeworks_mese_tube_noctr_6.png"},
+ plain = {"pipeworks_mese_tube_plain_1.png", "pipeworks_mese_tube_plain_2.png", "pipeworks_mese_tube_plain_3.png",
+ "pipeworks_mese_tube_plain_4.png", "pipeworks_mese_tube_plain_5.png", "pipeworks_mese_tube_plain_6.png"},
+ ends = { "pipeworks_mese_tube_end.png" },
+ short = "pipeworks_mese_tube_short.png",
+ no_facedir = true, -- Must use old tubes, since the textures are rotated with 6d ones
+ node_def = {
+ tube = {can_go = function(pos, node, velocity, stack)
+ local tbl, tbln = {}, 0
+ local found, foundn = {}, 0
+ local meta = minetest.get_meta(pos)
+ local inv = meta:get_inventory()
+ local name = stack:get_name()
+ for i, vect in ipairs(pipeworks.meseadjlist) do
+ local npos = vector.add(pos, vect)
+ local node = minetest.get_node(npos)
+ local reg_node = minetest.registered_nodes[node.name]
+ if meta:get_int("l"..i.."s") == 1 and reg_node then
+ local tube_def = reg_node.tube
+ if not tube_def or not tube_def.can_insert or
+ tube_def.can_insert(npos, node, stack, vect) then
+ local invname = "line"..i
+ local is_empty = true
+ for _, st in ipairs(inv:get_list(invname)) do
+ if not st:is_empty() then
+ is_empty = false
+ if st:get_name() == name then
+ foundn = foundn + 1
+ found[foundn] = vect
+ end
+ end
+ end
+ if is_empty then
+ tbln = tbln + 1
+ tbl[tbln] = vect
+ end
+ end
+ end
+ end
+ return (foundn > 0) and found or tbl
+ end},
+ on_construct = function(pos)
+ local meta = minetest.get_meta(pos)
+ local inv = meta:get_inventory()
+ for i = 1, 6 do
+ meta:set_int("l"..tostring(i).."s", 1)
+ inv:set_size("line"..tostring(i), 6*1)
+ end
+ update_formspec(pos)
+ meta:set_string("infotext", "Sorting pneumatic tube")
+ end,
+ on_punch = update_formspec,
+ on_receive_fields = function(pos, formname, fields, sender)
+ if not pipeworks.may_configure(pos, sender) then return end
+ fs_helpers.on_receive_fields(pos, fields)
+ update_formspec(pos)
+ end,
+ can_dig = function(pos, player)
+ update_formspec(pos) -- so non-virtual items would be dropped for old tubes
+ return true
+ end,
+ allow_metadata_inventory_put = function(pos, listname, index, stack, player)
+ if not pipeworks.may_configure(pos, player) then return 0 end
+ update_formspec(pos) -- For old tubes
+ local inv = minetest.get_meta(pos):get_inventory()
+ local stack_copy = ItemStack(stack)
+ stack_copy:set_count(1)
+ inv:set_stack(listname, index, stack_copy)
+ return 0
+ end,
+ allow_metadata_inventory_take = function(pos, listname, index, stack, player)
+ if not pipeworks.may_configure(pos, player) then return 0 end
+ update_formspec(pos) -- For old tubes
+ local inv = minetest.get_meta(pos):get_inventory()
+ inv:set_stack(listname, index, ItemStack(""))
+ return 0
+ end,
+ allow_metadata_inventory_move = function(pos, from_list, from_index, to_list, to_index, count, player)
+ if not pipeworks.may_configure(pos, player) then return 0 end
+ update_formspec(pos) -- For old tubes
+ local inv = minetest.get_meta(pos):get_inventory()
+ inv:set_stack(from_list, from_index, ItemStack(""))
+ return 0
+ end,
+ },
+ })
+
+ minetest.register_craft( {
+ output = "pipeworks:mese_tube_000000 2",
+ recipe = {
+ { "homedecor:plastic_sheeting", "homedecor:plastic_sheeting", "homedecor:plastic_sheeting" },
+ { "", "default:mese_crystal", "" },
+ { "homedecor:plastic_sheeting", "homedecor:plastic_sheeting", "homedecor:plastic_sheeting" }
+ },
+ })
+
+ minetest.register_craft( {
+ type = "shapeless",
+ output = "pipeworks:mese_tube_000000",
+ recipe = {
+ "pipeworks:tube_1",
+ "default:mese_crystal_fragment",
+ "default:mese_crystal_fragment",
+ "default:mese_crystal_fragment",
+ "default:mese_crystal_fragment"
+ },
+ })
+end
diff --git a/pipeworks/teleport_tube.lua b/pipeworks/teleport_tube.lua
new file mode 100644
index 0000000..3a870f5
--- /dev/null
+++ b/pipeworks/teleport_tube.lua
@@ -0,0 +1,242 @@
+local filename=minetest.get_worldpath() .. "/teleport_tubes"
+
+local tp_tube_db = nil -- nil forces a read
+local tp_tube_db_version = 2.0
+
+local function hash(pos)
+ return string.format("%d", minetest.hash_node_position(pos))
+end
+
+local function save_tube_db()
+ local file, err = io.open(filename, "w")
+ if file then
+ tp_tube_db.version = tp_tube_db_version
+ file:write(minetest.serialize(tp_tube_db))
+ tp_tube_db.version = nil
+ io.close(file)
+ else
+ error(err)
+ end
+end
+
+local function migrate_tube_db()
+ local tmp_db = {}
+ tp_tube_db.version = nil
+ for key, val in pairs(tp_tube_db) do
+ if(val.channel ~= "") then -- skip unconfigured tubes
+ tmp_db[hash(val)] = val
+ end
+ end
+ tp_tube_db = tmp_db
+ save_tube_db()
+end
+
+local function read_tube_db()
+ local file = io.open(filename, "r")
+ if file ~= nil then
+ local file_content = file:read("*all")
+ io.close(file)
+
+ if file_content and file_content ~= "" then
+ tp_tube_db = minetest.deserialize(file_content)
+ if(not tp_tube_db.version or tonumber(tp_tube_db.version) < tp_tube_db_version) then
+ migrate_tube_db()
+ end
+ tp_tube_db.version = nil -- we add it back when saving
+ return tp_tube_db -- we read sucessfully
+ end
+ end
+ tp_tube_db = {}
+ return tp_tube_db
+end
+
+-- updates or adds a tube
+local function set_tube(pos, channel, can_receive)
+ local tubes = tp_tube_db or read_tube_db()
+ local hash = hash(pos)
+ local tube = tubes[hash]
+ if tube then
+ tube.channel = channel
+ tube.cr = can_receive
+ save_tube_db()
+ return
+ end
+
+ -- we haven't found any tp tube to update, so lets add it
+ tp_tube_db[hash] = {x=pos.x,y=pos.y,z=pos.z,channel=channel,cr=can_receive}
+ save_tube_db()
+end
+
+local function remove_tube(pos)
+ local tubes = tp_tube_db or read_tube_db()
+ tubes[hash(pos)] = nil
+ save_tube_db()
+end
+
+local function read_node_with_vm(pos)
+ local vm = VoxelManip()
+ local MinEdge, MaxEdge = vm:read_from_map(pos, pos)
+ local data = vm:get_data()
+ local area = VoxelArea:new({MinEdge = MinEdge, MaxEdge = MaxEdge})
+ return minetest.get_name_from_content_id(data[area:index(pos.x, pos.y, pos.z)])
+end
+
+local function get_receivers(pos, channel)
+ local tubes = tp_tube_db or read_tube_db()
+ local receivers = {}
+ local dirty = false
+ for key, val in pairs(tubes) do
+ -- skip all non-receivers and the tube that it came from as early as possible, as this is called often
+ if (val.cr == 1 and val.channel == channel and (val.x ~= pos.x or val.y ~= pos.y or val.z ~= pos.z)) then
+ local is_loaded = (minetest.get_node_or_nil(val) ~= nil)
+ local node_name = is_loaded and minetest.get_node(pos).name or read_node_with_vm(val)
+
+ if minetest.registered_nodes[node_name] and minetest.registered_nodes[node_name].is_teleport_tube then
+ table.insert(receivers, val)
+ else
+ tp_tube_db[key] = nil
+ dirty = true
+ end
+ end
+ end
+ if dirty then
+ save_tube_db()
+ end
+ return receivers
+end
+
+local function update_meta(meta, can_receive)
+ meta:set_int("can_receive", can_receive and 1 or 0)
+ local cr_state = can_receive and "on" or "off"
+ meta:set_string("formspec","size[8.6,2.2]"..
+ "field[0.6,0.6;7,1;channel;Channel:;${channel}]"..
+ "label[7.3,0;Receive]"..
+ "image_button[7.3,0.3;1,1;pipeworks_button_" .. cr_state .. ".png;cr" .. (can_receive and 0 or 1) .. ";;;false;pipeworks_button_interm.png]"..
+ "image[0.3,1.3;1,1;pipeworks_teleport_tube_inv.png]"..
+ "label[1.6,1.2;channels are public by default]" ..
+ "label[1.6,1.5;use <player>:<channel> for fully private channels]" ..
+ "label[1.6,1.8;use <player>\\;<channel> for private receivers]" ..
+ default.gui_bg..
+ default.gui_bg_img)
+end
+
+pipeworks.register_tube("pipeworks:teleport_tube", {
+ description = "Teleporting Pneumatic Tube Segment",
+ inventory_image = "pipeworks_teleport_tube_inv.png",
+ noctr = { "pipeworks_teleport_tube_noctr.png" },
+ plain = { "pipeworks_teleport_tube_plain.png" },
+ ends = { "pipeworks_teleport_tube_end.png" },
+ short = "pipeworks_teleport_tube_short.png",
+ node_def = {
+ is_teleport_tube = true,
+ tube = {
+ can_go = function(pos,node,velocity,stack)
+ velocity.x = 0
+ velocity.y = 0
+ velocity.z = 0
+
+ local channel = minetest.get_meta(pos):get_string("channel")
+ if channel == "" then return {} end
+
+ local target = get_receivers(pos, channel)
+ if target[1] == nil then return {} end
+
+ local d = math.random(1,#target)
+ pos.x = target[d].x
+ pos.y = target[d].y
+ pos.z = target[d].z
+ return pipeworks.meseadjlist
+ end
+ },
+ on_construct = function(pos)
+ local meta = minetest.get_meta(pos)
+ update_meta(meta, true)
+ meta:set_string("infotext", "unconfigured Teleportation Tube")
+ end,
+ on_receive_fields = function(pos,formname,fields,sender)
+ if not fields.channel -- ignore escaping or clientside manipulation of the form
+ or not pipeworks.may_configure(pos, sender) then
+ return
+ end
+ local new_channel = tostring(fields.channel):trim()
+
+ local meta = minetest.get_meta(pos)
+ local can_receive = meta:get_int("can_receive")
+
+ -- check for private channels each time before actually changing anything
+ -- to not even allow switching between can_receive states of private channels
+ if new_channel ~= "" then
+ local sender_name = sender:get_player_name()
+ local name, mode = new_channel:match("^([^:;]+)([:;])")
+ if name and mode and name ~= sender_name then
+ --channels starting with '[name]:' can only be used by the named player
+ if mode == ":" then
+ minetest.chat_send_player(sender_name, "Sorry, channel '"..new_channel.."' is reserved for exclusive use by "..name)
+ return
+
+ --channels starting with '[name];' can be used by other players, but cannot be received from
+ elseif mode == ";" and (fields.cr1 or (can_receive ~= 0 and not fields.cr0)) then
+ minetest.chat_send_player(sender_name, "Sorry, receiving from channel '"..new_channel.."' is reserved for "..name)
+ return
+ end
+ end
+ end
+
+ local dirty = false
+
+ -- was the channel changed?
+ local channel = meta:get_string("channel")
+ if new_channel ~= channel then
+ channel = new_channel
+ meta:set_string("channel", channel)
+ dirty = true
+ end
+
+ -- test if a can_receive button was pressed
+ if fields.cr0 and can_receive ~= 0 then
+ can_receive = 0
+ update_meta(meta, false)
+ dirty = true
+ elseif fields.cr1 and can_receive ~= 1 then
+ can_receive = 1
+ update_meta(meta, true)
+ dirty = true
+ end
+
+ -- save if we changed something, handle the empty channel while we're at it
+ if dirty then
+ if channel ~= "" then
+ set_tube(pos, channel, can_receive)
+ local cr_description = (can_receive == 1) and "sending and receiving" or "sending"
+ meta:set_string("infotext", string.format("Teleportation Tube %s on '%s'", cr_description, channel))
+ else
+ -- remove empty channel tubes, to not have to search through them
+ remove_tube(pos)
+ meta:set_string("infotext", "unconfigured Teleportation Tube")
+ end
+ end
+ end,
+ on_destruct = function(pos)
+ remove_tube(pos)
+ end
+ },
+})
+minetest.register_craft( {
+ output = "pipeworks:teleport_tube_1 2",
+ recipe = {
+ { "homedecor:plastic_sheeting", "homedecor:plastic_sheeting", "homedecor:plastic_sheeting" },
+ { "default:desert_stone", "default:mese", "default:desert_stone" },
+ { "homedecor:plastic_sheeting", "homedecor:plastic_sheeting", "homedecor:plastic_sheeting" }
+ },
+})
+
+if minetest.get_modpath("mesecons_mvps") ~= nil then
+ mesecon.register_on_mvps_move(function(moved_nodes)
+ for _, n in ipairs(moved_nodes) do
+ if string.find(n.node.name, "pipeworks:teleport_tube") ~= nil then
+ local meta = minetest.get_meta(n.pos)
+ set_tube(n.pos, meta:get_string("channel"), meta:get_int("can_receive"))
+ end
+ end
+ end)
+end
diff --git a/pipeworks/textures/homedecor_oil_extract.png b/pipeworks/textures/homedecor_oil_extract.png
new file mode 100644
index 0000000..b945a9e
--- /dev/null
+++ b/pipeworks/textures/homedecor_oil_extract.png
Binary files differ
diff --git a/pipeworks/textures/homedecor_paraffin.png b/pipeworks/textures/homedecor_paraffin.png
new file mode 100644
index 0000000..77d2bbd
--- /dev/null
+++ b/pipeworks/textures/homedecor_paraffin.png
Binary files differ
diff --git a/pipeworks/textures/homedecor_plastic_sheeting.png b/pipeworks/textures/homedecor_plastic_sheeting.png
new file mode 100644
index 0000000..fba0ccd
--- /dev/null
+++ b/pipeworks/textures/homedecor_plastic_sheeting.png
Binary files differ
diff --git a/pipeworks/textures/pipeworks_accelerator_tube_end.png b/pipeworks/textures/pipeworks_accelerator_tube_end.png
new file mode 100644
index 0000000..6839165
--- /dev/null
+++ b/pipeworks/textures/pipeworks_accelerator_tube_end.png
Binary files differ
diff --git a/pipeworks/textures/pipeworks_accelerator_tube_inv.png b/pipeworks/textures/pipeworks_accelerator_tube_inv.png
new file mode 100644
index 0000000..743956a
--- /dev/null
+++ b/pipeworks/textures/pipeworks_accelerator_tube_inv.png
Binary files differ
diff --git a/pipeworks/textures/pipeworks_accelerator_tube_noctr.png b/pipeworks/textures/pipeworks_accelerator_tube_noctr.png
new file mode 100644
index 0000000..fa0daa6
--- /dev/null
+++ b/pipeworks/textures/pipeworks_accelerator_tube_noctr.png
Binary files differ
diff --git a/pipeworks/textures/pipeworks_accelerator_tube_plain.png b/pipeworks/textures/pipeworks_accelerator_tube_plain.png
new file mode 100644
index 0000000..8256d05
--- /dev/null
+++ b/pipeworks/textures/pipeworks_accelerator_tube_plain.png
Binary files differ
diff --git a/pipeworks/textures/pipeworks_accelerator_tube_short.png b/pipeworks/textures/pipeworks_accelerator_tube_short.png
new file mode 100644
index 0000000..1444b43
--- /dev/null
+++ b/pipeworks/textures/pipeworks_accelerator_tube_short.png
Binary files differ
diff --git a/pipeworks/textures/pipeworks_autocrafter.png b/pipeworks/textures/pipeworks_autocrafter.png
new file mode 100644
index 0000000..1643e82
--- /dev/null
+++ b/pipeworks/textures/pipeworks_autocrafter.png
Binary files differ
diff --git a/pipeworks/textures/pipeworks_black.png b/pipeworks/textures/pipeworks_black.png
new file mode 100644
index 0000000..34afad8
--- /dev/null
+++ b/pipeworks/textures/pipeworks_black.png
Binary files differ
diff --git a/pipeworks/textures/pipeworks_blue.png b/pipeworks/textures/pipeworks_blue.png
new file mode 100644
index 0000000..64c8a6f
--- /dev/null
+++ b/pipeworks/textures/pipeworks_blue.png
Binary files differ
diff --git a/pipeworks/textures/pipeworks_button_interm.png b/pipeworks/textures/pipeworks_button_interm.png
new file mode 100644
index 0000000..47320ce
--- /dev/null
+++ b/pipeworks/textures/pipeworks_button_interm.png
Binary files differ
diff --git a/pipeworks/textures/pipeworks_button_off.png b/pipeworks/textures/pipeworks_button_off.png
new file mode 100644
index 0000000..319fc6e
--- /dev/null
+++ b/pipeworks/textures/pipeworks_button_off.png
Binary files differ
diff --git a/pipeworks/textures/pipeworks_button_on.png b/pipeworks/textures/pipeworks_button_on.png
new file mode 100644
index 0000000..a9884cf
--- /dev/null
+++ b/pipeworks/textures/pipeworks_button_on.png
Binary files differ
diff --git a/pipeworks/textures/pipeworks_conductor_tube_end.png b/pipeworks/textures/pipeworks_conductor_tube_end.png
new file mode 100644
index 0000000..5942662
--- /dev/null
+++ b/pipeworks/textures/pipeworks_conductor_tube_end.png
Binary files differ
diff --git a/pipeworks/textures/pipeworks_conductor_tube_inv.png b/pipeworks/textures/pipeworks_conductor_tube_inv.png
new file mode 100644
index 0000000..6323937
--- /dev/null
+++ b/pipeworks/textures/pipeworks_conductor_tube_inv.png
Binary files differ
diff --git a/pipeworks/textures/pipeworks_conductor_tube_noctr.png b/pipeworks/textures/pipeworks_conductor_tube_noctr.png
new file mode 100644
index 0000000..f5e0501
--- /dev/null
+++ b/pipeworks/textures/pipeworks_conductor_tube_noctr.png
Binary files differ
diff --git a/pipeworks/textures/pipeworks_conductor_tube_on_end.png b/pipeworks/textures/pipeworks_conductor_tube_on_end.png
new file mode 100644
index 0000000..46d0e30
--- /dev/null
+++ b/pipeworks/textures/pipeworks_conductor_tube_on_end.png
Binary files differ
diff --git a/pipeworks/textures/pipeworks_conductor_tube_on_noctr.png b/pipeworks/textures/pipeworks_conductor_tube_on_noctr.png
new file mode 100644
index 0000000..27d2483
--- /dev/null
+++ b/pipeworks/textures/pipeworks_conductor_tube_on_noctr.png
Binary files differ
diff --git a/pipeworks/textures/pipeworks_conductor_tube_on_plain.png b/pipeworks/textures/pipeworks_conductor_tube_on_plain.png
new file mode 100644
index 0000000..c58eaf2
--- /dev/null
+++ b/pipeworks/textures/pipeworks_conductor_tube_on_plain.png
Binary files differ
diff --git a/pipeworks/textures/pipeworks_conductor_tube_plain.png b/pipeworks/textures/pipeworks_conductor_tube_plain.png
new file mode 100644
index 0000000..e0891ed
--- /dev/null
+++ b/pipeworks/textures/pipeworks_conductor_tube_plain.png
Binary files differ
diff --git a/pipeworks/textures/pipeworks_conductor_tube_short.png b/pipeworks/textures/pipeworks_conductor_tube_short.png
new file mode 100644
index 0000000..7ec809a
--- /dev/null
+++ b/pipeworks/textures/pipeworks_conductor_tube_short.png
Binary files differ
diff --git a/pipeworks/textures/pipeworks_crossing_tube_end.png b/pipeworks/textures/pipeworks_crossing_tube_end.png
new file mode 100644
index 0000000..7b51ce3
--- /dev/null
+++ b/pipeworks/textures/pipeworks_crossing_tube_end.png
Binary files differ
diff --git a/pipeworks/textures/pipeworks_crossing_tube_inv.png b/pipeworks/textures/pipeworks_crossing_tube_inv.png
new file mode 100644
index 0000000..2ee350b
--- /dev/null
+++ b/pipeworks/textures/pipeworks_crossing_tube_inv.png
Binary files differ
diff --git a/pipeworks/textures/pipeworks_crossing_tube_noctr.png b/pipeworks/textures/pipeworks_crossing_tube_noctr.png
new file mode 100644
index 0000000..fdef1be
--- /dev/null
+++ b/pipeworks/textures/pipeworks_crossing_tube_noctr.png
Binary files differ
diff --git a/pipeworks/textures/pipeworks_crossing_tube_plain.png b/pipeworks/textures/pipeworks_crossing_tube_plain.png
new file mode 100644
index 0000000..0ed695f
--- /dev/null
+++ b/pipeworks/textures/pipeworks_crossing_tube_plain.png
Binary files differ
diff --git a/pipeworks/textures/pipeworks_crossing_tube_short.png b/pipeworks/textures/pipeworks_crossing_tube_short.png
new file mode 100644
index 0000000..ef191de
--- /dev/null
+++ b/pipeworks/textures/pipeworks_crossing_tube_short.png
Binary files differ
diff --git a/pipeworks/textures/pipeworks_deployer_back.png b/pipeworks/textures/pipeworks_deployer_back.png
new file mode 100644
index 0000000..4e08be3
--- /dev/null
+++ b/pipeworks/textures/pipeworks_deployer_back.png
Binary files differ
diff --git a/pipeworks/textures/pipeworks_deployer_bottom.png b/pipeworks/textures/pipeworks_deployer_bottom.png
new file mode 100644
index 0000000..fcb863c
--- /dev/null
+++ b/pipeworks/textures/pipeworks_deployer_bottom.png
Binary files differ
diff --git a/pipeworks/textures/pipeworks_deployer_front_off.png b/pipeworks/textures/pipeworks_deployer_front_off.png
new file mode 100644
index 0000000..a314c8b
--- /dev/null
+++ b/pipeworks/textures/pipeworks_deployer_front_off.png
Binary files differ
diff --git a/pipeworks/textures/pipeworks_deployer_front_on.png b/pipeworks/textures/pipeworks_deployer_front_on.png
new file mode 100644
index 0000000..a59a61e
--- /dev/null
+++ b/pipeworks/textures/pipeworks_deployer_front_on.png
Binary files differ
diff --git a/pipeworks/textures/pipeworks_deployer_side.png b/pipeworks/textures/pipeworks_deployer_side.png
new file mode 100644
index 0000000..2c7da56
--- /dev/null
+++ b/pipeworks/textures/pipeworks_deployer_side.png
Binary files differ
diff --git a/pipeworks/textures/pipeworks_deployer_side1.png b/pipeworks/textures/pipeworks_deployer_side1.png
new file mode 100644
index 0000000..2c7da56
--- /dev/null
+++ b/pipeworks/textures/pipeworks_deployer_side1.png
Binary files differ
diff --git a/pipeworks/textures/pipeworks_deployer_side2.png b/pipeworks/textures/pipeworks_deployer_side2.png
new file mode 100644
index 0000000..eb24061
--- /dev/null
+++ b/pipeworks/textures/pipeworks_deployer_side2.png
Binary files differ
diff --git a/pipeworks/textures/pipeworks_deployer_top.png b/pipeworks/textures/pipeworks_deployer_top.png
new file mode 100644
index 0000000..f331212
--- /dev/null
+++ b/pipeworks/textures/pipeworks_deployer_top.png
Binary files differ
diff --git a/pipeworks/textures/pipeworks_detector_tube_end.png b/pipeworks/textures/pipeworks_detector_tube_end.png
new file mode 100644
index 0000000..e9d01ba
--- /dev/null
+++ b/pipeworks/textures/pipeworks_detector_tube_end.png
Binary files differ
diff --git a/pipeworks/textures/pipeworks_detector_tube_inv.png b/pipeworks/textures/pipeworks_detector_tube_inv.png
new file mode 100644
index 0000000..0e3b7d8
--- /dev/null
+++ b/pipeworks/textures/pipeworks_detector_tube_inv.png
Binary files differ
diff --git a/pipeworks/textures/pipeworks_detector_tube_noctr.png b/pipeworks/textures/pipeworks_detector_tube_noctr.png
new file mode 100644
index 0000000..6f07886
--- /dev/null
+++ b/pipeworks/textures/pipeworks_detector_tube_noctr.png
Binary files differ
diff --git a/pipeworks/textures/pipeworks_detector_tube_plain.png b/pipeworks/textures/pipeworks_detector_tube_plain.png
new file mode 100644
index 0000000..6a9845c
--- /dev/null
+++ b/pipeworks/textures/pipeworks_detector_tube_plain.png
Binary files differ
diff --git a/pipeworks/textures/pipeworks_detector_tube_short.png b/pipeworks/textures/pipeworks_detector_tube_short.png
new file mode 100644
index 0000000..6729c53
--- /dev/null
+++ b/pipeworks/textures/pipeworks_detector_tube_short.png
Binary files differ
diff --git a/pipeworks/textures/pipeworks_dispenser_back.png b/pipeworks/textures/pipeworks_dispenser_back.png
new file mode 100644
index 0000000..ce447bd
--- /dev/null
+++ b/pipeworks/textures/pipeworks_dispenser_back.png
Binary files differ
diff --git a/pipeworks/textures/pipeworks_dispenser_bottom.png b/pipeworks/textures/pipeworks_dispenser_bottom.png
new file mode 100644
index 0000000..16dc584
--- /dev/null
+++ b/pipeworks/textures/pipeworks_dispenser_bottom.png
Binary files differ
diff --git a/pipeworks/textures/pipeworks_dispenser_front_off.png b/pipeworks/textures/pipeworks_dispenser_front_off.png
new file mode 100644
index 0000000..b0c9e4a
--- /dev/null
+++ b/pipeworks/textures/pipeworks_dispenser_front_off.png
Binary files differ
diff --git a/pipeworks/textures/pipeworks_dispenser_front_on.png b/pipeworks/textures/pipeworks_dispenser_front_on.png
new file mode 100644
index 0000000..c9fff11
--- /dev/null
+++ b/pipeworks/textures/pipeworks_dispenser_front_on.png
Binary files differ
diff --git a/pipeworks/textures/pipeworks_dispenser_side1.png b/pipeworks/textures/pipeworks_dispenser_side1.png
new file mode 100644
index 0000000..bd17852
--- /dev/null
+++ b/pipeworks/textures/pipeworks_dispenser_side1.png
Binary files differ
diff --git a/pipeworks/textures/pipeworks_dispenser_side2.png b/pipeworks/textures/pipeworks_dispenser_side2.png
new file mode 100644
index 0000000..005d9a5
--- /dev/null
+++ b/pipeworks/textures/pipeworks_dispenser_side2.png
Binary files differ
diff --git a/pipeworks/textures/pipeworks_dispenser_top.png b/pipeworks/textures/pipeworks_dispenser_top.png
new file mode 100644
index 0000000..7dd49ad
--- /dev/null
+++ b/pipeworks/textures/pipeworks_dispenser_top.png
Binary files differ
diff --git a/pipeworks/textures/pipeworks_entry_panel.png b/pipeworks/textures/pipeworks_entry_panel.png
new file mode 100644
index 0000000..040f408
--- /dev/null
+++ b/pipeworks/textures/pipeworks_entry_panel.png
Binary files differ
diff --git a/pipeworks/textures/pipeworks_filter_input.png b/pipeworks/textures/pipeworks_filter_input.png
new file mode 100644
index 0000000..187c402
--- /dev/null
+++ b/pipeworks/textures/pipeworks_filter_input.png
Binary files differ
diff --git a/pipeworks/textures/pipeworks_filter_output.png b/pipeworks/textures/pipeworks_filter_output.png
new file mode 100644
index 0000000..db7af08
--- /dev/null
+++ b/pipeworks/textures/pipeworks_filter_output.png
Binary files differ
diff --git a/pipeworks/textures/pipeworks_filter_side.png b/pipeworks/textures/pipeworks_filter_side.png
new file mode 100644
index 0000000..be1577a
--- /dev/null
+++ b/pipeworks/textures/pipeworks_filter_side.png
Binary files differ
diff --git a/pipeworks/textures/pipeworks_filter_top.png b/pipeworks/textures/pipeworks_filter_top.png
new file mode 100644
index 0000000..45b6b5a
--- /dev/null
+++ b/pipeworks/textures/pipeworks_filter_top.png
Binary files differ
diff --git a/pipeworks/textures/pipeworks_flow_sensor_off.png b/pipeworks/textures/pipeworks_flow_sensor_off.png
new file mode 100644
index 0000000..10c6846
--- /dev/null
+++ b/pipeworks/textures/pipeworks_flow_sensor_off.png
Binary files differ
diff --git a/pipeworks/textures/pipeworks_flow_sensor_on.png b/pipeworks/textures/pipeworks_flow_sensor_on.png
new file mode 100644
index 0000000..03e054a
--- /dev/null
+++ b/pipeworks/textures/pipeworks_flow_sensor_on.png
Binary files differ
diff --git a/pipeworks/textures/pipeworks_fountainhead.png b/pipeworks/textures/pipeworks_fountainhead.png
new file mode 100644
index 0000000..4affa69
--- /dev/null
+++ b/pipeworks/textures/pipeworks_fountainhead.png
Binary files differ
diff --git a/pipeworks/textures/pipeworks_grating_sides.png b/pipeworks/textures/pipeworks_grating_sides.png
new file mode 100644
index 0000000..28ce593
--- /dev/null
+++ b/pipeworks/textures/pipeworks_grating_sides.png
Binary files differ
diff --git a/pipeworks/textures/pipeworks_grating_top.png b/pipeworks/textures/pipeworks_grating_top.png
new file mode 100644
index 0000000..6e876fa
--- /dev/null
+++ b/pipeworks/textures/pipeworks_grating_top.png
Binary files differ
diff --git a/pipeworks/textures/pipeworks_green.png b/pipeworks/textures/pipeworks_green.png
new file mode 100644
index 0000000..3f42f9f
--- /dev/null
+++ b/pipeworks/textures/pipeworks_green.png
Binary files differ
diff --git a/pipeworks/textures/pipeworks_mese_filter_input.png b/pipeworks/textures/pipeworks_mese_filter_input.png
new file mode 100644
index 0000000..58095d0
--- /dev/null
+++ b/pipeworks/textures/pipeworks_mese_filter_input.png
Binary files differ
diff --git a/pipeworks/textures/pipeworks_mese_filter_output.png b/pipeworks/textures/pipeworks_mese_filter_output.png
new file mode 100644
index 0000000..a39e5a8
--- /dev/null
+++ b/pipeworks/textures/pipeworks_mese_filter_output.png
Binary files differ
diff --git a/pipeworks/textures/pipeworks_mese_filter_side.png b/pipeworks/textures/pipeworks_mese_filter_side.png
new file mode 100644
index 0000000..3438ce1
--- /dev/null
+++ b/pipeworks/textures/pipeworks_mese_filter_side.png
Binary files differ
diff --git a/pipeworks/textures/pipeworks_mese_filter_top.png b/pipeworks/textures/pipeworks_mese_filter_top.png
new file mode 100644
index 0000000..aa4f67c
--- /dev/null
+++ b/pipeworks/textures/pipeworks_mese_filter_top.png
Binary files differ
diff --git a/pipeworks/textures/pipeworks_mese_sand_tube_end.png b/pipeworks/textures/pipeworks_mese_sand_tube_end.png
new file mode 100644
index 0000000..fa59f37
--- /dev/null
+++ b/pipeworks/textures/pipeworks_mese_sand_tube_end.png
Binary files differ
diff --git a/pipeworks/textures/pipeworks_mese_sand_tube_inv.png b/pipeworks/textures/pipeworks_mese_sand_tube_inv.png
new file mode 100644
index 0000000..8b1b5e1
--- /dev/null
+++ b/pipeworks/textures/pipeworks_mese_sand_tube_inv.png
Binary files differ
diff --git a/pipeworks/textures/pipeworks_mese_sand_tube_noctr.png b/pipeworks/textures/pipeworks_mese_sand_tube_noctr.png
new file mode 100644
index 0000000..f26f39d
--- /dev/null
+++ b/pipeworks/textures/pipeworks_mese_sand_tube_noctr.png
Binary files differ
diff --git a/pipeworks/textures/pipeworks_mese_sand_tube_plain.png b/pipeworks/textures/pipeworks_mese_sand_tube_plain.png
new file mode 100644
index 0000000..8a48599
--- /dev/null
+++ b/pipeworks/textures/pipeworks_mese_sand_tube_plain.png
Binary files differ
diff --git a/pipeworks/textures/pipeworks_mese_sand_tube_short.png b/pipeworks/textures/pipeworks_mese_sand_tube_short.png
new file mode 100644
index 0000000..78ca710
--- /dev/null
+++ b/pipeworks/textures/pipeworks_mese_sand_tube_short.png
Binary files differ
diff --git a/pipeworks/textures/pipeworks_mese_tube_end.png b/pipeworks/textures/pipeworks_mese_tube_end.png
new file mode 100644
index 0000000..b47281a
--- /dev/null
+++ b/pipeworks/textures/pipeworks_mese_tube_end.png
Binary files differ
diff --git a/pipeworks/textures/pipeworks_mese_tube_inv.png b/pipeworks/textures/pipeworks_mese_tube_inv.png
new file mode 100644
index 0000000..4b15ef9
--- /dev/null
+++ b/pipeworks/textures/pipeworks_mese_tube_inv.png
Binary files differ
diff --git a/pipeworks/textures/pipeworks_mese_tube_noctr_1.png b/pipeworks/textures/pipeworks_mese_tube_noctr_1.png
new file mode 100644
index 0000000..c9661a7
--- /dev/null
+++ b/pipeworks/textures/pipeworks_mese_tube_noctr_1.png
Binary files differ
diff --git a/pipeworks/textures/pipeworks_mese_tube_noctr_2.png b/pipeworks/textures/pipeworks_mese_tube_noctr_2.png
new file mode 100644
index 0000000..ffe53b7
--- /dev/null
+++ b/pipeworks/textures/pipeworks_mese_tube_noctr_2.png
Binary files differ
diff --git a/pipeworks/textures/pipeworks_mese_tube_noctr_3.png b/pipeworks/textures/pipeworks_mese_tube_noctr_3.png
new file mode 100644
index 0000000..b65c0e2
--- /dev/null
+++ b/pipeworks/textures/pipeworks_mese_tube_noctr_3.png
Binary files differ
diff --git a/pipeworks/textures/pipeworks_mese_tube_noctr_4.png b/pipeworks/textures/pipeworks_mese_tube_noctr_4.png
new file mode 100644
index 0000000..278c7e8
--- /dev/null
+++ b/pipeworks/textures/pipeworks_mese_tube_noctr_4.png
Binary files differ
diff --git a/pipeworks/textures/pipeworks_mese_tube_noctr_5.png b/pipeworks/textures/pipeworks_mese_tube_noctr_5.png
new file mode 100644
index 0000000..4b75ae2
--- /dev/null
+++ b/pipeworks/textures/pipeworks_mese_tube_noctr_5.png
Binary files differ
diff --git a/pipeworks/textures/pipeworks_mese_tube_noctr_6.png b/pipeworks/textures/pipeworks_mese_tube_noctr_6.png
new file mode 100644
index 0000000..e2bd483
--- /dev/null
+++ b/pipeworks/textures/pipeworks_mese_tube_noctr_6.png
Binary files differ
diff --git a/pipeworks/textures/pipeworks_mese_tube_plain_1.png b/pipeworks/textures/pipeworks_mese_tube_plain_1.png
new file mode 100644
index 0000000..47ce4ed
--- /dev/null
+++ b/pipeworks/textures/pipeworks_mese_tube_plain_1.png
Binary files differ
diff --git a/pipeworks/textures/pipeworks_mese_tube_plain_2.png b/pipeworks/textures/pipeworks_mese_tube_plain_2.png
new file mode 100644
index 0000000..12d7966
--- /dev/null
+++ b/pipeworks/textures/pipeworks_mese_tube_plain_2.png
Binary files differ
diff --git a/pipeworks/textures/pipeworks_mese_tube_plain_3.png b/pipeworks/textures/pipeworks_mese_tube_plain_3.png
new file mode 100644
index 0000000..4d3d415
--- /dev/null
+++ b/pipeworks/textures/pipeworks_mese_tube_plain_3.png
Binary files differ
diff --git a/pipeworks/textures/pipeworks_mese_tube_plain_4.png b/pipeworks/textures/pipeworks_mese_tube_plain_4.png
new file mode 100644
index 0000000..f4c3370
--- /dev/null
+++ b/pipeworks/textures/pipeworks_mese_tube_plain_4.png
Binary files differ
diff --git a/pipeworks/textures/pipeworks_mese_tube_plain_5.png b/pipeworks/textures/pipeworks_mese_tube_plain_5.png
new file mode 100644
index 0000000..fbe8de0
--- /dev/null
+++ b/pipeworks/textures/pipeworks_mese_tube_plain_5.png
Binary files differ
diff --git a/pipeworks/textures/pipeworks_mese_tube_plain_6.png b/pipeworks/textures/pipeworks_mese_tube_plain_6.png
new file mode 100644
index 0000000..76b49e3
--- /dev/null
+++ b/pipeworks/textures/pipeworks_mese_tube_plain_6.png
Binary files differ
diff --git a/pipeworks/textures/pipeworks_mese_tube_short.png b/pipeworks/textures/pipeworks_mese_tube_short.png
new file mode 100644
index 0000000..fd12ccd
--- /dev/null
+++ b/pipeworks/textures/pipeworks_mese_tube_short.png
Binary files differ
diff --git a/pipeworks/textures/pipeworks_nodebreaker_back.png b/pipeworks/textures/pipeworks_nodebreaker_back.png
new file mode 100644
index 0000000..3006cb7
--- /dev/null
+++ b/pipeworks/textures/pipeworks_nodebreaker_back.png
Binary files differ
diff --git a/pipeworks/textures/pipeworks_nodebreaker_bottom_off.png b/pipeworks/textures/pipeworks_nodebreaker_bottom_off.png
new file mode 100644
index 0000000..c7a48d4
--- /dev/null
+++ b/pipeworks/textures/pipeworks_nodebreaker_bottom_off.png
Binary files differ
diff --git a/pipeworks/textures/pipeworks_nodebreaker_bottom_on.png b/pipeworks/textures/pipeworks_nodebreaker_bottom_on.png
new file mode 100644
index 0000000..e14ca32
--- /dev/null
+++ b/pipeworks/textures/pipeworks_nodebreaker_bottom_on.png
Binary files differ
diff --git a/pipeworks/textures/pipeworks_nodebreaker_front_off.png b/pipeworks/textures/pipeworks_nodebreaker_front_off.png
new file mode 100644
index 0000000..36a5a50
--- /dev/null
+++ b/pipeworks/textures/pipeworks_nodebreaker_front_off.png
Binary files differ
diff --git a/pipeworks/textures/pipeworks_nodebreaker_front_on.png b/pipeworks/textures/pipeworks_nodebreaker_front_on.png
new file mode 100644
index 0000000..bf7fe70
--- /dev/null
+++ b/pipeworks/textures/pipeworks_nodebreaker_front_on.png
Binary files differ
diff --git a/pipeworks/textures/pipeworks_nodebreaker_side1_off.png b/pipeworks/textures/pipeworks_nodebreaker_side1_off.png
new file mode 100644
index 0000000..30769fa
--- /dev/null
+++ b/pipeworks/textures/pipeworks_nodebreaker_side1_off.png
Binary files differ
diff --git a/pipeworks/textures/pipeworks_nodebreaker_side1_on.png b/pipeworks/textures/pipeworks_nodebreaker_side1_on.png
new file mode 100644
index 0000000..ff0a893
--- /dev/null
+++ b/pipeworks/textures/pipeworks_nodebreaker_side1_on.png
Binary files differ
diff --git a/pipeworks/textures/pipeworks_nodebreaker_side2_off.png b/pipeworks/textures/pipeworks_nodebreaker_side2_off.png
new file mode 100644
index 0000000..babb681
--- /dev/null
+++ b/pipeworks/textures/pipeworks_nodebreaker_side2_off.png
Binary files differ
diff --git a/pipeworks/textures/pipeworks_nodebreaker_side2_on.png b/pipeworks/textures/pipeworks_nodebreaker_side2_on.png
new file mode 100644
index 0000000..ed0e12e
--- /dev/null
+++ b/pipeworks/textures/pipeworks_nodebreaker_side2_on.png
Binary files differ
diff --git a/pipeworks/textures/pipeworks_nodebreaker_top_off.png b/pipeworks/textures/pipeworks_nodebreaker_top_off.png
new file mode 100644
index 0000000..fb86b95
--- /dev/null
+++ b/pipeworks/textures/pipeworks_nodebreaker_top_off.png
Binary files differ
diff --git a/pipeworks/textures/pipeworks_nodebreaker_top_on.png b/pipeworks/textures/pipeworks_nodebreaker_top_on.png
new file mode 100644
index 0000000..97da74d
--- /dev/null
+++ b/pipeworks/textures/pipeworks_nodebreaker_top_on.png
Binary files differ
diff --git a/pipeworks/textures/pipeworks_one_way_tube_input.png b/pipeworks/textures/pipeworks_one_way_tube_input.png
new file mode 100644
index 0000000..8490858
--- /dev/null
+++ b/pipeworks/textures/pipeworks_one_way_tube_input.png
Binary files differ
diff --git a/pipeworks/textures/pipeworks_one_way_tube_output.png b/pipeworks/textures/pipeworks_one_way_tube_output.png
new file mode 100644
index 0000000..8490858
--- /dev/null
+++ b/pipeworks/textures/pipeworks_one_way_tube_output.png
Binary files differ
diff --git a/pipeworks/textures/pipeworks_one_way_tube_side.png b/pipeworks/textures/pipeworks_one_way_tube_side.png
new file mode 100644
index 0000000..9881be2
--- /dev/null
+++ b/pipeworks/textures/pipeworks_one_way_tube_side.png
Binary files differ
diff --git a/pipeworks/textures/pipeworks_one_way_tube_top.png b/pipeworks/textures/pipeworks_one_way_tube_top.png
new file mode 100644
index 0000000..5ade427
--- /dev/null
+++ b/pipeworks/textures/pipeworks_one_way_tube_top.png
Binary files differ
diff --git a/pipeworks/textures/pipeworks_pane_embedded_tube_ends.png b/pipeworks/textures/pipeworks_pane_embedded_tube_ends.png
new file mode 100644
index 0000000..8c424a8
--- /dev/null
+++ b/pipeworks/textures/pipeworks_pane_embedded_tube_ends.png
Binary files differ
diff --git a/pipeworks/textures/pipeworks_pane_embedded_tube_sides.png b/pipeworks/textures/pipeworks_pane_embedded_tube_sides.png
new file mode 100644
index 0000000..befe525
--- /dev/null
+++ b/pipeworks/textures/pipeworks_pane_embedded_tube_sides.png
Binary files differ
diff --git a/pipeworks/textures/pipeworks_pipe_3_empty.png b/pipeworks/textures/pipeworks_pipe_3_empty.png
new file mode 100644
index 0000000..d13ec77
--- /dev/null
+++ b/pipeworks/textures/pipeworks_pipe_3_empty.png
Binary files differ
diff --git a/pipeworks/textures/pipeworks_pipe_3_loaded.png b/pipeworks/textures/pipeworks_pipe_3_loaded.png
new file mode 100644
index 0000000..c086e19
--- /dev/null
+++ b/pipeworks/textures/pipeworks_pipe_3_loaded.png
Binary files differ
diff --git a/pipeworks/textures/pipeworks_pipe_inv.png b/pipeworks/textures/pipeworks_pipe_inv.png
new file mode 100644
index 0000000..0a17d0c
--- /dev/null
+++ b/pipeworks/textures/pipeworks_pipe_inv.png
Binary files differ
diff --git a/pipeworks/textures/pipeworks_pipe_plain.png b/pipeworks/textures/pipeworks_pipe_plain.png
new file mode 100644
index 0000000..7cbc11b
--- /dev/null
+++ b/pipeworks/textures/pipeworks_pipe_plain.png
Binary files differ
diff --git a/pipeworks/textures/pipeworks_plastic_sheeting.png b/pipeworks/textures/pipeworks_plastic_sheeting.png
new file mode 100644
index 0000000..3834df7
--- /dev/null
+++ b/pipeworks/textures/pipeworks_plastic_sheeting.png
Binary files differ
diff --git a/pipeworks/textures/pipeworks_pump_off.png b/pipeworks/textures/pipeworks_pump_off.png
new file mode 100644
index 0000000..28d2311
--- /dev/null
+++ b/pipeworks/textures/pipeworks_pump_off.png
Binary files differ
diff --git a/pipeworks/textures/pipeworks_pump_on.png b/pipeworks/textures/pipeworks_pump_on.png
new file mode 100644
index 0000000..50a8bbf
--- /dev/null
+++ b/pipeworks/textures/pipeworks_pump_on.png
Binary files differ
diff --git a/pipeworks/textures/pipeworks_red.png b/pipeworks/textures/pipeworks_red.png
new file mode 100644
index 0000000..33812bd
--- /dev/null
+++ b/pipeworks/textures/pipeworks_red.png
Binary files differ
diff --git a/pipeworks/textures/pipeworks_sand_tube_end.png b/pipeworks/textures/pipeworks_sand_tube_end.png
new file mode 100644
index 0000000..8cccaf4
--- /dev/null
+++ b/pipeworks/textures/pipeworks_sand_tube_end.png
Binary files differ
diff --git a/pipeworks/textures/pipeworks_sand_tube_inv.png b/pipeworks/textures/pipeworks_sand_tube_inv.png
new file mode 100644
index 0000000..3afb05d
--- /dev/null
+++ b/pipeworks/textures/pipeworks_sand_tube_inv.png
Binary files differ
diff --git a/pipeworks/textures/pipeworks_sand_tube_noctr.png b/pipeworks/textures/pipeworks_sand_tube_noctr.png
new file mode 100644
index 0000000..a9c6d2d
--- /dev/null
+++ b/pipeworks/textures/pipeworks_sand_tube_noctr.png
Binary files differ
diff --git a/pipeworks/textures/pipeworks_sand_tube_plain.png b/pipeworks/textures/pipeworks_sand_tube_plain.png
new file mode 100644
index 0000000..d665081
--- /dev/null
+++ b/pipeworks/textures/pipeworks_sand_tube_plain.png
Binary files differ
diff --git a/pipeworks/textures/pipeworks_sand_tube_short.png b/pipeworks/textures/pipeworks_sand_tube_short.png
new file mode 100644
index 0000000..8dcf2b4
--- /dev/null
+++ b/pipeworks/textures/pipeworks_sand_tube_short.png
Binary files differ
diff --git a/pipeworks/textures/pipeworks_spigot.png b/pipeworks/textures/pipeworks_spigot.png
new file mode 100644
index 0000000..a79dbf8
--- /dev/null
+++ b/pipeworks/textures/pipeworks_spigot.png
Binary files differ
diff --git a/pipeworks/textures/pipeworks_storage_tank_back.png b/pipeworks/textures/pipeworks_storage_tank_back.png
new file mode 100644
index 0000000..3b6a16b
--- /dev/null
+++ b/pipeworks/textures/pipeworks_storage_tank_back.png
Binary files differ
diff --git a/pipeworks/textures/pipeworks_storage_tank_fittings.png b/pipeworks/textures/pipeworks_storage_tank_fittings.png
new file mode 100644
index 0000000..f3b8b24
--- /dev/null
+++ b/pipeworks/textures/pipeworks_storage_tank_fittings.png
Binary files differ
diff --git a/pipeworks/textures/pipeworks_storage_tank_front_0.png b/pipeworks/textures/pipeworks_storage_tank_front_0.png
new file mode 100644
index 0000000..72c6f6b
--- /dev/null
+++ b/pipeworks/textures/pipeworks_storage_tank_front_0.png
Binary files differ
diff --git a/pipeworks/textures/pipeworks_storage_tank_front_1.png b/pipeworks/textures/pipeworks_storage_tank_front_1.png
new file mode 100644
index 0000000..889893b
--- /dev/null
+++ b/pipeworks/textures/pipeworks_storage_tank_front_1.png
Binary files differ
diff --git a/pipeworks/textures/pipeworks_storage_tank_front_10.png b/pipeworks/textures/pipeworks_storage_tank_front_10.png
new file mode 100644
index 0000000..f48a738
--- /dev/null
+++ b/pipeworks/textures/pipeworks_storage_tank_front_10.png
Binary files differ
diff --git a/pipeworks/textures/pipeworks_storage_tank_front_2.png b/pipeworks/textures/pipeworks_storage_tank_front_2.png
new file mode 100644
index 0000000..a36bc24
--- /dev/null
+++ b/pipeworks/textures/pipeworks_storage_tank_front_2.png
Binary files differ
diff --git a/pipeworks/textures/pipeworks_storage_tank_front_3.png b/pipeworks/textures/pipeworks_storage_tank_front_3.png
new file mode 100644
index 0000000..4575e37
--- /dev/null
+++ b/pipeworks/textures/pipeworks_storage_tank_front_3.png
Binary files differ
diff --git a/pipeworks/textures/pipeworks_storage_tank_front_4.png b/pipeworks/textures/pipeworks_storage_tank_front_4.png
new file mode 100644
index 0000000..47d9669
--- /dev/null
+++ b/pipeworks/textures/pipeworks_storage_tank_front_4.png
Binary files differ
diff --git a/pipeworks/textures/pipeworks_storage_tank_front_5.png b/pipeworks/textures/pipeworks_storage_tank_front_5.png
new file mode 100644
index 0000000..17eaf69
--- /dev/null
+++ b/pipeworks/textures/pipeworks_storage_tank_front_5.png
Binary files differ
diff --git a/pipeworks/textures/pipeworks_storage_tank_front_6.png b/pipeworks/textures/pipeworks_storage_tank_front_6.png
new file mode 100644
index 0000000..77619e3
--- /dev/null
+++ b/pipeworks/textures/pipeworks_storage_tank_front_6.png
Binary files differ
diff --git a/pipeworks/textures/pipeworks_storage_tank_front_7.png b/pipeworks/textures/pipeworks_storage_tank_front_7.png
new file mode 100644
index 0000000..ffebf9b
--- /dev/null
+++ b/pipeworks/textures/pipeworks_storage_tank_front_7.png
Binary files differ
diff --git a/pipeworks/textures/pipeworks_storage_tank_front_8.png b/pipeworks/textures/pipeworks_storage_tank_front_8.png
new file mode 100644
index 0000000..4974a82
--- /dev/null
+++ b/pipeworks/textures/pipeworks_storage_tank_front_8.png
Binary files differ
diff --git a/pipeworks/textures/pipeworks_storage_tank_front_9.png b/pipeworks/textures/pipeworks_storage_tank_front_9.png
new file mode 100644
index 0000000..87b6d79
--- /dev/null
+++ b/pipeworks/textures/pipeworks_storage_tank_front_9.png
Binary files differ
diff --git a/pipeworks/textures/pipeworks_teleport_tube_end.png b/pipeworks/textures/pipeworks_teleport_tube_end.png
new file mode 100644
index 0000000..7a27150
--- /dev/null
+++ b/pipeworks/textures/pipeworks_teleport_tube_end.png
Binary files differ
diff --git a/pipeworks/textures/pipeworks_teleport_tube_inv.png b/pipeworks/textures/pipeworks_teleport_tube_inv.png
new file mode 100644
index 0000000..d12b896
--- /dev/null
+++ b/pipeworks/textures/pipeworks_teleport_tube_inv.png
Binary files differ
diff --git a/pipeworks/textures/pipeworks_teleport_tube_noctr.png b/pipeworks/textures/pipeworks_teleport_tube_noctr.png
new file mode 100644
index 0000000..ac7364d
--- /dev/null
+++ b/pipeworks/textures/pipeworks_teleport_tube_noctr.png
Binary files differ
diff --git a/pipeworks/textures/pipeworks_teleport_tube_plain.png b/pipeworks/textures/pipeworks_teleport_tube_plain.png
new file mode 100644
index 0000000..0a859f2
--- /dev/null
+++ b/pipeworks/textures/pipeworks_teleport_tube_plain.png
Binary files differ
diff --git a/pipeworks/textures/pipeworks_teleport_tube_short.png b/pipeworks/textures/pipeworks_teleport_tube_short.png
new file mode 100644
index 0000000..f82d082
--- /dev/null
+++ b/pipeworks/textures/pipeworks_teleport_tube_short.png
Binary files differ
diff --git a/pipeworks/textures/pipeworks_testobject.png b/pipeworks/textures/pipeworks_testobject.png
new file mode 100644
index 0000000..d54c024
--- /dev/null
+++ b/pipeworks/textures/pipeworks_testobject.png
Binary files differ
diff --git a/pipeworks/textures/pipeworks_trashcan_bottom.png b/pipeworks/textures/pipeworks_trashcan_bottom.png
new file mode 100644
index 0000000..91fd944
--- /dev/null
+++ b/pipeworks/textures/pipeworks_trashcan_bottom.png
Binary files differ
diff --git a/pipeworks/textures/pipeworks_trashcan_side.png b/pipeworks/textures/pipeworks_trashcan_side.png
new file mode 100644
index 0000000..cf0a3bf
--- /dev/null
+++ b/pipeworks/textures/pipeworks_trashcan_side.png
Binary files differ
diff --git a/pipeworks/textures/pipeworks_tube_connection_metallic.png b/pipeworks/textures/pipeworks_tube_connection_metallic.png
new file mode 100644
index 0000000..10becfe
--- /dev/null
+++ b/pipeworks/textures/pipeworks_tube_connection_metallic.png
Binary files differ
diff --git a/pipeworks/textures/pipeworks_tube_connection_stony.png b/pipeworks/textures/pipeworks_tube_connection_stony.png
new file mode 100644
index 0000000..6ed02a4
--- /dev/null
+++ b/pipeworks/textures/pipeworks_tube_connection_stony.png
Binary files differ
diff --git a/pipeworks/textures/pipeworks_tube_connection_wooden.png b/pipeworks/textures/pipeworks_tube_connection_wooden.png
new file mode 100644
index 0000000..ff199ca
--- /dev/null
+++ b/pipeworks/textures/pipeworks_tube_connection_wooden.png
Binary files differ
diff --git a/pipeworks/textures/pipeworks_tube_end.png b/pipeworks/textures/pipeworks_tube_end.png
new file mode 100644
index 0000000..e9d01ba
--- /dev/null
+++ b/pipeworks/textures/pipeworks_tube_end.png
Binary files differ
diff --git a/pipeworks/textures/pipeworks_tube_inv.png b/pipeworks/textures/pipeworks_tube_inv.png
new file mode 100644
index 0000000..51c728d
--- /dev/null
+++ b/pipeworks/textures/pipeworks_tube_inv.png
Binary files differ
diff --git a/pipeworks/textures/pipeworks_tube_noctr.png b/pipeworks/textures/pipeworks_tube_noctr.png
new file mode 100644
index 0000000..6f07886
--- /dev/null
+++ b/pipeworks/textures/pipeworks_tube_noctr.png
Binary files differ
diff --git a/pipeworks/textures/pipeworks_tube_plain.png b/pipeworks/textures/pipeworks_tube_plain.png
new file mode 100644
index 0000000..9d6442b
--- /dev/null
+++ b/pipeworks/textures/pipeworks_tube_plain.png
Binary files differ
diff --git a/pipeworks/textures/pipeworks_tube_short.png b/pipeworks/textures/pipeworks_tube_short.png
new file mode 100644
index 0000000..6729c53
--- /dev/null
+++ b/pipeworks/textures/pipeworks_tube_short.png
Binary files differ
diff --git a/pipeworks/textures/pipeworks_tube_transparent.png b/pipeworks/textures/pipeworks_tube_transparent.png
new file mode 100644
index 0000000..aa4418d
--- /dev/null
+++ b/pipeworks/textures/pipeworks_tube_transparent.png
Binary files differ
diff --git a/pipeworks/textures/pipeworks_valve.png b/pipeworks/textures/pipeworks_valve.png
new file mode 100644
index 0000000..60ef960
--- /dev/null
+++ b/pipeworks/textures/pipeworks_valve.png
Binary files differ
diff --git a/pipeworks/textures/pipeworks_white.png b/pipeworks/textures/pipeworks_white.png
new file mode 100644
index 0000000..faf0ec1
--- /dev/null
+++ b/pipeworks/textures/pipeworks_white.png
Binary files differ
diff --git a/pipeworks/textures/pipeworks_yellow.png b/pipeworks/textures/pipeworks_yellow.png
new file mode 100644
index 0000000..ce1af41
--- /dev/null
+++ b/pipeworks/textures/pipeworks_yellow.png
Binary files differ
diff --git a/pipeworks/trashcan.lua b/pipeworks/trashcan.lua
new file mode 100644
index 0000000..87980ab
--- /dev/null
+++ b/pipeworks/trashcan.lua
@@ -0,0 +1,49 @@
+minetest.register_node("pipeworks:trashcan", {
+ description = "Trash Can",
+ drawtype = "normal",
+ tiles = {
+ "pipeworks_trashcan_bottom.png",
+ "pipeworks_trashcan_bottom.png",
+ "pipeworks_trashcan_side.png",
+ "pipeworks_trashcan_side.png",
+ "pipeworks_trashcan_side.png",
+ "pipeworks_trashcan_side.png",
+ },
+ groups = {snappy = 3, tubedevice = 1, tubedevice_receiver = 1},
+ tube = {
+ insert_object = function(pos, node, stack, direction)
+ return ItemStack("")
+ end,
+ connect_sides = {left = 1, right = 1, front = 1, back = 1, top = 1, bottom = 1},
+ priority = 1, -- Lower than anything else
+ },
+ on_construct = function(pos)
+ local meta = minetest.get_meta(pos)
+ meta:set_string("formspec",
+ "size[8,7]"..
+ "item_image[0,0;1,1;pipeworks:trashcan]"..
+ "label[1,0;Trash Can]"..
+ "list[context;trash;3.5,1;1,1;]"..
+ default.gui_bg..
+ default.gui_bg_img..
+ default.gui_slots..
+ default.get_hotbar_bg(0,3) ..
+ "list[current_player;main;0,3;8,4;]")
+ meta:set_string("infotext", "Trash Can")
+ meta:get_inventory():set_size("trash", 1)
+ end,
+ after_place_node = pipeworks.after_place,
+ after_dig_node = pipeworks.after_dig,
+ on_metadata_inventory_put = function(pos, listname, index, stack, player)
+ minetest.get_meta(pos):get_inventory():set_stack(listname, index, ItemStack(""))
+ end,
+})
+
+minetest.register_craft({
+ output = "pipeworks:trashcan",
+ recipe = {
+ { "homedecor:plastic_sheeting", "homedecor:plastic_sheeting", "homedecor:plastic_sheeting" },
+ { "default:steel_ingot", "", "default:steel_ingot" },
+ { "default:steel_ingot", "default:steel_ingot", "default:steel_ingot" },
+ },
+})
diff --git a/pipeworks/tube_registration.lua b/pipeworks/tube_registration.lua
new file mode 100644
index 0000000..c926216
--- /dev/null
+++ b/pipeworks/tube_registration.lua
@@ -0,0 +1,240 @@
+-- This file supplies the various kinds of pneumatic tubes
+
+local tubenodes = {}
+pipeworks.tubenodes = tubenodes
+
+minetest.register_alias("pipeworks:tube", "pipeworks:tube_000000")
+
+-- now, a function to define the tubes
+
+local REGISTER_COMPATIBILITY = true
+
+local vti = {4, 3, 2, 1, 6, 5}
+
+local default_noctrs = { "pipeworks_tube_noctr.png" }
+local default_plain = { "pipeworks_tube_plain.png" }
+local default_ends = { "pipeworks_tube_end.png" }
+
+local texture_mt = {
+ __index = function(table, key)
+ local size, idx = #table, tonumber(key)
+ if size > 0 then -- avoid endless loops with empty tables
+ while idx > size do idx = idx - size end
+ return table[idx]
+ end
+ end
+}
+
+local register_one_tube = function(name, tname, dropname, desc, plain, noctrs, ends, short, inv, special, connects, style)
+ noctrs = noctrs or default_noctrs
+ setmetatable(noctrs, texture_mt)
+ plain = plain or default_plain
+ setmetatable(plain, texture_mt)
+ ends = ends or default_ends
+ setmetatable(ends, texture_mt)
+ short = short or "pipeworks_tube_short.png"
+ inv = inv or "pipeworks_tube_inv.png"
+
+ local outboxes = {}
+ local outsel = {}
+ local outimgs = {}
+
+ for i = 1, 6 do
+ outimgs[vti[i]] = plain[i]
+ end
+
+ for _, v in ipairs(connects) do
+ table.extend(outboxes, pipeworks.tube_boxes[v])
+ table.insert(outsel, pipeworks.tube_selectboxes[v])
+ outimgs[vti[v]] = noctrs[v]
+ end
+
+ if #connects == 1 then
+ local v = connects[1]
+ v = v-1 + 2*(v%2) -- Opposite side
+ outimgs[vti[v]] = ends[v]
+ end
+
+ local tgroups = {snappy = 3, tube = 1, tubedevice = 1, not_in_creative_inventory = 1}
+ local tubedesc = string.format("%s %s... You hacker, you.", desc, dump(connects))
+ local iimg = plain[1]
+ local wscale = {x = 1, y = 1, z = 1}
+
+ if #connects == 0 then
+ tgroups = {snappy = 3, tube = 1, tubedevice = 1}
+ tubedesc = desc
+ iimg=inv
+ outimgs = {
+ short, short,
+ ends[3],ends[4],
+ short, short
+ }
+ outboxes = { -24/64, -9/64, -9/64, 24/64, 9/64, 9/64 }
+ outsel = { -24/64, -10/64, -10/64, 24/64, 10/64, 10/64 }
+ wscale = {x = 1, y = 1, z = 0.01}
+ end
+
+ local rname = string.format("%s_%s", name, tname)
+ table.insert(tubenodes, rname)
+
+ local nodedef = {
+ description = tubedesc,
+ drawtype = "nodebox",
+ tiles = outimgs,
+ sunlight_propagates = true,
+ inventory_image = iimg,
+ wield_image = iimg,
+ wield_scale = wscale,
+ paramtype = "light",
+ selection_box = {
+ type = "fixed",
+ fixed = outsel
+ },
+ node_box = {
+ type = "fixed",
+ fixed = outboxes
+ },
+ groups = tgroups,
+ sounds = default.node_sound_wood_defaults(),
+ walkable = true,
+ stack_max = 99,
+ basename = name,
+ style = style,
+ drop = string.format("%s_%s", name, dropname),
+ tubelike = 1,
+ tube = {
+ connect_sides = {front = 1, back = 1, left = 1, right = 1, top = 1, bottom = 1},
+ priority = 50
+ },
+ after_place_node = pipeworks.after_place,
+ after_dig_node = pipeworks.after_dig
+ }
+ if style == "6d" then
+ nodedef.paramtype2 = "facedir"
+ end
+
+ if special == nil then special = {} end
+
+ for key, value in pairs(special) do
+ --if key == "after_dig_node" or key == "after_place_node" then
+ -- nodedef[key.."_"] = value
+ if key == "groups" then
+ for group, val in pairs(value) do
+ nodedef.groups[group] = val
+ end
+ elseif key == "tube" then
+ for key, val in pairs(value) do
+ nodedef.tube[key] = val
+ end
+ else
+ nodedef[key] = table.recursive_replace(value, "#id", tname)
+ end
+ end
+
+ minetest.register_node(rname, nodedef)
+end
+
+local register_all_tubes = function(name, desc, plain, noctrs, ends, short, inv, special, old_registration)
+ if old_registration then
+ for xm = 0, 1 do
+ for xp = 0, 1 do
+ for ym = 0, 1 do
+ for yp = 0, 1 do
+ for zm = 0, 1 do
+ for zp = 0, 1 do
+ local connects = {}
+ if xm == 1 then
+ connects[#connects+1] = 1
+ end
+ if xp == 1 then
+ connects[#connects+1] = 2
+ end
+ if ym == 1 then
+ connects[#connects+1] = 3
+ end
+ if yp == 1 then
+ connects[#connects+1] = 4
+ end
+ if zm == 1 then
+ connects[#connects+1] = 5
+ end
+ if zp == 1 then
+ connects[#connects+1] = 6
+ end
+ local tname = xm..xp..ym..yp..zm..zp
+ register_one_tube(name, tname, "000000", desc, plain, noctrs, ends, short, inv, special, connects, "old")
+ end
+ end
+ end
+ end
+ end
+ end
+ else
+ -- 6d tubes: uses only 10 nodes instead of 64, but the textures must be rotated
+ local cconnects = {{}, {1}, {1, 2}, {1, 3}, {1, 3, 5}, {1, 2, 3}, {1, 2, 3, 5}, {1, 2, 3, 4}, {1, 2, 3, 4, 5}, {1, 2, 3, 4, 5, 6}}
+ for index, connects in ipairs(cconnects) do
+ register_one_tube(name, tostring(index), "1", desc, plain, noctrs, ends, short, inv, special, connects, "6d")
+ end
+ if REGISTER_COMPATIBILITY then
+ local cname = name.."_compatibility"
+ minetest.register_node(cname, {
+ drawtype = "airlike",
+ style = "6d",
+ basename = name,
+ inventory_image = inv,
+ wield_image = inv,
+ paramtype = "light",
+ sunlight_propagates = true,
+ description = "Pneumatic tube segment (legacy)",
+ after_place_node = pipeworks.after_place,
+ groups = {not_in_creative_inventory = 1, tube_to_update = 1, tube = 1},
+ tube = {connect_sides = {front = 1, back = 1, left = 1, right = 1, top = 1, bottom = 1}},
+ drop = name.."_1",
+ })
+ table.insert(tubenodes, cname)
+ for xm = 0, 1 do
+ for xp = 0, 1 do
+ for ym = 0, 1 do
+ for yp = 0, 1 do
+ for zm = 0, 1 do
+ for zp = 0, 1 do
+ local tname = xm..xp..ym..yp..zm..zp
+ minetest.register_alias(name.."_"..tname, cname)
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+end
+
+pipeworks.register_tube = function(name, def, ...)
+ if type(def) == "table" then
+ register_all_tubes(name, def.description,
+ def.plain, def.noctr, def.ends, def.short,
+ def.inventory_image, def.node_def, def.no_facedir)
+ else
+ -- we assert to be the old function with the second parameter being the description
+ -- function(name, desc, plain, noctrs, ends, short, inv, special, old_registration)
+ assert(type(def) == "string", "invalid arguments to pipeworks.register_tube")
+ register_all_tubes(name, def, ...)
+ end
+end
+
+
+if REGISTER_COMPATIBILITY then
+ minetest.register_abm({
+ nodenames = {"group:tube_to_update"},
+ interval = 1,
+ chance = 1,
+ action = function(pos, node, active_object_count, active_object_count_wider)
+ local minp = vector.subtract(pos, 1)
+ local maxp = vector.add(pos, 1)
+ if table.getn(minetest.find_nodes_in_area(minp, maxp, "ignore")) == 0 then
+ pipeworks.scan_for_tube_objects(pos)
+ end
+ end
+ })
+end
diff --git a/pipeworks/vacuum_tubes.lua b/pipeworks/vacuum_tubes.lua
new file mode 100644
index 0000000..51f6f81
--- /dev/null
+++ b/pipeworks/vacuum_tubes.lua
@@ -0,0 +1,122 @@
+if pipeworks.enable_sand_tube then
+ pipeworks.register_tube("pipeworks:sand_tube", {
+ description = "Vacuuming Pneumatic Tube Segment",
+ inventory_image = "pipeworks_sand_tube_inv.png",
+ short = "pipeworks_sand_tube_short.png",
+ noctr = { "pipeworks_sand_tube_noctr.png" },
+ plain = { "pipeworks_sand_tube_plain.png" },
+ ends = { "pipeworks_sand_tube_end.png" },
+ node_def = { groups = {vacuum_tube = 1}},
+ })
+
+ minetest.register_craft( {
+ output = "pipeworks:sand_tube_1 2",
+ recipe = {
+ { "homedecor:plastic_sheeting", "homedecor:plastic_sheeting", "homedecor:plastic_sheeting" },
+ { "group:sand", "group:sand", "group:sand" },
+ { "homedecor:plastic_sheeting", "homedecor:plastic_sheeting", "homedecor:plastic_sheeting" }
+ },
+ })
+
+ minetest.register_craft( {
+ output = "pipeworks:sand_tube_1",
+ recipe = {
+ { "group:sand", "pipeworks:tube_1", "group:sand" },
+ },
+ })
+end
+
+if pipeworks.enable_mese_sand_tube then
+ pipeworks.register_tube("pipeworks:mese_sand_tube", {
+ description = "Adjustable Vacuuming Pneumatic Tube Segment",
+ inventory_image = "pipeworks_mese_sand_tube_inv.png",
+ short = "pipeworks_mese_sand_tube_short.png",
+ noctr = { "pipeworks_mese_sand_tube_noctr.png" },
+ plain = { "pipeworks_mese_sand_tube_plain.png" },
+ ends = { "pipeworks_mese_sand_tube_end.png" },
+ node_def = {
+ groups = {vacuum_tube = 1},
+ on_construct = function(pos)
+ local meta = minetest.get_meta(pos)
+ meta:set_int("dist", 0)
+ meta:set_string("formspec", "size[2.1,0.8]"..
+ "image[0,0;1,1;pipeworks_mese_sand_tube_inv.png]"..
+ "field[1.3,0.4;1,1;dist;radius;${dist}]"..
+ default.gui_bg..
+ default.gui_bg_img)
+ meta:set_string("infotext", "Adjustable Vacuuming Pneumatic Tube Segment")
+ end,
+ on_receive_fields = function(pos,formname,fields,sender)
+ if not pipeworks.may_configure(pos, sender) then return end
+ local meta = minetest.get_meta(pos)
+ local dist = tonumber(fields.dist)
+ if dist then
+ dist = math.max(0, dist)
+ dist = math.min(8, dist)
+ meta:set_int("dist", dist)
+ meta:set_string("infotext", ("Adjustable Vacuuming Pneumatic Tube Segment (%dm)"):format(dist))
+ end
+ end,
+ },
+ })
+
+ minetest.register_craft( {
+ output = "pipeworks:mese_sand_tube_1 2",
+ recipe = {
+ { "homedecor:plastic_sheeting", "homedecor:plastic_sheeting", "homedecor:plastic_sheeting" },
+ { "group:sand", "default:mese_crystal", "group:sand" },
+ { "homedecor:plastic_sheeting", "homedecor:plastic_sheeting", "homedecor:plastic_sheeting" }
+ },
+ })
+
+ minetest.register_craft( {
+ type = "shapeless",
+ output = "pipeworks:mese_sand_tube_1",
+ recipe = {
+ "pipeworks:sand_tube_1",
+ "default:mese_crystal_fragment",
+ "default:mese_crystal_fragment",
+ "default:mese_crystal_fragment",
+ "default:mese_crystal_fragment"
+ },
+ })
+end
+
+local sqrt_3 = math.sqrt(3)
+local tube_inject_item = pipeworks.tube_inject_item
+local get_objects_inside_radius = minetest.get_objects_inside_radius
+local function vacuum(pos, radius)
+ radius = radius + 0.5
+ for _, object in pairs(get_objects_inside_radius(pos, sqrt_3 * radius)) do
+ local lua_entity = object:get_luaentity()
+ if not object:is_player() and lua_entity and lua_entity.name == "__builtin:item" then
+ local obj_pos = object:getpos()
+ local x1, y1, z1 = pos.x, pos.y, pos.z
+ local x2, y2, z2 = obj_pos.x, obj_pos.y, obj_pos.z
+
+ if x1 - radius <= x2 and x2 <= x1 + radius
+ and y1 - radius <= y2 and y2 <= y1 + radius
+ and z1 - radius <= z2 and z2 <= z1 + radius then
+ if lua_entity.itemstring ~= "" then
+ tube_inject_item(pos, pos, vector.new(0, 0, 0), lua_entity.itemstring)
+ lua_entity.itemstring = ""
+ end
+ object:remove()
+ end
+ end
+ end
+end
+
+minetest.register_abm({nodenames = {"group:vacuum_tube"},
+ interval = 1,
+ chance = 1,
+ label = "Vacuum tubes",
+ action = function(pos, node, active_object_count, active_object_count_wider)
+ if node.name:find("pipeworks:sand_tube") then
+ vacuum(pos, 2)
+ else
+ local radius = minetest.get_meta(pos):get_int("dist")
+ vacuum(pos, radius)
+ end
+ end
+})
diff --git a/pipeworks/wielder.lua b/pipeworks/wielder.lua
new file mode 100644
index 0000000..3cb1649
--- /dev/null
+++ b/pipeworks/wielder.lua
@@ -0,0 +1,456 @@
+local assumed_eye_pos = vector.new(0, 1.5, 0)
+
+local function vector_copy(v)
+ return { x = v.x, y = v.y, z = v.z }
+end
+
+local function delay(x)
+ return (function() return x end)
+end
+
+local function set_wielder_formspec(data, meta)
+ meta:set_string("formspec",
+ "invsize[8,"..(6+data.wield_inv_height)..";]"..
+ "item_image[0,0;1,1;"..data.name_base.."_off]"..
+ "label[1,0;"..minetest.formspec_escape(data.description).."]"..
+ "list[current_name;"..minetest.formspec_escape(data.wield_inv_name)..";"..((8-data.wield_inv_width)*0.5)..",1;"..data.wield_inv_width..","..data.wield_inv_height..";]"..
+ "list[current_player;main;0,"..(2+data.wield_inv_height)..";8,4;]")
+ meta:set_string("infotext", data.description)
+end
+
+local function wielder_on(data, wielder_pos, wielder_node)
+ data.fixup_node(wielder_pos, wielder_node)
+ if wielder_node.name ~= data.name_base.."_off" then return end
+ wielder_node.name = data.name_base.."_on"
+ minetest.swap_node(wielder_pos, wielder_node)
+ nodeupdate(wielder_pos)
+ local wielder_meta = minetest.get_meta(wielder_pos)
+ local inv = wielder_meta:get_inventory()
+ local wield_inv_name = data.wield_inv_name
+ local wieldindex, wieldstack
+ for i, stack in ipairs(inv:get_list(wield_inv_name)) do
+ if not stack:is_empty() then
+ wieldindex = i
+ wieldstack = stack
+ break
+ end
+ end
+ if not wieldindex then
+ if not data.ghost_inv_name then return end
+ wield_inv_name = data.ghost_inv_name
+ inv:set_stack(wield_inv_name, 1, ItemStack(data.ghost_tool))
+ wieldindex = 1
+ wieldstack = inv:get_stack(wield_inv_name, 1)
+ end
+ local dir = minetest.facedir_to_dir(wielder_node.param2)
+ -- under/above is currently intentionally left switched
+ -- even though this causes some problems with deployers and e.g. seeds
+ -- as there are some issues related to nodebreakers otherwise breaking 2 nodes afar.
+ -- solidity would have to be checked as well,
+ -- but would open a whole can of worms related to difference in nodebreaker/deployer behavior
+ -- and the problems of wielders acting on themselves if below is solid
+ local under_pos = vector.subtract(wielder_pos, dir)
+ local above_pos = vector.subtract(under_pos, dir)
+ local pitch
+ local yaw
+ if dir.z < 0 then
+ yaw = 0
+ pitch = 0
+ elseif dir.z > 0 then
+ yaw = math.pi
+ pitch = 0
+ elseif dir.x < 0 then
+ yaw = 3*math.pi/2
+ pitch = 0
+ elseif dir.x > 0 then
+ yaw = math.pi/2
+ pitch = 0
+ elseif dir.y > 0 then
+ yaw = 0
+ pitch = -math.pi/2
+ else
+ yaw = 0
+ pitch = math.pi/2
+ end
+ local virtplayer = {
+ get_inventory_formspec = delay(wielder_meta:get_string("formspec")),
+ get_look_dir = delay(vector.multiply(dir, -1)),
+ get_look_pitch = delay(pitch),
+ get_look_yaw = delay(yaw),
+ get_player_control = delay({ jump=false, right=false, left=false, LMB=false, RMB=false, sneak=data.sneak, aux1=false, down=false, up=false }),
+ get_player_control_bits = delay(data.sneak and 64 or 0),
+ get_player_name = delay(data.masquerade_as_owner and wielder_meta:get_string("owner") or ":pipeworks:"..minetest.pos_to_string(wielder_pos)),
+ is_player = delay(true),
+ is_fake_player = true,
+ set_inventory_formspec = delay(),
+ getpos = delay(vector.subtract(wielder_pos, assumed_eye_pos)),
+ get_hp = delay(20),
+ get_inventory = delay(inv),
+ get_wielded_item = delay(wieldstack),
+ get_wield_index = delay(wieldindex),
+ get_wield_list = delay(wield_inv_name),
+ moveto = delay(),
+ punch = delay(),
+ remove = delay(),
+ right_click = delay(),
+ setpos = delay(),
+ set_hp = delay(),
+ set_properties = delay(),
+ set_wielded_item = function(self, item)
+ wieldstack = item
+ inv:set_stack(wield_inv_name, wieldindex, item)
+ end,
+ set_animation = delay(),
+ set_attach = delay(),
+ set_detach = delay(),
+ set_bone_position = delay(),
+ hud_change = delay(),
+ get_breath = delay(11),
+ -- TODO "implement" all these
+ -- set_armor_groups
+ -- get_armor_groups
+ -- get_animation
+ -- get_attach
+ -- get_bone_position
+ -- get_properties
+ -- get_player_velocity
+ -- set_look_pitch
+ -- set_look_yaw
+ -- set_breath
+ -- set_physics_override
+ -- get_physics_override
+ -- hud_add
+ -- hud_remove
+ -- hud_get
+ -- hud_set_flags
+ -- hud_get_flags
+ -- hud_set_hotbar_itemcount
+ -- hud_get_hotbar_itemcount
+ -- hud_set_hotbar_image
+ -- hud_get_hotbar_image
+ -- hud_set_hotbar_selected_image
+ -- hud_get_hotbar_selected_image
+ -- hud_replace_builtin
+ -- set_sky
+ -- get_sky
+ -- override_day_night_ratio
+ -- get_day_night_ratio
+ -- set_local_animation
+ }
+ local pointed_thing = { type="node", under=under_pos, above=above_pos }
+ data.act(virtplayer, pointed_thing)
+ if data.eject_drops then
+ for i, stack in ipairs(inv:get_list("main")) do
+ if not stack:is_empty() then
+ pipeworks.tube_inject_item(wielder_pos, wielder_pos, dir, stack)
+ inv:set_stack("main", i, ItemStack(""))
+ end
+ end
+ end
+end
+
+local function wielder_off(data, pos, node)
+ if node.name == data.name_base.."_on" then
+ node.name = data.name_base.."_off"
+ minetest.swap_node(pos, node)
+ nodeupdate(pos)
+ end
+end
+
+local function register_wielder(data)
+ data.fixup_node = data.fixup_node or function (pos, node) end
+ data.fixup_oldmetadata = data.fixup_oldmetadata or function (m) return m end
+ for _, state in ipairs({ "off", "on" }) do
+ local groups = { snappy=2, choppy=2, oddly_breakable_by_hand=2, mesecon=2, tubedevice=1, tubedevice_receiver=1 }
+ if state == "on" then groups.not_in_creative_inventory = 1 end
+ local tile_images = {}
+ for _, face in ipairs({ "top", "bottom", "side2", "side1", "back", "front" }) do
+ table.insert(tile_images, data.texture_base.."_"..face..(data.texture_stateful[face] and "_"..state or "")..".png")
+ end
+ minetest.register_node(data.name_base.."_"..state, {
+ description = data.description,
+ tiles = tile_images,
+ mesecons = {
+ effector = {
+ rules = pipeworks.rules_all,
+ action_on = function (pos, node)
+ wielder_on(data, pos, node)
+ end,
+ action_off = function (pos, node)
+ wielder_off(data, pos, node)
+ end,
+ },
+ },
+ tube = {
+ can_insert = function(pos, node, stack, tubedir)
+ if not data.tube_permit_anteroposterior_insert then
+ local nodedir = minetest.facedir_to_dir(node.param2)
+ if vector.equals(tubedir, nodedir) or vector.equals(tubedir, vector.multiply(nodedir, -1)) then
+ return false
+ end
+ end
+ local meta = minetest.get_meta(pos)
+ local inv = meta:get_inventory()
+ return inv:room_for_item(data.wield_inv_name, stack)
+ end,
+ insert_object = function(pos, node, stack, tubedir)
+ if not data.tube_permit_anteroposterior_insert then
+ local nodedir = minetest.facedir_to_dir(node.param2)
+ if vector.equals(tubedir, nodedir) or vector.equals(tubedir, vector.multiply(nodedir, -1)) then
+ return stack
+ end
+ end
+ local meta = minetest.get_meta(pos)
+ local inv = meta:get_inventory()
+ return inv:add_item(data.wield_inv_name, stack)
+ end,
+ input_inventory = data.wield_inv_name,
+ connect_sides = data.tube_connect_sides,
+ can_remove = function(pos, node, stack, tubedir)
+ return stack:get_count()
+ end,
+ },
+ is_ground_content = true,
+ paramtype2 = "facedir",
+ tubelike = 1,
+ groups = groups,
+ sounds = default.node_sound_stone_defaults(),
+ drop = data.name_base.."_off",
+ on_construct = function(pos)
+ local meta = minetest.get_meta(pos)
+ set_wielder_formspec(data, meta)
+ local inv = meta:get_inventory()
+ inv:set_size(data.wield_inv_name, data.wield_inv_width*data.wield_inv_height)
+ if data.ghost_inv_name then
+ inv:set_size(data.ghost_inv_name, 1)
+ end
+ if data.eject_drops then
+ inv:set_size("main", 100)
+ end
+ end,
+ after_place_node = function (pos, placer)
+ pipeworks.scan_for_tube_objects(pos)
+ local placer_pos = placer:getpos()
+ if placer_pos and placer:is_player() then placer_pos = vector.add(placer_pos, assumed_eye_pos) end
+ if placer_pos then
+ local dir = vector.subtract(pos, placer_pos)
+ local node = minetest.get_node(pos)
+ node.param2 = minetest.dir_to_facedir(dir, true)
+ minetest.set_node(pos, node)
+ minetest.log("action", "real (6d) facedir: " .. node.param2)
+ end
+ minetest.get_meta(pos):set_string("owner", placer:get_player_name())
+ end,
+ can_dig = (data.can_dig_nonempty_wield_inv and delay(true) or function(pos, player)
+ local meta = minetest.get_meta(pos)
+ local inv = meta:get_inventory()
+ return inv:is_empty(data.wield_inv_name)
+ end),
+ after_dig_node = function(pos, oldnode, oldmetadata, digger)
+ -- The legacy-node fixup is done here in a
+ -- different form from the standard fixup,
+ -- rather than relying on a standard fixup
+ -- in an on_dig callback, because some
+ -- non-standard diggers (such as technic's
+ -- mining drill) don't respect on_dig.
+ oldmetadata = data.fixup_oldmetadata(oldmetadata)
+ for _, stack in ipairs(oldmetadata.inventory[data.wield_inv_name] or {}) do
+ if not stack:is_empty() then
+ minetest.add_item(pos, stack)
+ end
+ end
+ pipeworks.scan_for_tube_objects(pos)
+ end,
+ on_punch = data.fixup_node,
+ allow_metadata_inventory_put = function(pos, listname, index, stack, player)
+ if not pipeworks.may_configure(pos, player) then return 0 end
+ return stack:get_count()
+ end,
+ allow_metadata_inventory_take = function(pos, listname, index, stack, player)
+ if not pipeworks.may_configure(pos, player) then return 0 end
+ return stack:get_count()
+ end,
+ allow_metadata_inventory_move = function(pos, from_list, from_index, to_list, to_index, count, player)
+ if not pipeworks.may_configure(pos, player) then return 0 end
+ return count
+ end
+ })
+ end
+end
+
+if pipeworks.enable_node_breaker then
+ local data
+ data = {
+ name_base = "pipeworks:nodebreaker",
+ description = "Node Breaker",
+ texture_base = "pipeworks_nodebreaker",
+ texture_stateful = { top = true, bottom = true, side2 = true, side1 = true, front = true },
+ tube_connect_sides = { top=1, bottom=1, left=1, right=1, back=1 },
+ tube_permit_anteroposterior_insert = false,
+ wield_inv_name = "pick",
+ wield_inv_width = 1,
+ wield_inv_height = 1,
+ can_dig_nonempty_wield_inv = true,
+ ghost_inv_name = "ghost_pick",
+ ghost_tool = "default:pick_mese",
+ fixup_node = function (pos, node)
+ local meta = minetest.get_meta(pos)
+ local inv = meta:get_inventory()
+ -- Node breakers predating the visible pick slot
+ -- may have been partially updated. This code
+ -- fully updates them. Some have been observed
+ -- to have no pick slot at all; first add one.
+ if inv:get_size("pick") ~= 1 then
+ inv:set_size("pick", 1)
+ end
+ -- Originally, they had a ghost pick in a "pick"
+ -- inventory, no other inventory, and no form.
+ -- The partial update of early with-form node
+ -- breaker code gives them "ghost_pick" and "main"
+ -- inventories, but leaves the old ghost pick in
+ -- the "pick" inventory, and doesn't add a form.
+ -- First perform that partial update.
+ if inv:get_size("ghost_pick") ~= 1 then
+ inv:set_size("ghost_pick", 1)
+ inv:set_size("main", 100)
+ end
+ -- If the node breaker predates the visible pick
+ -- slot, which we can detect by it not having a
+ -- form, then the pick slot needs to be cleared
+ -- of the old ghost pick.
+ if (meta:get_string("formspec") or "") == "" then
+ inv:set_stack("pick", 1, ItemStack(""))
+ end
+ -- Finally, unconditionally set the formspec
+ -- and infotext. This not only makes the
+ -- pick slot visible for node breakers where
+ -- it wasn't before; it also updates the form
+ -- for node breakers that had an older version
+ -- of the form, and sets infotext where it was
+ -- missing for early with-form node breakers.
+ set_wielder_formspec(data, meta)
+ end,
+ fixup_oldmetadata = function (oldmetadata)
+ -- Node breakers predating the visible pick slot,
+ -- with node form, kept their ghost pick in an
+ -- inventory named "pick", the same name as the
+ -- later visible pick slot. The pick must be
+ -- removed to avoid spilling it.
+ if not oldmetadata.fields.formspec then
+ return { inventory = { pick = {} }, fields = oldmetadata.fields }
+ else
+ return oldmetadata
+ end
+ end,
+ masquerade_as_owner = true,
+ sneak = false,
+ act = function(virtplayer, pointed_thing)
+ local wieldstack = virtplayer:get_wielded_item()
+ local oldwieldstack = ItemStack(wieldstack)
+ local on_use = (minetest.registered_items[wieldstack:get_name()] or {}).on_use
+ if on_use then
+ wieldstack = on_use(wieldstack, virtplayer, pointed_thing) or wieldstack
+ virtplayer:set_wielded_item(wieldstack)
+ else
+ local under_node = minetest.get_node(pointed_thing.under)
+ local on_dig = (minetest.registered_nodes[under_node.name] or {on_dig=minetest.node_dig}).on_dig
+ on_dig(pointed_thing.under, under_node, virtplayer)
+ wieldstack = virtplayer:get_wielded_item()
+ end
+ local wieldname = wieldstack:get_name()
+ if wieldname == oldwieldstack:get_name() then
+ -- don't mechanically wear out tool
+ if wieldstack:get_count() == oldwieldstack:get_count() and
+ wieldstack:get_metadata() == oldwieldstack:get_metadata() and
+ ((minetest.registered_items[wieldstack:get_name()] or {}).wear_represents or "mechanical_wear") == "mechanical_wear" then
+ virtplayer:set_wielded_item(oldwieldstack)
+ end
+ elseif wieldname ~= "" then
+ -- tool got replaced by something else:
+ -- treat it as a drop
+ virtplayer:get_inventory():add_item("main", wieldstack)
+ virtplayer:set_wielded_item(ItemStack(""))
+ end
+ end,
+ eject_drops = true,
+ }
+ register_wielder(data)
+ minetest.register_craft({
+ output = "pipeworks:nodebreaker_off",
+ recipe = {
+ { "group:wood", "default:pick_mese", "group:wood" },
+ { "default:stone", "mesecons:piston", "default:stone" },
+ { "default:stone", "mesecons:mesecon", "default:stone" },
+ }
+ })
+ -- aliases for when someone had technic installed, but then uninstalled it but not pipeworks
+ minetest.register_alias("technic:nodebreaker_off", "pipeworks:nodebreaker_off")
+ minetest.register_alias("technic:nodebreaker_on", "pipeworks:nodebreaker_on")
+ minetest.register_alias("technic:node_breaker_off", "pipeworks:nodebreaker_off")
+ minetest.register_alias("technic:node_breaker_on", "pipeworks:nodebreaker_on")
+ -- turn legacy auto-tree-taps into node breakers
+ dofile(pipeworks.modpath.."/legacy.lua")
+end
+
+if pipeworks.enable_deployer then
+ register_wielder({
+ name_base = "pipeworks:deployer",
+ description = "Deployer",
+ texture_base = "pipeworks_deployer",
+ texture_stateful = { front = true },
+ tube_connect_sides = { back=1 },
+ tube_permit_anteroposterior_insert = true,
+ wield_inv_name = "main",
+ wield_inv_width = 3,
+ wield_inv_height = 3,
+ can_dig_nonempty_wield_inv = false,
+ masquerade_as_owner = true,
+ sneak = false,
+ act = function(virtplayer, pointed_thing)
+ local wieldstack = virtplayer:get_wielded_item()
+ virtplayer:set_wielded_item((minetest.registered_items[wieldstack:get_name()] or {on_place=minetest.item_place}).on_place(wieldstack, virtplayer, pointed_thing) or wieldstack)
+ end,
+ eject_drops = false,
+ })
+ minetest.register_craft({
+ output = "pipeworks:deployer_off",
+ recipe = {
+ { "group:wood", "default:chest", "group:wood" },
+ { "default:stone", "mesecons:piston", "default:stone" },
+ { "default:stone", "mesecons:mesecon", "default:stone" },
+ }
+ })
+ -- aliases for when someone had technic installed, but then uninstalled it but not pipeworks
+ minetest.register_alias("technic:deployer_off", "pipeworks:deployer_off")
+ minetest.register_alias("technic:deployer_on", "pipeworks:deployer_on")
+end
+
+if pipeworks.enable_dispenser then
+ register_wielder({
+ name_base = "pipeworks:dispenser",
+ description = "Dispenser",
+ texture_base = "pipeworks_dispenser",
+ texture_stateful = { front = true },
+ tube_connect_sides = { back=1 },
+ tube_permit_anteroposterior_insert = true,
+ wield_inv_name = "main",
+ wield_inv_width = 3,
+ wield_inv_height = 3,
+ can_dig_nonempty_wield_inv = false,
+ masquerade_as_owner = false,
+ sneak = true,
+ act = function(virtplayer, pointed_thing)
+ local wieldstack = virtplayer:get_wielded_item()
+ virtplayer:set_wielded_item((minetest.registered_items[wieldstack:get_name()] or {on_drop=minetest.item_drop}).on_drop(wieldstack, virtplayer, virtplayer:getpos()) or wieldstack)
+ end,
+ eject_drops = false,
+ })
+ minetest.register_craft({
+ output = "pipeworks:dispenser_off",
+ recipe = {
+ { "default:desert_sand", "default:chest", "default:desert_sand" },
+ { "default:stone", "mesecons:piston", "default:stone" },
+ { "default:stone", "mesecons:mesecon", "default:stone" },
+ }
+ })
+end