90 Commits

Author SHA1 Message Date
d4e05f33af Fix Luacontroller’s print() (#422)
Because of working inside the sandbox, it was unable to print tables.
2018-07-23 15:53:32 +03:00
334400a541 Add 'settingtypes.txt' (#350) 2018-07-23 15:48:34 +03:00
5a0492b176 Check protection on microcontroller programming (#420)
Also, fix globals assignment.
2018-07-23 14:00:59 +03:00
f61b1affea Let things fall behind movestones (#421)
* Let things fall behind movestones
2018-07-23 13:14:05 +03:00
a234006592 Fix mesecon receiver duplication (#419) 2018-07-21 10:42:24 +03:00
12fb09f452 Fix crash when error()ing an invalid value on programming (#418) 2018-07-18 22:49:34 +03:00
ff73d0e60f Merge pull request #401 from Wuzzy2/sfx
Add missing sound effects and fix wrong pressure plate sounds
2018-07-18 01:37:45 +03:00
7013f2e5d4 Add screenshot.png 2018-05-15 20:21:33 +01:00
f70a308bb0 Replace deprecated methods:
- 'setting_get' with 'settings:get'
- 'setting_getbool' with 'settings:get_bool'
2018-03-25 22:05:10 +02:00
d8f82e6771 Fix sticky pistons (#403)
Fixed method name to get the position.
2018-02-15 11:47:24 +01:00
DS
7537b9f381 Use rotate_simple for insulated wires (#382) 2018-01-30 21:47:03 +03:00
5ae3354227 Change hydroturbine sound to metal 2018-01-28 21:22:09 +01:00
1b513d2111 Fix sounds of pressure plates, change groups 2018-01-28 21:14:54 +01:00
6f1ff24474 Add sounds for wires and piston heads 2018-01-28 20:56:42 +01:00
065e870349 Improve LuaController security (#393)
Fixes:
1. Lack of 'safe' on minetest.deserialize usage
2. String sandbox bypass via (""):evil()
3. Loss of upcoming digilines messages on server shutdown
4. LCs failing to show information on some errors
5. Interrupt IDs as infinite data storage
2018-01-22 14:26:21 +03:00
fec82ab246 Sticky block: Add texture, sounds and groups (#397) 2018-01-18 22:01:53 +03:00
02f8d29170 Microcontroller craft fallbacks for detectors (#390)
Register both luacontroller and microcontroller variations of detector craft recipes.
2018-01-14 23:21:43 +03:00
2b096f050d Limit and optimize digiline_send (#379)
* Close vulnerability and optimize digiline_send

`digiline_send` as it previously existed was vulnerable to a
time-of-check-to-time-of-use vulnerability in which a table could be
sent, size-checked, and then modified after the send but before
delivery. This would allow larger tables to be sent. It was also slow
because it called `minetest.serialize`. Fix both of these by
implementing custom message cleanup logic which simultaneously computes
the message’s cost.

* Clean up interaction with Digilines

Use `minetest.global_exists` to avoid an undefined global variable
warning when operating a Luacontroller with Digilines not available. Use
the new `digilines` table in preference to the old `digiline` table.

* Copy received messages

When a Digiline message is received at a Luacontroller, copy it so that
local modifications made by the Luacontroller code will not modify
copies of the table that are being passed to other nodes on the Digiline
network.
2018-01-13 22:27:00 +03:00
DS
993fdedd8c Check for falling after piston pusher removal (#392) 2018-01-07 01:32:15 +03:00
DS
ff0bd76efe Set is_ground_content to false (#386) 2017-11-01 00:50:39 +03:00
db39eef2f6 Make the fpga overheat 2017-10-29 21:19:08 +01:00
f78937b351 Fix typo 2017-10-21 17:05:09 +03:00
cc860acf8a Publish some LuaC API (#348) 2017-10-18 22:54:28 +03:00
DS
748446b3cc MVPS: pull objects (#374) 2017-10-18 22:53:22 +03:00
DS
1b10610f92 Check for falling nodes on MVPS move (#371) 2017-10-18 22:40:25 +03:00
4f400f3fae Add bower compatibility (#347) 2017-10-15 17:40:44 +03:00
DS
7094f0b606 Improve movestones (#366)
Improve the code and add vertical movestones
2017-10-08 19:41:22 +03:00
b08e93fc8b Remove obsolete nodeupdate call
It wasn't necessary, actually.
2017-10-08 19:20:24 +03:00
DS
928f04fa9c Rewrite pistons (#362) 2017-10-08 19:21:19 +03:00
DS
c4a1aa0b98 MVPS: Improve object move (#367) 2017-10-08 18:18:47 +03:00
DS
37eb7f00e8 Improve rules and rule handling (#370) 2017-10-08 02:39:02 +03:00
DS
905260c8db Handle blasts (#356) 2017-10-07 01:44:49 +03:00
DS
8999597df2 Support an on-move callback (#363) 2017-10-06 00:09:48 +03:00
DS
0b3039e9a9 Make removestone check nodes above for falling (#357)
Fixes a part of #290.
2017-10-04 01:19:09 +03:00
DS
1f5601661e Do not reset conductor param2 on place (#364) 2017-10-04 00:55:33 +03:00
fa58607546 fpga: Make rotatable with screwdrivers 2017-10-03 17:46:58 +02:00
DS
1963d8b3d5 Prevent wires from being rotated (#365) 2017-09-19 18:12:00 +03:00
954262d016 Add 6 new lightstone colors (#329)
Cyan, magenta, orange, pink, violet and white.
2017-09-18 01:38:55 +03:00
DS
3ef8ae01e7 Add conversation recipes for Lua- and Microcontroller (#354) 2017-09-11 21:26:37 +02:00
DS
42cd973921 Do not stop node timers on mvps move (#359) 2017-09-11 21:26:04 +02:00
DS
36a6419481 Fix active button staying on forever (#355) 2017-09-03 21:27:31 +03:00
564bdc2d9b Fix crash when error()ing an invalid value
See #337 for details.
2017-05-08 17:34:30 +03:00
DS
f9ebbdc0fb Make LuaC formspec bigger (#338) 2017-05-08 02:59:57 +04:00
4dcc7fb32f Update github links in the README 2017-04-21 21:33:21 +02:00
54b9eaffa2 Improve overheating (#334)
New overheating system that doesn’t use the meta.
2017-04-14 23:14:17 +04:00
2554164674 Improve object and node detectors
* Support detection of multiple players in object detector
* Add distance parameter to node detector
* Fix area protection
2017-03-31 12:11:40 +02:00
967bde284a Spell-check and clarify item names
* Fix inconsistent insulated mesecon names
* Clarify lightstone names
* Rename meselamp to "Mesecon Lamp"
* Use capitalization "Luacontroller" consistently
* Cleanup / improvements for logic gate naming
2017-03-07 19:04:05 +01:00
DS
d80c788fab Change sticky movestone craft recipe
It used to be so that you could gain two sticky movestones out of one normal one,
this didn't make much sense.
2017-03-04 09:10:44 +01:00
03ab151c87 Fix active ghoststones being droppable with sand
Fixes #289
2017-02-15 23:00:02 +01:00
dd2b36c41c fix wrong UV mapping on "on" turbine blades 2017-02-13 14:24:29 -05:00
0cb286b425 Merge pull request #321 from Jeija/animated_turbine
Make "on" water turbine animated!
2017-02-12 19:56:29 -05:00
46cbc76988 make "on" water turbine animated!
This uses a fairly simple trick: the textures are animated, while the
model is static and has a number of rotated copies of the parts that are
seen to move (four copies of the blades, eight copies of the top/bottom
and their edges).  The opaque parts of the textures then decide which of
those faces' copies are visible in each frame.
2017-02-12 13:57:30 -05:00
fa3bd19270 fix Z-fighting on water turbine 2017-02-12 10:56:54 -05:00
2bc3c5d97c fpga: Make formspec usage less prone to breakage 2017-01-28 11:54:27 +01:00
07d074075c FPGAs (#315) 2017-01-28 11:33:13 +01:00
5188853014 Make descriptions of insulated wires consistent
This allows finding all of them by searching
"insulated" in the creative menu.
2017-01-22 13:39:10 +01:00
7667e7d8c5 Fix Lua error with microcontrollers
caused by an oversight in ececf525b6
2017-01-19 16:31:36 +01:00
ececf525b6 Fix remaining namespace pollutions (closes #311) 2017-01-15 23:12:13 +01:00
54daee236e Luacontroller: Revert function stripping from digiline messages 2017-01-15 20:11:12 +01:00
c2e3d7c4e5 Fix most of the namespace pollutions reported in #311 2017-01-15 11:53:49 +01:00
7415036f5b Make insulated cossover to mesh
This removes the weird "holes" in the isolation of the crossing
2017-01-02 14:59:52 +01:00
1bd936ad8c Properly handle rotation of buttons / levers
Buttons and levers can now also be pointed upwards / downwards which will make them connect to corresponding up / down receivers. You will need to use the screwdriver for this.

Receivers cannot be rotated using the screwdriver anymore.
2017-01-02 14:51:28 +01:00
79edbed8d7 Allow water turbines to work with river water (fixes #294)
This also makes turbines compatible with any liquid that is in the `water` group and has `liquidtype == "flowing"`.
2016-12-31 10:57:50 +01:00
8743699298 Luacontroller: Fix bugs in 703e6fda, no more functions as keys
Thanks to @ShadowNinja for reporting this
Make sure functions that are keys in tables and functions inside nested tables also get removed when using digiline_send.
2016-12-31 10:43:45 +01:00
703e6fdadb Luacontroller: Restrict digiline messages
Restrict maximum length of messages to 50.000 characters and disable sending functions or table references over the wire. Restrict types of channel variable to string, number or boolean.

The missing length restriction made DoS-like attacks possible by overflowing memory using string concatenation. Thanks to gamemanj for disclosing this issue.
2016-12-28 10:07:59 +01:00
67cd17aa79 Fix crash with movestones 2016-12-04 19:37:31 +08:00
203aaf3c90 Remove an unused function. 2016-11-17 14:55:02 +01:00
95fedc88bc Never postpone action_on or action_off
There is no more need for that since VoxelManip caching makes sure we
always get an answer to get_node_force.
2016-09-04 09:50:30 +02:00
433778c2ec Add Hawk777 to contributor list, update developer documentation URL 2016-09-04 09:32:41 +02:00
54efc64558 Duplicate unhash_blockpos code to legacy.lua
Duplicating that small piece of code seems like a better idea than
putting the undo-forceloading code back into util.lua. This way, it is
easier to remember to remove that unneccesary code after a couple of
months / years, when people have transitioned. This also means we can
make changes to the code in util.lua without breaking old code.
2016-08-31 08:46:11 +02:00
dfeb070a20 Remove some long unused legacy code
The change that required this compatibility layer happened in
2014, so other mods have had a lot of time to update.
2016-08-30 20:54:20 +02:00
6dacdaee1f Small cleanups in internal.lua, move forceloading reversal to legacy 2016-08-30 19:37:43 +02:00
e561be7fa3 Greatly improve performance by making use of VoxelManips in turnoff
Instead of seperately looking for onstate receptors along equipotential
sections of the circuit before turning off, do that while already
modifying the VoxelManip. In case an onstate receptor is found, discard
the VoxelManip cache, otherwise commit it after turnoff is completed.
2016-08-30 19:12:09 +02:00
89153f6909 Further simplification of turnon/turnoff 2016-08-30 18:24:08 +02:00
8e6536ca2e Simplify turnon/turnoff.
It is no longer possible for get_node_force to return nil if the target
location does, in fact, exist, because a VM will always be able to load
it (whereas a forceload might not, due to exhaustion of forceload
resources). So it is no longer necessary to handle get_node_force
returning nil by deferring processing.
2016-08-24 00:42:40 -07:00
bc9d4c2d5a Use VM transactions for conductor state changes.
VoxelManipulator-based transactions are used to hopefully speed up
scanning and replacing of networks of conductors when receptors start or
stop driving signals into them.
2016-08-24 00:42:40 -07:00
6d79272ed4 Implement VoxelManipulator-based transactions.
Rather than calling out through the Lua-to-C API for each node that
needs to be read or written, a group of map reads (and optionally
writes) can be grouped into a transaction. Access to map data within the
transaction is provided at high speed by means of VoxelManipulators.
Once the reads and writes are finished, the transaction can be committed
or aborted.
2016-08-24 00:42:38 -07:00
564cee346a Use VoxelManipulators for get_node_force.
A VoxelManipulator, when asked to read a mapblock, in addition to making
that mapblock available to the caller, also pulls it into the server’s
map cache, thus making get_node calls in the immediate future succeed.

This has the dual advantages that not every mapblock containing a
Mesecons circuit need remain loaded at all times (rather mapblocks can
be loaded on demand as signals are sent), and that the server need not
bother running ABMs and ticking entities within those mapblocks that are
loaded due to Mesecons signalling.
2016-08-24 00:41:47 -07:00
912f17f335 Split wires into their own mod, introduce autoconnect hooks
The update_autoconnect function had to be abstracted away from the
default wires, any kind of wire can now register autoconnect hooks,
which should make having multiple different wire types much easier.

mesecons_mvps, mesecons_receiver and mesecons_random made use of
update_autoconnect, their code was also adapted. This also fixes a
receiver bug: If a receiver was placed with a onstate receptor next
to it (but not the wall lever / button that caused the receiver to
appear) the receiver didn't turn on in the past.

Also move documentation for mesecon wire into mesecons_wire.
2016-08-23 11:08:53 +02:00
4816dee396 Move shared textures into base mod (fixes a few LuaC issues) 2016-08-23 11:02:12 +02:00
a3042b44fc Merge pull request #282 from Hawk777/luacontroller-comment
Remove an obsolete comment.
2016-08-16 12:14:33 +02:00
53eaf2af11 Remove an obsolete comment. 2016-08-16 00:16:24 -07:00
778ee427f4 Fix bug introduced in previous commit that broke all logic blocks
turnon / turnoff were calling activate / deactivate on nodes even though
their rules didn't link

Fixes #278, thanks to @darkfeels
2016-07-31 22:26:33 +02:00
7c7595fd7d Fix #276: Fix bugs in block forceloading in turnon / turnoff
Thanks to @Hawk777 for reporting this problem
2016-07-25 10:01:43 +02:00
acd41b5773 Don't bother checking if a node can overheat before cooling it 2016-07-09 11:17:08 +02:00
f9f7600017 Command block server crash fixed
Before that, command block would crash the server if activated when no
players are online
2016-07-09 11:01:27 +02:00
40487a65f4 Add protection support to Luacontrollers,
protection is ignored with protection_bypass_priv
2016-05-17 07:58:50 +02:00
75308f73e4 Merge pull request #270 from Emon-Omen/patch-1
Fixed missing capital letter in "ghoststone"
2016-05-17 07:53:35 +02:00
478680292c fixed missing capital letter @ line 29 2016-05-16 22:24:56 +02:00
85bc62a65d Add COPYING.txt file to clarify coprights and licenses 2016-05-16 08:04:57 +02:00
115 changed files with 4805 additions and 1502 deletions

30
COPYING.txt Normal file
View File

@ -0,0 +1,30 @@
The Mesecons Mod for Minetest is
Copyright (C) 2011-2016 Mesecons Mod Developer Team and contributors
See the version control system log for information about other authors.
License of source code
----------------------
Copyright (C) 2011-2016 Mesecons Mod Developer Team and contributors
This program is free software; you can redistribute the Mesecons Mod and/or
modify it under the terms of the GNU Lesser General Public License version 3
published by the Free Software Foundation.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the
Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
Boston, MA 02110-1301, USA.
License of media (textures, sounds and documentation)
-----------------------------------------------------
Copyright (C) 2011-2016 Mesecons Mod Developer Team and contributors
All textures, sounds and documentation files are licensed under the
Attribution-ShareAlike 3.0 Unported (CC BY-SA 3.0)
http://creativecommons.org/licenses/by-sa/3.0/

View File

@ -22,7 +22,7 @@ OK, I want in.
-------------- --------------
Go get it! Go get it!
[DOWNLOAD IT NOW](https://github.com/Jeija/minetest-mod-mesecons/archive/master.zip) [DOWNLOAD IT NOW](https://github.com/minetest-mods/mesecons/archive/master.zip)
Now go ahead and install it like any other Minetest mod. Don't know how? Check out [the wonderful page about it](http://wiki.minetest.com/wiki/Mods) over at the Minetest Wiki. For your convenience, here's a quick summary: Now go ahead and install it like any other Minetest mod. Don't know how? Check out [the wonderful page about it](http://wiki.minetest.com/wiki/Mods) over at the Minetest Wiki. For your convenience, here's a quick summary:
@ -45,7 +45,7 @@ An overview for the very newest of new beginners? How does [this one](http://ube
Want to get more into building? Why not check out the [Mesecons Laboratory](http://uberi.mesecons.net/), a website dedicated to advanced Mesecons builders? Want to get more into building? Why not check out the [Mesecons Laboratory](http://uberi.mesecons.net/), a website dedicated to advanced Mesecons builders?
Want to contribute to Mesecons itself? Check out the [source code](https://github.com/Jeija/minetest-mod-mesecons)! Want to contribute to Mesecons itself? Check out the [source code](https://github.com/minetest-mods/mesecons)!
Who wrote it anyways? Who wrote it anyways?
--------------------- ---------------------
@ -53,6 +53,7 @@ These awesome people made Mesecons possible!
| Contributor | Contribution | | Contributor | Contribution |
| --------------- | -------------------------------- | | --------------- | -------------------------------- |
| Hawk777 | Code for VoxelManip caching |
| Jat15 | Various tweaks. | | Jat15 | Various tweaks. |
| Jeija | **Main developer! Everything.** | | Jeija | **Main developer! Everything.** |
| Jordach | Noteblock sounds. | | Jordach | Noteblock sounds. |

12
bower.json Normal file
View File

@ -0,0 +1,12 @@
{
"name": "mesecons",
"description": "Mesecons is a mod for Minetest that implements items related to digital circuitry: wires, buttons, lights, and programmable controllers.",
"homepage": "http://mesecons.net",
"authors": "Jeija",
"license": "LGPL-3.0+",
"keywords": [
"mesecons",
"minetest",
"mod"
]
}

View File

@ -1,6 +1,6 @@
{ {
"Conductors" : { "Conductors" : {
"Mesecon" : "mesecons/doc/mesecon", "Mesecon" : "mesecons_wires/doc/mesecon",
"Insulated Wire" : "mesecons_insulated/doc/insulated", "Insulated Wire" : "mesecons_insulated/doc/insulated",
"T-Junction" : "mesecons_extrawires/doc/tjunction", "T-Junction" : "mesecons_extrawires/doc/tjunction",
"Crossing" : "mesecons_extrawires/doc/crossing", "Crossing" : "mesecons_extrawires/doc/crossing",
@ -42,6 +42,8 @@
}, },
"Logic" : { "Logic" : {
"Luacontroller" : "mesecons_luacontroller/doc/luacontroller", "Luacontroller" : "mesecons_luacontroller/doc/luacontroller",
"FPGA" : "mesecons_fpga/doc/fpga",
"FPGA Programmer" : "mesecons_fpga/doc/programmer",
"Torch" : "mesecons_torch/doc/torch", "Torch" : "mesecons_torch/doc/torch",
"Delayer" : "mesecons_delayer/doc/delayer", "Delayer" : "mesecons_delayer/doc/delayer",
"Gates" : { "Gates" : {

View File

@ -87,7 +87,11 @@ minetest.register_globalstep(function (dtime)
end) end)
function mesecon.queue:execute(action) function mesecon.queue:execute(action)
mesecon.queue.funcs[action.func](action.pos, unpack(action.params)) -- ignore if action queue function name doesn't exist,
-- (e.g. in case the action queue savegame was written by an old mesecons version)
if mesecon.queue.funcs[action.func] then
mesecon.queue.funcs[action.func](action.pos, unpack(action.params))
end
end end

View File

@ -1 +0,0 @@
Mesecons are the wires, use them to connect effectors with receptors.

View File

@ -3,7 +3,7 @@
-- | \/ | |___ ____ |___ | | | | \ | |____ -- | \/ | |___ ____ |___ | | | | \ | |____
-- | | | | | | | | | \ | | -- | | | | | | | | | \ | |
-- | | |___ ____| |___ |____ |____| | \| ____| -- | | |___ ____| |___ |____ |____| | \| ____|
-- by Jeija, Uberi (Temperest), sfan5, VanessaE -- by Jeija, Uberi (Temperest), sfan5, VanessaE, Hawk777 and contributors
-- --
-- --
-- --
@ -11,7 +11,7 @@
-- See the documentation on the forum for additional information, especially about crafting -- See the documentation on the forum for additional information, especially about crafting
-- --
-- --
-- For developer documentation see the Developers' section on mesecons.TK -- For basic development resources, see http://mesecons.net/developers.html
-- --
-- --
-- --
@ -70,19 +70,11 @@ dofile(minetest.get_modpath("mesecons").."/internal.lua");
-- these are the only functions you need to remember -- these are the only functions you need to remember
mesecon.queue:add_function("receptor_on", function (pos, rules) mesecon.queue:add_function("receptor_on", function (pos, rules)
mesecon.vm_begin()
rules = rules or mesecon.rules.default rules = rules or mesecon.rules.default
-- if area (any of the rule targets) is not loaded, keep trying and call this again later -- Call turnon on all linking positions
for _, rule in ipairs(mesecon.flattenrules(rules)) do
local np = vector.add(pos, rule)
-- if area is not loaded, keep trying
if minetest.get_node_or_nil(np) == nil then
mesecon.queue:add_action(pos, "receptor_on", {rules}, nil, rules)
return
end
end
-- execute action
for _, rule in ipairs(mesecon.flattenrules(rules)) do for _, rule in ipairs(mesecon.flattenrules(rules)) do
local np = vector.add(pos, rule) local np = vector.add(pos, rule)
local rulenames = mesecon.rules_link_rule_all(pos, rule) local rulenames = mesecon.rules_link_rule_all(pos, rule)
@ -90,6 +82,8 @@ mesecon.queue:add_function("receptor_on", function (pos, rules)
mesecon.turnon(np, rulename) mesecon.turnon(np, rulename)
end end
end end
mesecon.vm_commit()
end) end)
function mesecon.receptor_on(pos, rules) function mesecon.receptor_on(pos, rules)
@ -99,23 +93,21 @@ end
mesecon.queue:add_function("receptor_off", function (pos, rules) mesecon.queue:add_function("receptor_off", function (pos, rules)
rules = rules or mesecon.rules.default rules = rules or mesecon.rules.default
-- if area (any of the rule targets) is not loaded, keep trying and call this again later -- Call turnoff on all linking positions
for _, rule in ipairs(mesecon.flattenrules(rules)) do
local np = vector.add(pos, rule)
if minetest.get_node_or_nil(np) == nil then
mesecon.queue:add_action(pos, "receptor_off", {rules}, nil, rules)
return
end
end
for _, rule in ipairs(mesecon.flattenrules(rules)) do for _, rule in ipairs(mesecon.flattenrules(rules)) do
local np = vector.add(pos, rule) local np = vector.add(pos, rule)
local rulenames = mesecon.rules_link_rule_all(pos, rule) local rulenames = mesecon.rules_link_rule_all(pos, rule)
for _, rulename in ipairs(rulenames) do for _, rulename in ipairs(rulenames) do
if not mesecon.connected_to_receptor(np, mesecon.invertRule(rule)) then mesecon.vm_begin()
mesecon.turnoff(np, rulename) mesecon.changesignal(np, minetest.get_node(np), rulename, mesecon.state.off, 2)
-- Turnoff returns true if turnoff process was successful, no onstate receptor
-- was found along the way. Commit changes that were made in voxelmanip. If turnoff
-- returns true, an onstate receptor was found, abort voxelmanip transaction.
if (mesecon.turnoff(np, rulename)) then
mesecon.vm_commit()
else else
mesecon.changesignal(np, minetest.get_node(np), rulename, mesecon.state.off, 2) mesecon.vm_abort()
end end
end end
end end
@ -132,8 +124,5 @@ print("[OK] Mesecons")
-- To be removed in future releases -- To be removed in future releases
dofile(minetest.get_modpath("mesecons").."/legacy.lua"); dofile(minetest.get_modpath("mesecons").."/legacy.lua");
--The actual wires
dofile(minetest.get_modpath("mesecons").."/wires.lua");
--Services like turnoff receptor on dignode and so on --Services like turnoff receptor on dignode and so on
dofile(minetest.get_modpath("mesecons").."/services.lua"); dofile(minetest.get_modpath("mesecons").."/services.lua");

View File

@ -37,11 +37,6 @@
-- HIGH-LEVEL Internals -- HIGH-LEVEL Internals
-- mesecon.is_power_on(pos) --> Returns true if pos emits power in any way -- mesecon.is_power_on(pos) --> Returns true if pos emits power in any way
-- mesecon.is_power_off(pos) --> Returns true if pos does not emit power in any way -- mesecon.is_power_off(pos) --> Returns true if pos does not emit power in any way
-- mesecon.turnon(pos, link) --> link is the input rule that caused calling turnon, turns on every connected node, iterative
-- mesecon.turnoff(pos, link) --> link is the input rule that caused calling turnoff, turns off every connected node, iterative
-- mesecon.connected_to_receptor(pos, link) --> Returns true if pos is connected to a receptor directly or via conductors, iterative
-- mesecon.rules_link(output, input, dug_outputrules) --> Returns true if outputposition + outputrules = inputposition and inputposition + inputrules = outputposition (if the two positions connect)
-- mesecon.rules_link_anydir(outp., inp., d_outpr.) --> Same as rules mesecon.rules_link but also returns true if output and input are swapped
-- mesecon.is_powered(pos) --> Returns true if pos is powered by a receptor or a conductor -- mesecon.is_powered(pos) --> Returns true if pos is powered by a receptor or a conductor
-- RULES ROTATION helpers -- RULES ROTATION helpers
@ -76,7 +71,7 @@ function mesecon.get_conductor(nodename)
end end
end end
function mesecon.get_any_outputrules (node) function mesecon.get_any_outputrules(node)
if not node then return nil end if not node then return nil end
if mesecon.is_conductor(node.name) then if mesecon.is_conductor(node.name) then
@ -86,7 +81,7 @@ function mesecon.get_any_outputrules (node)
end end
end end
function mesecon.get_any_inputrules (node) function mesecon.get_any_inputrules(node)
if not node then return nil end if not node then return nil end
if mesecon.is_conductor(node.name) then if mesecon.is_conductor(node.name) then
@ -96,7 +91,7 @@ function mesecon.get_any_inputrules (node)
end end
end end
function mesecon.get_any_rules (node) function mesecon.get_any_rules(node)
return mesecon.mergetable(mesecon.get_any_inputrules(node) or {}, return mesecon.mergetable(mesecon.get_any_inputrules(node) or {},
mesecon.get_any_outputrules(node) or {}) mesecon.get_any_outputrules(node) or {})
end end
@ -371,38 +366,32 @@ function mesecon.is_power_off(pos, rulename)
return false return false
end end
-- Turn off an equipotential section starting at `pos`, which outputs in the direction of `link`.
-- Breadth-first search. Map is abstracted away in a voxelmanip.
-- Follow all all conductor paths replacing conductors that were already
-- looked at, activating / changing all effectors along the way.
function mesecon.turnon(pos, link) function mesecon.turnon(pos, link)
local frontiers = {{pos = pos, link = link}} local frontiers = {{pos = pos, link = link}}
local depth = 1 local depth = 1
while frontiers[depth] do while frontiers[1] do
local f = frontiers[depth] local f = table.remove(frontiers, 1)
local node = mesecon.get_node_force(f.pos) local node = mesecon.get_node_force(f.pos)
-- area not loaded, postpone action
if not node then if not node then
mesecon.queue:add_action(f.pos, "turnon", {link}, nil, true) -- Area does not exist; do nothing
elseif mesecon.is_conductor_off(node, f.link) then elseif mesecon.is_conductor_off(node, f.link) then
local rules = mesecon.conductor_get_rules(node) local rules = mesecon.conductor_get_rules(node)
minetest.swap_node(f.pos, {name = mesecon.get_conductor_on(node, f.link), -- Call turnon on neighbors
param2 = node.param2})
-- call turnon on neighbors: normal rules
for _, r in ipairs(mesecon.rule2meta(f.link, rules)) do for _, r in ipairs(mesecon.rule2meta(f.link, rules)) do
local np = vector.add(f.pos, r) local np = vector.add(f.pos, r)
for _, l in ipairs(mesecon.rules_link_rule_all(f.pos, r)) do
-- area not loaded, postpone action table.insert(frontiers, {pos = np, link = l})
if not mesecon.get_node_force(np) then
mesecon.queue:add_action(np, "turnon", {rulename},
nil, true)
else
local links = mesecon.rules_link_rule_all(f.pos, r)
for _, l in ipairs(links) do
table.insert(frontiers, {pos = np, link = l})
end
end end
end end
mesecon.swap_node_force(f.pos, mesecon.get_conductor_on(node, f.link))
elseif mesecon.is_effector(node.name) then elseif mesecon.is_effector(node.name) then
mesecon.changesignal(f.pos, node, f.link, mesecon.state.on, depth) mesecon.changesignal(f.pos, node, f.link, mesecon.state.on, depth)
if mesecon.is_effector_off(node.name) then if mesecon.is_effector_off(node.name) then
@ -413,141 +402,81 @@ function mesecon.turnon(pos, link)
end end
end end
mesecon.queue:add_function("turnon", function (pos, rulename, recdepth) -- Turn on an equipotential section starting at `pos`, which outputs in the direction of `link`.
mesecon.turnon(pos, rulename, recdepth) -- Breadth-first search. Map is abstracted away in a voxelmanip.
end) -- Follow all all conductor paths replacing conductors that were already
-- looked at, deactivating / changing all effectors along the way.
-- In case an onstate receptor is discovered, abort the process by returning false, which will
-- cause `receptor_off` to discard all changes made in the voxelmanip.
-- Contrary to turnon, turnoff has to cache all change and deactivate signals so that they will only
-- be called in the very end when we can be sure that no conductor was found along the path.
--
-- Signal table entry structure:
-- {
-- pos = position of effector,
-- node = node descriptor (name, param1 and param2),
-- link = link the effector is connected to,
-- depth = indicates order in which signals wire fired, higher is later
-- }
function mesecon.turnoff(pos, link) function mesecon.turnoff(pos, link)
local frontiers = {{pos = pos, link = link}} local frontiers = {{pos = pos, link = link}}
local signals = {}
local depth = 1 local depth = 1
while frontiers[depth] do while frontiers[1] do
local f = frontiers[depth] local f = table.remove(frontiers, 1)
local node = mesecon.get_node_force(f.pos) local node = mesecon.get_node_force(f.pos)
-- area not loaded, postpone action
if not node then if not node then
mesecon.queue:add_action(f.pos, "turnoff", {link}, nil, true) -- Area does not exist; do nothing
elseif mesecon.is_conductor_on(node, f.link) then elseif mesecon.is_conductor_on(node, f.link) then
local rules = mesecon.conductor_get_rules(node) local rules = mesecon.conductor_get_rules(node)
minetest.swap_node(f.pos, {name = mesecon.get_conductor_off(node, f.link),
param2 = node.param2})
-- call turnoff on neighbors: normal rules
for _, r in ipairs(mesecon.rule2meta(f.link, rules)) do for _, r in ipairs(mesecon.rule2meta(f.link, rules)) do
local np = vector.add(f.pos, r) local np = vector.add(f.pos, r)
-- area not loaded, postpone action -- Check if an onstate receptor is connected. If that is the case,
if not mesecon.get_node_force(np) then -- abort this turnoff process by returning false. `receptor_off` will
mesecon.queue:add_action(np, "turnoff", {rulename}, -- discard all the changes that we made in the voxelmanip:
nil, true) for _, l in ipairs(mesecon.rules_link_rule_all_inverted(f.pos, r)) do
else if mesecon.is_receptor_on(mesecon.get_node_force(np).name) then
local links = mesecon.rules_link_rule_all(f.pos, r) return false
for _, l in ipairs(links) do
table.insert(frontiers, {pos = np, link = l})
end end
end end
-- Call turnoff on neighbors
for _, l in ipairs(mesecon.rules_link_rule_all(f.pos, r)) do
table.insert(frontiers, {pos = np, link = l})
end
end end
mesecon.swap_node_force(f.pos, mesecon.get_conductor_off(node, f.link))
elseif mesecon.is_effector(node.name) then elseif mesecon.is_effector(node.name) then
mesecon.changesignal(f.pos, node, f.link, mesecon.state.off, depth) table.insert(signals, {
if mesecon.is_effector_on(node.name) and not mesecon.is_powered(f.pos) then pos = f.pos,
mesecon.deactivate(f.pos, node, f.link, depth) node = node,
end link = f.link,
depth = depth
})
end end
depth = depth + 1 depth = depth + 1
end end
end
mesecon.queue:add_function("turnoff", function (pos, rulename, recdepth) for _, sig in ipairs(signals) do
mesecon.turnoff(pos, rulename, recdepth) mesecon.changesignal(sig.pos, sig.node, sig.link, mesecon.state.off, sig.depth)
end) if mesecon.is_effector_on(sig.node.name) and not mesecon.is_powered(sig.pos) then
mesecon.deactivate(sig.pos, sig.node, sig.link, sig.depth)
function mesecon.connected_to_receptor(pos, link)
local node = mesecon.get_node_force(pos)
if not node then return false end
-- Check if conductors around are connected
local rules = mesecon.get_any_inputrules(node)
if not rules then return false end
for _, rule in ipairs(mesecon.rule2meta(link, rules)) do
local links = mesecon.rules_link_rule_all_inverted(pos, rule)
for _, l in ipairs(links) do
local np = vector.add(pos, l)
if mesecon.find_receptor_on(np, mesecon.invertRule(l)) then
return true
end
end end
end end
return false return true
end
function mesecon.find_receptor_on(pos, link)
local frontiers = {{pos = pos, link = link}}
local checked = {}
-- List of positions that have been searched for onstate receptors
local depth = 1
while frontiers[depth] do
local f = frontiers[depth]
local node = mesecon.get_node_force(f.pos)
if not node then return false end
if mesecon.is_receptor_on(node.name) then return true end
if mesecon.is_conductor_on(node, f.link) then
local rules = mesecon.conductor_get_rules(node)
-- call turnoff on neighbors: normal rules
for _, r in ipairs(mesecon.rule2meta(f.link, rules)) do
local np = vector.add(f.pos, r)
local links = mesecon.rules_link_rule_all_inverted(f.pos, r)
for _, l in ipairs(links) do
local checkedstring = np.x..np.y..np.z..l.x..l.y..l.z
if not checked[checkedstring] then
table.insert(frontiers, {pos = np, link = l})
checked[checkedstring] = true
end
end
end
end
depth = depth + 1
end
end
function mesecon.rules_link(output, input, dug_outputrules) --output/input are positions (outputrules optional, used if node has been dug), second return value: the name of the affected input rule
local outputnode = mesecon.get_node_force(output)
local inputnode = mesecon.get_node_force(input)
local outputrules = dug_outputrules or mesecon.get_any_outputrules (outputnode)
local inputrules = mesecon.get_any_inputrules (inputnode)
if not outputrules or not inputrules then
return
end
for _, outputrule in ipairs(mesecon.flattenrules(outputrules)) do
-- Check if output sends to input
if vector.equals(vector.add(output, outputrule), input) then
for _, inputrule in ipairs(mesecon.flattenrules(inputrules)) do
-- Check if input accepts from output
if vector.equals(vector.add(input, inputrule), output) then
return true, inputrule
end
end
end
end
return false
end end
-- Get all linking inputrules of inputnode (effector or conductor) that is connected to
-- outputnode (receptor or conductor) at position `output` and has an output in direction `rule`
function mesecon.rules_link_rule_all(output, rule) function mesecon.rules_link_rule_all(output, rule)
local input = vector.add(output, rule) local input = vector.add(output, rule)
local inputnode = mesecon.get_node_force(input) local inputnode = mesecon.get_node_force(input)
local inputrules = mesecon.get_any_inputrules (inputnode) local inputrules = mesecon.get_any_inputrules(inputnode)
if not inputrules then if not inputrules then
return {} return {}
end end
@ -563,11 +492,12 @@ function mesecon.rules_link_rule_all(output, rule)
return rules return rules
end end
-- Get all linking outputnodes of outputnode (receptor or conductor) that is connected to
-- inputnode (effector or conductor) at position `input` and has an input in direction `rule`
function mesecon.rules_link_rule_all_inverted(input, rule) function mesecon.rules_link_rule_all_inverted(input, rule)
--local irule = mesecon.invertRule(rule)
local output = vector.add(input, rule) local output = vector.add(input, rule)
local outputnode = mesecon.get_node_force(output) local outputnode = mesecon.get_node_force(output)
local outputrules = mesecon.get_any_outputrules (outputnode) local outputrules = mesecon.get_any_outputrules(outputnode)
if not outputrules then if not outputrules then
return {} return {}
end end
@ -581,10 +511,6 @@ function mesecon.rules_link_rule_all_inverted(input, rule)
return rules return rules
end end
function mesecon.rules_link_anydir(pos1, pos2)
return mesecon.rules_link(pos1, pos2) or mesecon.rules_link(pos2, pos1)
end
function mesecon.is_powered(pos, rule) function mesecon.is_powered(pos, rule)
local node = mesecon.get_node_force(pos) local node = mesecon.get_node_force(pos)
local rules = mesecon.get_any_inputrules(node) local rules = mesecon.get_any_inputrules(node)
@ -622,52 +548,3 @@ function mesecon.is_powered(pos, rule)
if (#sourcepos == 0) then return false if (#sourcepos == 0) then return false
else return sourcepos end else return sourcepos end
end end
--Rules rotation Functions:
function mesecon.rotate_rules_right(rules)
local nr = {}
for i, rule in ipairs(rules) do
table.insert(nr, {
x = -rule.z,
y = rule.y,
z = rule.x,
name = rule.name})
end
return nr
end
function mesecon.rotate_rules_left(rules)
local nr = {}
for i, rule in ipairs(rules) do
table.insert(nr, {
x = rule.z,
y = rule.y,
z = -rule.x,
name = rule.name})
end
return nr
end
function mesecon.rotate_rules_down(rules)
local nr = {}
for i, rule in ipairs(rules) do
table.insert(nr, {
x = -rule.y,
y = rule.x,
z = rule.z,
name = rule.name})
end
return nr
end
function mesecon.rotate_rules_up(rules)
local nr = {}
for i, rule in ipairs(rules) do
table.insert(nr, {
x = rule.y,
y = -rule.x,
z = rule.z,
name = rule.name})
end
return nr
end

View File

@ -1,30 +1,14 @@
-- Ugly hack to prevent breaking compatibility with other mods -- Un-forceload any forceloaded mapblocks from older versions of Mesecons which
-- Just remove the following two functions to delete the hack, to be done when other mods have updated -- used forceloading instead of VoxelManipulators.
function mesecon.receptor_on(self, pos, rules) local BLOCKSIZE = 16
if (self.receptor_on) then
print("[Mesecons] Warning: A mod with mesecon support called mesecon:receptor_on.") -- convert block hash --> node position
print("[Mesecons] If you are the programmer of this mod, please update it ") local function unhash_blockpos(hash)
print("[Mesecons] to use mesecon.receptor_on instead. mesecon:* is deprecated") return vector.multiply(minetest.get_position_from_hash(hash), BLOCKSIZE)
print("[Mesecons] Otherwise, please make sure you're running the latest version")
print("[Mesecons] of that mod and inform the mod creator.")
else
rules = pos
pos = self
end
mesecon.queue:add_action(pos, "receptor_on", {rules}, nil, rules)
end end
function mesecon.receptor_off(self, pos, rules) local old_forceloaded_blocks = mesecon.file2table("mesecon_forceloaded")
if (self.receptor_off) then for hash, _ in pairs(old_forceloaded_blocks) do
print("[Mesecons] Warning: A mod with mesecon support called mesecon:receptor_off.") minetest.forceload_free_block(unhash_blockpos(hash))
print("[Mesecons] If you are the programmer of this mod, please update it ")
print("[Mesecons] to use mesecon.receptor_off instead. mesecon:* is deprecated")
print("[Mesecons] Otherwise, please make sure you're running the latest version")
print("[Mesecons] of that mod and inform the mod creator.")
else
rules = pos
pos = self
end
mesecon.queue:add_action(pos, "receptor_off", {rules}, nil, rules)
end end
os.remove(minetest.get_worldpath()..DIR_DELIM.."mesecon_forceloaded")

View File

@ -4,7 +4,7 @@ minetest.register_node("mesecons:mesecon_off", {
inventory_image = "jeija_mesecon_off.png", inventory_image = "jeija_mesecon_off.png",
wield_image = "jeija_mesecon_off.png", wield_image = "jeija_mesecon_off.png",
paramtype = "light", paramtype = "light",
is_ground_content = true, is_ground_content = false,
walkable = false, walkable = false,
selection_box = { selection_box = {
type = "fixed", type = "fixed",
@ -22,7 +22,7 @@ minetest.register_node("mesecons:mesecon_on", {
drawtype = "raillike", drawtype = "raillike",
tiles = {"jeija_mesecon_on.png", "jeija_mesecon_curved_on.png", "jeija_mesecon_t_junction_on.png", "jeija_mesecon_crossing_on.png"}, tiles = {"jeija_mesecon_on.png", "jeija_mesecon_curved_on.png", "jeija_mesecon_t_junction_on.png", "jeija_mesecon_crossing_on.png"},
paramtype = "light", paramtype = "light",
is_ground_content = true, is_ground_content = false,
walkable = false, walkable = false,
selection_box = { selection_box = {
type = "fixed", type = "fixed",

View File

@ -1,54 +1,85 @@
mesecon.rules = {} mesecon.rules = {}
mesecon.state = {} mesecon.state = {}
mesecon.rules.default = mesecon.rules.default = {
{{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=-1, y=0, z=0}, {x = -1, y = 0, z = 0},
{x=0, y=0, z=1}, {x = 0, y = 0, z = 1},
{x=1, y=1, z=0}, {x = 1, y = 1, z = 0},
{x=1, y=-1, z=0}, {x = 1, y = -1, z = 0},
{x=-1, y=1, z=0}, {x = -1, y = 1, z = 0},
{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=0, y=-1, z=1}, {x = 0, y = -1, z = 1},
{x=0, y=1, z=-1}, {x = 0, y = 1, z = -1},
{x=0, y=-1, z=-1}} {x = 0, y = -1, z = -1},
}
mesecon.rules.pplate = mesecon.mergetable(mesecon.rules.default, {{x=0, y=-2, z=0}}) mesecon.rules.floor = mesecon.mergetable(mesecon.rules.default, {{x = 0, y = -1, z = 0}})
mesecon.rules.buttonlike = mesecon.rules.pplate = mesecon.mergetable(mesecon.rules.floor, {{x = 0, y = -2, z = 0}})
{{x = 1, y = 0, z = 0},
{x = 1, y = 1, z = 0},
{x = 1, y =-1, z = 0},
{x = 1, y =-1, z = 1},
{x = 1, y =-1, z =-1},
{x = 2, y = 0, z = 0}}
mesecon.rules.flat = mesecon.rules.buttonlike = {
{{x = 1, y = 0, z = 0}, {x = 1, y = 0, z = 0},
{x =-1, y = 0, z = 0}, {x = 1, y = 1, z = 0},
{x = 0, y = 0, z = 1}, {x = 1, y = -1, z = 0},
{x = 0, y = 0, z =-1}} {x = 1, y = -1, z = 1},
{x = 1, y = -1, z = -1},
{x = 2, y = 0, z = 0},
}
mesecon.rules.alldirs = mesecon.rules.flat = {
{{x= 1, y= 0, z= 0}, {x = 1, y = 0, z = 0},
{x=-1, y= 0, z= 0}, {x = -1, y = 0, z = 0},
{x= 0, y= 1, z= 0}, {x = 0, y = 0, z = 1},
{x= 0, y=-1, z= 0}, {x = 0, y = 0, z = -1},
{x= 0, y= 0, z= 1}, }
{x= 0, y= 0, z=-1}}
mesecon.rules.alldirs = {
{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},
}
local rules_wallmounted = {
xp = mesecon.rotate_rules_down(mesecon.rules.floor),
xn = mesecon.rotate_rules_up(mesecon.rules.floor),
yp = mesecon.rotate_rules_up(mesecon.rotate_rules_up(mesecon.rules.floor)),
yn = mesecon.rules.floor,
zp = mesecon.rotate_rules_left(mesecon.rotate_rules_up(mesecon.rules.floor)),
zn = mesecon.rotate_rules_right(mesecon.rotate_rules_up(mesecon.rules.floor)),
}
local rules_buttonlike = {
xp = mesecon.rules.buttonlike,
xn = mesecon.rotate_rules_right(mesecon.rotate_rules_right(mesecon.rules.buttonlike)),
yp = mesecon.rotate_rules_down(mesecon.rules.buttonlike),
yn = mesecon.rotate_rules_up(mesecon.rules.buttonlike),
zp = mesecon.rotate_rules_right(mesecon.rules.buttonlike),
zn = mesecon.rotate_rules_left(mesecon.rules.buttonlike),
}
local function rules_from_dir(ruleset, dir)
if dir.x == 1 then return ruleset.xp end
if dir.y == 1 then return ruleset.yp end
if dir.z == 1 then return ruleset.zp end
if dir.x == -1 then return ruleset.xn end
if dir.y == -1 then return ruleset.yn end
if dir.z == -1 then return ruleset.zn end
end
mesecon.rules.wallmounted_get = function(node)
local dir = minetest.wallmounted_to_dir(node.param2)
return rules_from_dir(rules_wallmounted, dir)
end
mesecon.rules.buttonlike_get = function(node) mesecon.rules.buttonlike_get = function(node)
local rules = mesecon.rules.buttonlike local dir = minetest.facedir_to_dir(node.param2)
if node.param2 == 2 then return rules_from_dir(rules_buttonlike, dir)
rules=mesecon.rotate_rules_left(rules)
elseif node.param2 == 3 then
rules=mesecon.rotate_rules_right(mesecon.rotate_rules_right(rules))
elseif node.param2 == 0 then
rules=mesecon.rotate_rules_right(rules)
end
return rules
end end
mesecon.state.on = "on" mesecon.state.on = "on"

View File

@ -1,7 +1,7 @@
-- Dig and place services -- Dig and place services
mesecon.on_placenode = function (pos, node) mesecon.on_placenode = function(pos, node)
mesecon.update_autoconnect(pos, node) mesecon.execute_autoconnect_hooks_now(pos, node)
-- Receptors: Send on signal when active -- Receptors: Send on signal when active
if mesecon.is_receptor_on(node.name) then if mesecon.is_receptor_on(node.name) then
@ -21,7 +21,8 @@ mesecon.on_placenode = function (pos, node)
end end
--mesecon.receptor_on (pos, mesecon.conductor_get_rules(node)) --mesecon.receptor_on (pos, mesecon.conductor_get_rules(node))
elseif mesecon.is_conductor_on(node) then elseif mesecon.is_conductor_on(node) then
minetest.swap_node(pos, {name = mesecon.get_conductor_off(node)}) node.name = mesecon.get_conductor_off(node)
minetest.swap_node(pos, node)
end end
end end
@ -52,49 +53,84 @@ mesecon.on_placenode = function (pos, node)
end end
end end
mesecon.on_dignode = function (pos, node) mesecon.on_dignode = function(pos, node)
if mesecon.is_conductor_on(node) then if mesecon.is_conductor_on(node) then
mesecon.receptor_off(pos, mesecon.conductor_get_rules(node)) mesecon.receptor_off(pos, mesecon.conductor_get_rules(node))
elseif mesecon.is_receptor_on(node.name) then elseif mesecon.is_receptor_on(node.name) then
mesecon.receptor_off(pos, mesecon.receptor_get_rules(node)) mesecon.receptor_off(pos, mesecon.receptor_get_rules(node))
end end
mesecon.queue:add_action(pos, "update_autoconnect", {node})
mesecon.execute_autoconnect_hooks_queue(pos, node)
end end
mesecon.queue:add_function("update_autoconnect", mesecon.update_autoconnect) function mesecon.on_blastnode(pos, intensity)
local node = minetest.get_node(pos)
minetest.remove_node(pos)
mesecon.on_dignode(pos, node)
return minetest.get_node_drops(node.name, "")
end
minetest.register_on_placenode(mesecon.on_placenode) minetest.register_on_placenode(mesecon.on_placenode)
minetest.register_on_dignode(mesecon.on_dignode) minetest.register_on_dignode(mesecon.on_dignode)
-- Overheating service for fast circuits -- Overheating service for fast circuits
local OVERHEAT_MAX = mesecon.setting("overheat_max", 20)
local COOLDOWN_TIME = mesecon.setting("cooldown_time", 2.0)
local COOLDOWN_STEP = mesecon.setting("cooldown_granularity", 0.5)
local COOLDOWN_MULTIPLIER = OVERHEAT_MAX / COOLDOWN_TIME
local cooldown_timer = 0.0
local object_heat = {}
-- returns true if heat is too high -- returns true if heat is too high
mesecon.do_overheat = function(pos) function mesecon.do_overheat(pos)
local meta = minetest.get_meta(pos) local id = minetest.hash_node_position(pos)
local heat = meta:get_int("heat") or 0 local heat = (object_heat[id] or 0) + 1
object_heat[id] = heat
heat = heat + 1 if heat >= OVERHEAT_MAX then
meta:set_int("heat", heat) minetest.log("action", "Node overheats at " .. minetest.pos_to_string(pos))
object_heat[id] = nil
if heat < mesecon.setting("overheat_max", 20) then
mesecon.queue:add_action(pos, "cooldown", {}, 1, nil, 0)
else
return true return true
end end
return false return false
end end
function mesecon.do_cooldown(pos)
local id = minetest.hash_node_position(pos)
object_heat[id] = nil
end
mesecon.queue:add_function("cooldown", function (pos) function mesecon.get_heat(pos)
if minetest.get_item_group(minetest.get_node(pos).name, "overheat") == 0 then local id = minetest.hash_node_position(pos)
return -- node has been moved, this one does not use overheating - ignore return object_heat[id] or 0
end
function mesecon.move_hot_nodes(moved_nodes)
local new_heat = {}
for _, n in ipairs(moved_nodes) do
local old_id = minetest.hash_node_position(n.oldpos)
local new_id = minetest.hash_node_position(n.pos)
new_heat[new_id] = object_heat[old_id]
object_heat[old_id] = nil
end end
for id, heat in pairs(new_heat) do
local meta = minetest.get_meta(pos) object_heat[id] = heat
local heat = meta:get_int("heat")
if (heat > 0) then
meta:set_int("heat", heat - 1)
end end
end) end
local function global_cooldown(dtime)
cooldown_timer = cooldown_timer + dtime
if cooldown_timer < COOLDOWN_STEP then
return -- don't overload the CPU
end
local cooldown = COOLDOWN_MULTIPLIER * cooldown_timer
cooldown_timer = 0
for id, heat in pairs(object_heat) do
heat = heat - cooldown
if heat <= 0 then
object_heat[id] = nil -- free some RAM
else
object_heat[id] = heat
end
end
end
minetest.register_globalstep(global_cooldown)

View File

@ -1,15 +1,15 @@
-- SETTINGS -- SETTINGS
function mesecon.setting(setting, default) function mesecon.setting(setting, default)
if type(default) == "boolean" then if type(default) == "boolean" then
local read = minetest.setting_getbool("mesecon."..setting) local read = minetest.settings:get_bool("mesecon."..setting)
if read == nil then if read == nil then
return default return default
else else
return read return read
end end
elseif type(default) == "string" then elseif type(default) == "string" then
return minetest.setting_get("mesecon."..setting) or default return minetest.settings:get("mesecon."..setting) or default
elseif type(default) == "number" then elseif type(default) == "number" then
return tonumber(minetest.setting_get("mesecon."..setting) or default) return tonumber(minetest.settings:get("mesecon."..setting) or default)
end end
end end

View File

Before

Width:  |  Height:  |  Size: 323 B

After

Width:  |  Height:  |  Size: 323 B

View File

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

Before

Width:  |  Height:  |  Size: 550 B

After

Width:  |  Height:  |  Size: 550 B

View File

Before

Width:  |  Height:  |  Size: 613 B

After

Width:  |  Height:  |  Size: 613 B

View File

@ -6,6 +6,56 @@ function mesecon.move_node(pos, newpos)
minetest.get_meta(pos):from_table(meta) minetest.get_meta(pos):from_table(meta)
end end
-- Rules rotation Functions:
function mesecon.rotate_rules_right(rules)
local nr = {}
for i, rule in ipairs(rules) do
table.insert(nr, {
x = -rule.z,
y = rule.y,
z = rule.x,
name = rule.name})
end
return nr
end
function mesecon.rotate_rules_left(rules)
local nr = {}
for i, rule in ipairs(rules) do
table.insert(nr, {
x = rule.z,
y = rule.y,
z = -rule.x,
name = rule.name})
end
return nr
end
function mesecon.rotate_rules_down(rules)
local nr = {}
for i, rule in ipairs(rules) do
table.insert(nr, {
x = -rule.y,
y = rule.x,
z = rule.z,
name = rule.name})
end
return nr
end
function mesecon.rotate_rules_up(rules)
local nr = {}
for i, rule in ipairs(rules) do
table.insert(nr, {
x = rule.y,
y = -rule.x,
z = rule.z,
name = rule.name})
end
return nr
end
--
function mesecon.flattenrules(allrules) function mesecon.flattenrules(allrules)
--[[ --[[
{ {
@ -178,6 +228,7 @@ end
function mesecon.register_node(name, spec_common, spec_off, spec_on) function mesecon.register_node(name, spec_common, spec_off, spec_on)
spec_common.drop = spec_common.drop or name .. "_off" spec_common.drop = spec_common.drop or name .. "_off"
spec_common.on_blast = spec_common.on_blast or mesecon.on_blastnode
spec_common.__mesecon_basename = name spec_common.__mesecon_basename = name
spec_on.__mesecon_state = "on" spec_on.__mesecon_state = "on"
spec_off.__mesecon_state = "off" spec_off.__mesecon_state = "off"
@ -219,7 +270,7 @@ function mesecon.table2file(filename, table)
f:close() f:close()
end end
-- Forceloading: Force server to load area if node is nil -- Block position "hashing" (convert to integer) functions for voxelmanip cache
local BLOCKSIZE = 16 local BLOCKSIZE = 16
-- convert node position --> block hash -- convert node position --> block hash
@ -231,45 +282,160 @@ local function hash_blockpos(pos)
}) })
end end
-- convert block hash --> node position -- Maps from a hashed mapblock position (as returned by hash_blockpos) to a
local function unhash_blockpos(hash) -- table.
return vector.multiply(minetest.get_position_from_hash(hash), BLOCKSIZE) --
-- Contents of the table are:
-- “vm” → the VoxelManipulator
-- “va” → the VoxelArea
-- “data” → the data array
-- “param1” → the param1 array
-- “param2” → the param2 array
-- “dirty” → true if data has been modified
--
-- Nil if no VM-based transaction is in progress.
local vm_cache = nil
-- Starts a VoxelManipulator-based transaction.
--
-- During a VM transaction, calls to vm_get_node and vm_swap_node operate on a
-- cached copy of the world loaded via VoxelManipulators. That cache can later
-- be committed to the real map by means of vm_commit or discarded by means of
-- vm_abort.
function mesecon.vm_begin()
vm_cache = {}
end end
mesecon.forceloaded_blocks = {} -- Finishes a VoxelManipulator-based transaction, freeing the VMs and map data
-- and writing back any modified areas.
function mesecon.vm_commit()
for hash, tbl in pairs(vm_cache) do
if tbl.dirty then
local vm = tbl.vm
vm:set_data(tbl.data)
vm:write_to_map()
vm:update_map()
end
end
vm_cache = nil
end
-- get node and force-load area -- Finishes a VoxelManipulator-based transaction, freeing the VMs and throwing
function mesecon.get_node_force(pos) -- away any modified areas.
function mesecon.vm_abort()
vm_cache = nil
end
-- Gets the cache entry covering a position, populating it if necessary.
local function vm_get_or_create_entry(pos)
local hash = hash_blockpos(pos) local hash = hash_blockpos(pos)
local tbl = vm_cache[hash]
if mesecon.forceloaded_blocks[hash] == nil then if not tbl then
-- if no more forceload spaces are available, try again next time local vm = minetest.get_voxel_manip(pos, pos)
if minetest.forceload_block(pos) then local min_pos, max_pos = vm:get_emerged_area()
mesecon.forceloaded_blocks[hash] = 0 local va = VoxelArea:new{MinEdge = min_pos, MaxEdge = max_pos}
end tbl = {vm = vm, va = va, data = vm:get_data(), param1 = vm:get_light_data(), param2 = vm:get_param2_data(), dirty = false}
else vm_cache[hash] = tbl
mesecon.forceloaded_blocks[hash] = 0
end end
return tbl
return minetest.get_node_or_nil(pos)
end end
minetest.register_globalstep(function (dtime) -- Gets the node at a given position during a VoxelManipulator-based
for hash, time in pairs(mesecon.forceloaded_blocks) do -- transaction.
-- unload forceloaded blocks after 10 minutes without usage function mesecon.vm_get_node(pos)
if (time > mesecon.setting("forceload_timeout", 600)) then local tbl = vm_get_or_create_entry(pos)
minetest.forceload_free_block(unhash_blockpos(hash)) local index = tbl.va:indexp(pos)
mesecon.forceloaded_blocks[hash] = nil local node_value = tbl.data[index]
else if node_value == core.CONTENT_IGNORE then
mesecon.forceloaded_blocks[hash] = time + dtime return nil
end else
local node_param1 = tbl.param1[index]
local node_param2 = tbl.param2[index]
return {name = minetest.get_name_from_content_id(node_value), param1 = node_param1, param2 = node_param2}
end end
end) end
-- Store and read the forceloaded blocks to / from a file -- Sets a nodes name during a VoxelManipulator-based transaction.
-- so that those blocks are remembered when the game --
-- is restarted -- Existing param1, param2, and metadata are left alone.
mesecon.forceloaded_blocks = mesecon.file2table("mesecon_forceloaded") function mesecon.vm_swap_node(pos, name)
minetest.register_on_shutdown(function() local tbl = vm_get_or_create_entry(pos)
mesecon.table2file("mesecon_forceloaded", mesecon.forceloaded_blocks) local index = tbl.va:indexp(pos)
end) tbl.data[index] = minetest.get_content_id(name)
tbl.dirty = true
end
-- Gets the node at a given position, regardless of whether it is loaded or
-- not, respecting a transaction if one is in progress.
--
-- Outside a VM transaction, if the mapblock is not loaded, it is pulled into
-- the servers main map data cache and then accessed from there.
--
-- Inside a VM transaction, the transactions VM cache is used.
function mesecon.get_node_force(pos)
if vm_cache then
return mesecon.vm_get_node(pos)
else
local node = minetest.get_node_or_nil(pos)
if node == nil then
-- Node is not currently loaded; use a VoxelManipulator to prime
-- the mapblock cache and try again.
minetest.get_voxel_manip(pos, pos)
node = minetest.get_node_or_nil(pos)
end
return node
end
end
-- Swaps the node at a given position, regardless of whether it is loaded or
-- not, respecting a transaction if one is in progress.
--
-- Outside a VM transaction, if the mapblock is not loaded, it is pulled into
-- the servers main map data cache and then accessed from there.
--
-- Inside a VM transaction, the transactions VM cache is used.
--
-- This function can only be used to change the nodes name, not its parameters
-- or metadata.
function mesecon.swap_node_force(pos, name)
if vm_cache then
return mesecon.vm_swap_node(pos, name)
else
-- This serves to both ensure the mapblock is loaded and also hand us
-- the old node table so we can preserve param2.
local node = mesecon.get_node_force(pos)
node.name = name
minetest.swap_node(pos, node)
end
end
-- Autoconnect Hooks
-- Nodes like conductors may change their appearance and their connection rules
-- right after being placed or after being dug, e.g. the default wires use this
-- to automatically connect to linking nodes after placement.
-- After placement, the update function will be executed immediately so that the
-- possibly changed rules can be taken into account when recalculating the circuit.
-- After digging, the update function will be queued and executed after
-- recalculating the circuit. The update function must take care of updating the
-- node at the given position itself, but also all of the other nodes the given
-- position may have (had) a linking connection to.
mesecon.autoconnect_hooks = {}
-- name: A unique name for the hook, e.g. "foowire". Used to name the actionqueue function.
-- fct: The update function with parameters function(pos, node)
function mesecon.register_autoconnect_hook(name, fct)
mesecon.autoconnect_hooks[name] = fct
mesecon.queue:add_function("autoconnect_hook_"..name, fct)
end
function mesecon.execute_autoconnect_hooks_now(pos, node)
for _, fct in pairs(mesecon.autoconnect_hooks) do
fct(pos, node)
end
end
function mesecon.execute_autoconnect_hooks_queue(pos, node)
for name in pairs(mesecon.autoconnect_hooks) do
mesecon.queue:add_action(pos, "autoconnect_hook_"..name, {node})
end
end

View File

@ -24,6 +24,7 @@ mesecon.register_node("mesecons_blinkyplant:blinky_plant", {
drawtype = "plantlike", drawtype = "plantlike",
inventory_image = "jeija_blinky_plant_off.png", inventory_image = "jeija_blinky_plant_off.png",
paramtype = "light", paramtype = "light",
is_ground_content = false,
walkable = false, walkable = false,
sounds = default.node_sound_leaves_defaults(), sounds = default.node_sound_leaves_defaults(),
selection_box = { selection_box = {

View File

@ -4,12 +4,13 @@
mesecon.button_turnoff = function (pos) mesecon.button_turnoff = function (pos)
local node = minetest.get_node(pos) local node = minetest.get_node(pos)
if node.name=="mesecons_button:button_on" then --has not been dug if node.name ~= "mesecons_button:button_on" then -- has been dug
minetest.swap_node(pos, {name = "mesecons_button:button_off", param2=node.param2}) return
minetest.sound_play("mesecons_button_pop", {pos=pos})
local rules = mesecon.rules.buttonlike_get(node)
mesecon.receptor_off(pos, rules)
end end
minetest.swap_node(pos, {name = "mesecons_button:button_off", param2 = node.param2})
minetest.sound_play("mesecons_button_pop", {pos = pos})
local rules = mesecon.rules.buttonlike_get(node)
mesecon.receptor_off(pos, rules)
end end
minetest.register_node("mesecons_button:button_off", { minetest.register_node("mesecons_button:button_off", {
@ -24,8 +25,10 @@ minetest.register_node("mesecons_button:button_off", {
}, },
paramtype = "light", paramtype = "light",
paramtype2 = "facedir", paramtype2 = "facedir",
is_ground_content = false,
legacy_wallmounted = true, legacy_wallmounted = true,
walkable = false, walkable = false,
on_rotate = mesecon.buttonlike_onrotate,
sunlight_propagates = true, sunlight_propagates = true,
selection_box = { selection_box = {
type = "fixed", type = "fixed",
@ -44,13 +47,14 @@ minetest.register_node("mesecons_button:button_off", {
minetest.swap_node(pos, {name = "mesecons_button:button_on", param2=node.param2}) minetest.swap_node(pos, {name = "mesecons_button:button_on", param2=node.param2})
mesecon.receptor_on(pos, mesecon.rules.buttonlike_get(node)) mesecon.receptor_on(pos, mesecon.rules.buttonlike_get(node))
minetest.sound_play("mesecons_button_push", {pos=pos}) minetest.sound_play("mesecons_button_push", {pos=pos})
minetest.after(1, mesecon.button_turnoff, pos) minetest.get_node_timer(pos):start(1)
end, end,
sounds = default.node_sound_stone_defaults(), sounds = default.node_sound_stone_defaults(),
mesecons = {receptor = { mesecons = {receptor = {
state = mesecon.state.off, state = mesecon.state.off,
rules = mesecon.rules.buttonlike_get rules = mesecon.rules.buttonlike_get
}} }},
on_blast = mesecon.on_blastnode,
}) })
minetest.register_node("mesecons_button:button_on", { minetest.register_node("mesecons_button:button_on", {
@ -65,8 +69,10 @@ minetest.register_node("mesecons_button:button_on", {
}, },
paramtype = "light", paramtype = "light",
paramtype2 = "facedir", paramtype2 = "facedir",
is_ground_content = false,
legacy_wallmounted = true, legacy_wallmounted = true,
walkable = false, walkable = false,
on_rotate = false,
light_source = default.LIGHT_MAX-7, light_source = default.LIGHT_MAX-7,
sunlight_propagates = true, sunlight_propagates = true,
selection_box = { selection_box = {
@ -87,7 +93,9 @@ minetest.register_node("mesecons_button:button_on", {
mesecons = {receptor = { mesecons = {receptor = {
state = mesecon.state.on, state = mesecon.state.on,
rules = mesecon.rules.buttonlike_get rules = mesecon.rules.buttonlike_get
}} }},
on_timer = mesecon.button_turnoff,
on_blast = mesecon.on_blastnode,
}) })
minetest.register_craft({ minetest.register_craft({

View File

@ -93,9 +93,22 @@ local function receive_fields(pos, formname, fields, sender)
end end
local function resolve_commands(commands, pos) local function resolve_commands(commands, pos)
local players = minetest.get_connected_players()
-- No players online: remove all commands containing
-- @nearest, @farthest and @random
if #players == 0 then
commands = commands:gsub("[^\r\n]+", function (line)
if line:find("@nearest") then return "" end
if line:find("@farthest") then return "" end
if line:find("@random") then return "" end
return line
end)
return commands
end
local nearest, farthest = nil, nil local nearest, farthest = nil, nil
local min_distance, max_distance = math.huge, -1 local min_distance, max_distance = math.huge, -1
local players = minetest.get_connected_players()
for index, player in pairs(players) do for index, player in pairs(players) do
local distance = vector.distance(pos, player:getpos()) local distance = vector.distance(pos, player:getpos())
if distance < min_distance then if distance < min_distance then
@ -168,6 +181,7 @@ minetest.register_node("mesecons_commandblock:commandblock_off", {
description = "Command Block", description = "Command Block",
tiles = {"jeija_commandblock_off.png"}, tiles = {"jeija_commandblock_off.png"},
inventory_image = minetest.inventorycube("jeija_commandblock_off.png"), inventory_image = minetest.inventorycube("jeija_commandblock_off.png"),
is_ground_content = false,
groups = {cracky=2, mesecon_effector_off=1}, groups = {cracky=2, mesecon_effector_off=1},
on_construct = construct, on_construct = construct,
after_place_node = after_place, after_place_node = after_place,
@ -176,11 +190,13 @@ minetest.register_node("mesecons_commandblock:commandblock_off", {
sounds = default.node_sound_stone_defaults(), sounds = default.node_sound_stone_defaults(),
mesecons = {effector = { mesecons = {effector = {
action_on = commandblock_action_on action_on = commandblock_action_on
}} }},
on_blast = mesecon.on_blastnode,
}) })
minetest.register_node("mesecons_commandblock:commandblock_on", { minetest.register_node("mesecons_commandblock:commandblock_on", {
tiles = {"jeija_commandblock_on.png"}, tiles = {"jeija_commandblock_on.png"},
is_ground_content = false,
groups = {cracky=2, mesecon_effector_on=1, not_in_creative_inventory=1}, groups = {cracky=2, mesecon_effector_on=1, not_in_creative_inventory=1},
light_source = 10, light_source = 10,
drop = "mesecons_commandblock:commandblock_off", drop = "mesecons_commandblock:commandblock_off",
@ -191,5 +207,6 @@ minetest.register_node("mesecons_commandblock:commandblock_on", {
sounds = default.node_sound_stone_defaults(), sounds = default.node_sound_stone_defaults(),
mesecons = {effector = { mesecons = {effector = {
action_off = commandblock_action_off action_off = commandblock_action_off
}} }},
on_blast = mesecon.on_blastnode,
}) })

View File

@ -47,7 +47,8 @@ elseif i == 2 then delaytime = 0.3
elseif i == 3 then delaytime = 0.5 elseif i == 3 then delaytime = 0.5
elseif i == 4 then delaytime = 1.0 end elseif i == 4 then delaytime = 1.0 end
boxes = {{ -6/16, -8/16, -6/16, 6/16, -7/16, 6/16 }, -- the main slab local boxes = {
{ -6/16, -8/16, -6/16, 6/16, -7/16, 6/16 }, -- the main slab
{ -2/16, -7/16, -4/16, 2/16, -26/64, -3/16 }, -- the jeweled "on" indicator { -2/16, -7/16, -4/16, 2/16, -26/64, -3/16 }, -- the jeweled "on" indicator
{ -3/16, -7/16, -3/16, 3/16, -26/64, -2/16 }, { -3/16, -7/16, -3/16, 3/16, -26/64, -2/16 },
@ -57,7 +58,8 @@ boxes = {{ -6/16, -8/16, -6/16, 6/16, -7/16, 6/16 }, -- the main slab
{ -6/16, -7/16, -6/16, -4/16, -27/64, -4/16 }, -- the timer indicator { -6/16, -7/16, -6/16, -4/16, -27/64, -4/16 }, -- the timer indicator
{ -8/16, -8/16, -1/16, -6/16, -7/16, 1/16 }, -- the two wire stubs { -8/16, -8/16, -1/16, -6/16, -7/16, 1/16 }, -- the two wire stubs
{ 6/16, -8/16, -1/16, 8/16, -7/16, 1/16 }} { 6/16, -8/16, -1/16, 8/16, -7/16, 1/16 }
}
minetest.register_node("mesecons_delayer:delayer_off_"..tostring(i), { minetest.register_node("mesecons_delayer:delayer_off_"..tostring(i), {
description = "Delayer", description = "Delayer",
@ -85,7 +87,7 @@ minetest.register_node("mesecons_delayer:delayer_off_"..tostring(i), {
paramtype = "light", paramtype = "light",
paramtype2 = "facedir", paramtype2 = "facedir",
sunlight_propagates = true, sunlight_propagates = true,
is_ground_content = true, is_ground_content = false,
drop = 'mesecons_delayer:delayer_off_1', drop = 'mesecons_delayer:delayer_off_1',
on_punch = function (pos, node) on_punch = function (pos, node)
if node.name=="mesecons_delayer:delayer_off_1" then if node.name=="mesecons_delayer:delayer_off_1" then
@ -112,7 +114,8 @@ minetest.register_node("mesecons_delayer:delayer_off_"..tostring(i), {
rules = delayer_get_input_rules, rules = delayer_get_input_rules,
action_on = delayer_activate action_on = delayer_activate
} }
} },
on_blast = mesecon.on_blastnode,
}) })
@ -140,7 +143,7 @@ minetest.register_node("mesecons_delayer:delayer_on_"..tostring(i), {
paramtype = "light", paramtype = "light",
paramtype2 = "facedir", paramtype2 = "facedir",
sunlight_propagates = true, sunlight_propagates = true,
is_ground_content = true, is_ground_content = false,
drop = 'mesecons_delayer:delayer_off_1', drop = 'mesecons_delayer:delayer_off_1',
on_punch = function (pos, node) on_punch = function (pos, node)
if node.name=="mesecons_delayer:delayer_on_1" then if node.name=="mesecons_delayer:delayer_on_1" then
@ -155,6 +158,7 @@ minetest.register_node("mesecons_delayer:delayer_on_"..tostring(i), {
end, end,
delayer_time = delaytime, delayer_time = delaytime,
delayer_offstate = "mesecons_delayer:delayer_off_"..tostring(i), delayer_offstate = "mesecons_delayer:delayer_off_"..tostring(i),
sounds = default.node_sound_stone_defaults(),
mesecons = { mesecons = {
receptor = receptor =
{ {
@ -166,7 +170,8 @@ minetest.register_node("mesecons_delayer:delayer_on_"..tostring(i), {
rules = delayer_get_input_rules, rules = delayer_get_input_rules,
action_off = delayer_deactivate action_off = delayer_deactivate
} }
} },
on_blast = mesecon.on_blastnode,
}) })
end end

View File

@ -4,3 +4,4 @@ It can also receive digiline signals. You can either send "GET" and it will
respond with the detected nodename or you can send any other string and it will respond with the detected nodename or you can send any other string and it will
set this string as the node to scan for. set this string as the node to scan for.
Nodenames must include the mod they reside in, so for instance default:dirt, not just dirt. Nodenames must include the mod they reside in, so for instance default:dirt, not just dirt.
The distance parameter specifies how many blocks are between the node detector and the node to detect.

View File

@ -1,3 +1,4 @@
The object detector is a receptor. It changes its state when a player approaches. The object detector is a receptor. It changes its state when a player approaches.
Right-click it to set a name to scan for. Right-click it to set a name to scan for.
You can also search for comma-separated lists of players where the detector gets activated if any of the names in the list are found.
It can also receive digiline signals which are the name to scan for on the specified channel in the right-click menu. It can also receive digiline signals which are the name to scan for on the specified channel in the right-click menu.

View File

@ -5,15 +5,18 @@ local GET_COMMAND = "GET"
-- The radius can be specified in mesecons/settings.lua -- The radius can be specified in mesecons/settings.lua
local function object_detector_make_formspec(pos) local function object_detector_make_formspec(pos)
minetest.get_meta(pos):set_string("formspec", "size[9,2.5]" .. local meta = minetest.get_meta(pos)
meta:set_string("formspec", "size[9,2.5]" ..
"field[0.3, 0;9,2;scanname;Name of player to scan for (empty for any):;${scanname}]".. "field[0.3, 0;9,2;scanname;Name of player to scan for (empty for any):;${scanname}]"..
"field[0.3,1.5;4,2;digiline_channel;Digiline Channel (optional):;${digiline_channel}]".. "field[0.3,1.5;4,2;digiline_channel;Digiline Channel (optional):;${digiline_channel}]"..
"button_exit[7,0.75;2,3;;Save]") "button_exit[7,0.75;2,3;;Save]")
end end
local function object_detector_on_receive_fields(pos, _, fields) local function object_detector_on_receive_fields(pos, formname, fields, sender)
if not fields.scanname or not fields.digiline_channel then return end if not fields.scanname or not fields.digiline_channel then return end
if minetest.is_protected(pos, sender:get_player_name()) then return end
local meta = minetest.get_meta(pos) local meta = minetest.get_meta(pos)
meta:set_string("scanname", fields.scanname) meta:set_string("scanname", fields.scanname)
meta:set_string("digiline_channel", fields.digiline_channel) meta:set_string("digiline_channel", fields.digiline_channel)
@ -28,14 +31,17 @@ local function object_detector_scan(pos)
if next(objs) == nil then return false end if next(objs) == nil then return false end
local scanname = minetest.get_meta(pos):get_string("scanname") local scanname = minetest.get_meta(pos):get_string("scanname")
local scan_for = {}
for _, str in pairs(string.split(scanname:gsub(" ", ""), ",")) do
scan_for[str] = true
end
local every_player = scanname == "" local every_player = scanname == ""
for _, obj in pairs(objs) do for _, obj in pairs(objs) do
-- "" is returned if it is not a player; "" ~= nil; so only handle objects with foundname ~= "" -- "" is returned if it is not a player; "" ~= nil; so only handle objects with foundname ~= ""
local foundname = obj:get_player_name() local foundname = obj:get_player_name()
if foundname ~= "" then if foundname ~= "" then
-- return true if scanning for any player or if specific playername was detected if every_player or scan_for[foundname] then
if scanname == "" or foundname == scanname then
return true return true
end end
end end
@ -60,6 +66,7 @@ local object_detector_digiline = {
minetest.register_node("mesecons_detector:object_detector_off", { minetest.register_node("mesecons_detector:object_detector_off", {
tiles = {"default_steel_block.png", "default_steel_block.png", "jeija_object_detector_off.png", "jeija_object_detector_off.png", "jeija_object_detector_off.png", "jeija_object_detector_off.png"}, tiles = {"default_steel_block.png", "default_steel_block.png", "jeija_object_detector_off.png", "jeija_object_detector_off.png", "jeija_object_detector_off.png", "jeija_object_detector_off.png"},
paramtype = "light", paramtype = "light",
is_ground_content = false,
walkable = true, walkable = true,
groups = {cracky=3}, groups = {cracky=3},
description="Player Detector", description="Player Detector",
@ -70,12 +77,14 @@ minetest.register_node("mesecons_detector:object_detector_off", {
on_construct = object_detector_make_formspec, on_construct = object_detector_make_formspec,
on_receive_fields = object_detector_on_receive_fields, on_receive_fields = object_detector_on_receive_fields,
sounds = default.node_sound_stone_defaults(), sounds = default.node_sound_stone_defaults(),
digiline = object_detector_digiline digiline = object_detector_digiline,
on_blast = mesecon.on_blastnode,
}) })
minetest.register_node("mesecons_detector:object_detector_on", { minetest.register_node("mesecons_detector:object_detector_on", {
tiles = {"default_steel_block.png", "default_steel_block.png", "jeija_object_detector_on.png", "jeija_object_detector_on.png", "jeija_object_detector_on.png", "jeija_object_detector_on.png"}, tiles = {"default_steel_block.png", "default_steel_block.png", "jeija_object_detector_on.png", "jeija_object_detector_on.png", "jeija_object_detector_on.png", "jeija_object_detector_on.png"},
paramtype = "light", paramtype = "light",
is_ground_content = false,
walkable = true, walkable = true,
groups = {cracky=3,not_in_creative_inventory=1}, groups = {cracky=3,not_in_creative_inventory=1},
drop = 'mesecons_detector:object_detector_off', drop = 'mesecons_detector:object_detector_off',
@ -86,7 +95,8 @@ minetest.register_node("mesecons_detector:object_detector_on", {
on_construct = object_detector_make_formspec, on_construct = object_detector_make_formspec,
on_receive_fields = object_detector_on_receive_fields, on_receive_fields = object_detector_on_receive_fields,
sounds = default.node_sound_stone_defaults(), sounds = default.node_sound_stone_defaults(),
digiline = object_detector_digiline digiline = object_detector_digiline,
on_blast = mesecon.on_blastnode,
}) })
minetest.register_craft({ minetest.register_craft({
@ -98,6 +108,15 @@ minetest.register_craft({
} }
}) })
minetest.register_craft({
output = 'mesecons_detector:object_detector_off',
recipe = {
{"default:steel_ingot", "default:steel_ingot", "default:steel_ingot"},
{"default:steel_ingot", "mesecons_microcontroller:microcontroller0000", "default:steel_ingot"},
{"default:steel_ingot", "group:mesecon_conductor_craftable", "default:steel_ingot"},
}
})
minetest.register_abm({ minetest.register_abm({
nodenames = {"mesecons_detector:object_detector_off"}, nodenames = {"mesecons_detector:object_detector_off"},
interval = 1, interval = 1,
@ -128,17 +147,23 @@ minetest.register_abm({
-- Detects the node in front of it -- Detects the node in front of it
local function node_detector_make_formspec(pos) local function node_detector_make_formspec(pos)
minetest.get_meta(pos):set_string("formspec", "size[9,2.5]" .. local meta = minetest.get_meta(pos)
if meta:get_string("distance") == "" then meta:set_string("distance", "0") end
meta:set_string("formspec", "size[9,2.5]" ..
"field[0.3, 0;9,2;scanname;Name of node to scan for (empty for any):;${scanname}]".. "field[0.3, 0;9,2;scanname;Name of node to scan for (empty for any):;${scanname}]"..
"field[0.3,1.5;4,2;digiline_channel;Digiline Channel (optional):;${digiline_channel}]".. "field[0.3,1.5;2.5,2;distance;Distance (0-"..mesecon.setting("node_detector_distance_max", 10).."):;${distance}]"..
"field[3,1.5;4,2;digiline_channel;Digiline Channel (optional):;${digiline_channel}]"..
"button_exit[7,0.75;2,3;;Save]") "button_exit[7,0.75;2,3;;Save]")
end end
local function node_detector_on_receive_fields(pos, _, fields) local function node_detector_on_receive_fields(pos, fieldname, fields, sender)
if not fields.scanname or not fields.digiline_channel then return end if not fields.scanname or not fields.digiline_channel then return end
if minetest.is_protected(pos, sender:get_player_name()) then return end
local meta = minetest.get_meta(pos) local meta = minetest.get_meta(pos)
meta:set_string("scanname", fields.scanname) meta:set_string("scanname", fields.scanname)
meta:set_string("distance", fields.distance or "0")
meta:set_string("digiline_channel", fields.digiline_channel) meta:set_string("digiline_channel", fields.digiline_channel)
node_detector_make_formspec(pos) node_detector_make_formspec(pos)
end end
@ -148,10 +173,17 @@ local function node_detector_scan(pos)
local node = minetest.get_node_or_nil(pos) local node = minetest.get_node_or_nil(pos)
if not node then return end if not node then return end
local meta = minetest.get_meta(pos)
local distance = meta:get_int("distance")
local distance_max = mesecon.setting("node_detector_distance_max", 10)
if distance < 0 then distance = 0 end
if distance > distance_max then distance = distance_max end
local frontname = minetest.get_node( local frontname = minetest.get_node(
vector.subtract(pos, minetest.facedir_to_dir(node.param2)) vector.subtract(pos, vector.multiply(minetest.facedir_to_dir(node.param2), distance + 1))
).name ).name
local scanname = minetest.get_meta(pos):get_string("scanname") local scanname = meta:get_string("scanname")
return (frontname == scanname) or return (frontname == scanname) or
(frontname ~= "air" and frontname ~= "ignore" and scanname == "") (frontname ~= "air" and frontname ~= "ignore" and scanname == "")
@ -162,11 +194,17 @@ local node_detector_digiline = {
effector = { effector = {
action = function(pos, node, channel, msg) action = function(pos, node, channel, msg)
local meta = minetest.get_meta(pos) local meta = minetest.get_meta(pos)
local distance = meta:get_int("distance")
local distance_max = mesecon.setting("node_detector_distance_max", 10)
if distance < 0 then distance = 0 end
if distance > distance_max then distance = distance_max end
if channel ~= meta:get_string("digiline_channel") then return end if channel ~= meta:get_string("digiline_channel") then return end
if msg == GET_COMMAND then if msg == GET_COMMAND then
local nodename = minetest.get_node( local nodename = minetest.get_node(
vector.subtract(pos, minetest.facedir_to_dir(node.param2)) vector.subtract(pos, vector.multiply(minetest.facedir_to_dir(node.param2), distance + 1))
).name ).name
digiline:receptor_send(pos, digiline.rules.default, channel, nodename) digiline:receptor_send(pos, digiline.rules.default, channel, nodename)
@ -200,6 +238,7 @@ minetest.register_node("mesecons_detector:node_detector_off", {
tiles = {"default_steel_block.png", "default_steel_block.png", "default_steel_block.png", "default_steel_block.png", "default_steel_block.png", "jeija_node_detector_off.png"}, tiles = {"default_steel_block.png", "default_steel_block.png", "default_steel_block.png", "default_steel_block.png", "default_steel_block.png", "jeija_node_detector_off.png"},
paramtype = "light", paramtype = "light",
paramtype2 = "facedir", paramtype2 = "facedir",
is_ground_content = false,
walkable = true, walkable = true,
groups = {cracky=3}, groups = {cracky=3},
description="Node Detector", description="Node Detector",
@ -208,15 +247,16 @@ minetest.register_node("mesecons_detector:node_detector_off", {
}}, }},
on_construct = node_detector_make_formspec, on_construct = node_detector_make_formspec,
on_receive_fields = node_detector_on_receive_fields, on_receive_fields = node_detector_on_receive_fields,
after_place_node = after_place_node_detector,
sounds = default.node_sound_stone_defaults(), sounds = default.node_sound_stone_defaults(),
digiline = node_detector_digiline digiline = node_detector_digiline,
on_blast = mesecon.on_blastnode,
}) })
minetest.register_node("mesecons_detector:node_detector_on", { minetest.register_node("mesecons_detector:node_detector_on", {
tiles = {"default_steel_block.png", "default_steel_block.png", "default_steel_block.png", "default_steel_block.png", "default_steel_block.png", "jeija_node_detector_on.png"}, tiles = {"default_steel_block.png", "default_steel_block.png", "default_steel_block.png", "default_steel_block.png", "default_steel_block.png", "jeija_node_detector_on.png"},
paramtype = "light", paramtype = "light",
paramtype2 = "facedir", paramtype2 = "facedir",
is_ground_content = false,
walkable = true, walkable = true,
groups = {cracky=3,not_in_creative_inventory=1}, groups = {cracky=3,not_in_creative_inventory=1},
drop = 'mesecons_detector:node_detector_off', drop = 'mesecons_detector:node_detector_off',
@ -225,9 +265,9 @@ minetest.register_node("mesecons_detector:node_detector_on", {
}}, }},
on_construct = node_detector_make_formspec, on_construct = node_detector_make_formspec,
on_receive_fields = node_detector_on_receive_fields, on_receive_fields = node_detector_on_receive_fields,
after_place_node = after_place_node_detector,
sounds = default.node_sound_stone_defaults(), sounds = default.node_sound_stone_defaults(),
digiline = node_detector_digiline digiline = node_detector_digiline,
on_blast = mesecon.on_blastnode,
}) })
minetest.register_craft({ minetest.register_craft({
@ -239,6 +279,15 @@ minetest.register_craft({
} }
}) })
minetest.register_craft({
output = 'mesecons_detector:node_detector_off',
recipe = {
{"default:steel_ingot", "group:mesecon_conductor_craftable", "default:steel_ingot"},
{"default:steel_ingot", "mesecons_microcontroller:microcontroller0000", "default:steel_ingot"},
{"default:steel_ingot", "default:steel_ingot", "default:steel_ingot"},
}
})
minetest.register_abm({ minetest.register_abm({
nodenames = {"mesecons_detector:node_detector_off"}, nodenames = {"mesecons_detector:node_detector_off"},
interval = 1, interval = 1,

View File

@ -1,3 +1,5 @@
local screwdriver_exists = minetest.global_exists("screwdriver")
local corner_nodebox = { local corner_nodebox = {
type = "fixed", type = "fixed",
fixed = {{ -16/32-0.001, -17/32, -3/32, 0, -13/32, 3/32 }, fixed = {{ -16/32-0.001, -17/32, -3/32, 0, -13/32, 3/32 },
@ -33,23 +35,27 @@ minetest.register_node("mesecons_extrawires:corner_on", {
}, },
paramtype = "light", paramtype = "light",
paramtype2 = "facedir", paramtype2 = "facedir",
is_ground_content = false,
walkable = false, walkable = false,
sunlight_propagates = true, sunlight_propagates = true,
selection_box = corner_selectionbox, selection_box = corner_selectionbox,
node_box = corner_nodebox, node_box = corner_nodebox,
groups = {dig_immediate = 3, not_in_creative_inventory = 1}, groups = {dig_immediate = 3, not_in_creative_inventory = 1},
drop = "mesecons_extrawires:corner_off", drop = "mesecons_extrawires:corner_off",
sounds = default.node_sound_defaults(),
mesecons = {conductor = mesecons = {conductor =
{ {
state = mesecon.state.on, state = mesecon.state.on,
rules = corner_get_rules, rules = corner_get_rules,
offstate = "mesecons_extrawires:corner_off" offstate = "mesecons_extrawires:corner_off"
}} }},
on_blast = mesecon.on_blastnode,
on_rotate = screwdriver_exists and screwdriver.rotate_simple,
}) })
minetest.register_node("mesecons_extrawires:corner_off", { minetest.register_node("mesecons_extrawires:corner_off", {
drawtype = "nodebox", drawtype = "nodebox",
description = "Mesecon Corner", description = "Insulated Mesecon Corner",
tiles = { tiles = {
"jeija_insulated_wire_curved_tb_off.png", "jeija_insulated_wire_curved_tb_off.png",
"jeija_insulated_wire_curved_tb_off.png^[transformR270", "jeija_insulated_wire_curved_tb_off.png^[transformR270",
@ -60,17 +66,21 @@ minetest.register_node("mesecons_extrawires:corner_off", {
}, },
paramtype = "light", paramtype = "light",
paramtype2 = "facedir", paramtype2 = "facedir",
is_ground_content = false,
walkable = false, walkable = false,
sunlight_propagates = true, sunlight_propagates = true,
selection_box = corner_selectionbox, selection_box = corner_selectionbox,
node_box = corner_nodebox, node_box = corner_nodebox,
groups = {dig_immediate = 3}, groups = {dig_immediate = 3},
sounds = default.node_sound_defaults(),
mesecons = {conductor = mesecons = {conductor =
{ {
state = mesecon.state.off, state = mesecon.state.off,
rules = corner_get_rules, rules = corner_get_rules,
onstate = "mesecons_extrawires:corner_on" onstate = "mesecons_extrawires:corner_on"
}} }},
on_blast = mesecon.on_blastnode,
on_rotate = screwdriver_exists and screwdriver.rotate_simple,
}) })
minetest.register_craft({ minetest.register_craft({

View File

@ -1,4 +1,4 @@
function crossover_get_rules(node) local function crossover_get_rules(node)
return { return {
{--first wire {--first wire
{x=-1,y=0,z=0}, {x=-1,y=0,z=0},
@ -19,143 +19,110 @@ local crossover_states = {
} }
minetest.register_node("mesecons_extrawires:crossover_off", { minetest.register_node("mesecons_extrawires:crossover_off", {
description = "Insulated Crossover", description = "Insulated Mesecon Crossover",
drawtype = "nodebox", drawtype = "mesh",
mesh = "mesecons_extrawires_crossover.b3d",
tiles = { tiles = {
"jeija_insulated_wire_crossing_tb_off.png", "jeija_insulated_wire_ends_off.png",
"jeija_insulated_wire_crossing_tb_off.png", "jeija_insulated_wire_sides_off.png",
"jeija_insulated_wire_sides_off.png",
"jeija_insulated_wire_ends_off.png" "jeija_insulated_wire_ends_off.png"
}, },
paramtype = "light", paramtype = "light",
is_ground_content = false,
walkable = false, walkable = false,
stack_max = 99, stack_max = 99,
selection_box = {type="fixed", fixed={-16/32-0.0001, -18/32, -16/32-0.001, 16/32+0.001, -5/32, 16/32+0.001}}, selection_box = {type="fixed", fixed={-16/32-0.0001, -18/32, -16/32-0.001, 16/32+0.001, -5/32, 16/32+0.001}},
node_box = {
type = "fixed",
fixed = {
{ -16/32-0.001, -17/32, -3/32, 16/32+0.001, -13/32, 3/32 },
{ -3/32, -17/32, -16/32-0.001, 3/32, -13/32, -6/32 },
{ -3/32, -13/32, -9/32, 3/32, -6/32, -6/32 },
{ -3/32, -9/32, -9/32, 3/32, -6/32, 9/32 },
{ -3/32, -13/32, 6/32, 3/32, -6/32, 9/32 },
{ -3/32, -17/32, 6/32, 3/32, -13/32, 16/32+0.001 },
},
},
groups = {dig_immediate=3, mesecon=3}, groups = {dig_immediate=3, mesecon=3},
sounds = default.node_sound_defaults(),
mesecons = { mesecons = {
conductor = { conductor = {
states = crossover_states, states = crossover_states,
rules = crossover_get_rules(), rules = crossover_get_rules(),
} }
}, },
on_blast = mesecon.on_blastnode,
}) })
minetest.register_node("mesecons_extrawires:crossover_01", { minetest.register_node("mesecons_extrawires:crossover_01", {
description = "You hacker you!", description = "You hacker you!",
drop = "mesecons_extrawires:crossover_off", drop = "mesecons_extrawires:crossover_off",
drawtype = "nodebox", drawtype = "mesh",
mesh = "mesecons_extrawires_crossover.b3d",
tiles = { tiles = {
"jeija_insulated_wire_crossing_tb_01.png", "jeija_insulated_wire_ends_on.png",
"jeija_insulated_wire_crossing_tb_01.png", "jeija_insulated_wire_sides_on.png",
"jeija_insulated_wire_ends_01x.png", "jeija_insulated_wire_sides_off.png",
"jeija_insulated_wire_ends_01x.png", "jeija_insulated_wire_ends_off.png"
"jeija_insulated_wire_ends_01z.png",
"jeija_insulated_wire_ends_01z.png"
}, },
paramtype = "light", paramtype = "light",
is_ground_content = false,
walkable = false, walkable = false,
stack_max = 99, stack_max = 99,
selection_box = {type="fixed", fixed={-16/32-0.0001, -18/32, -16/32-0.001, 16/32+0.001, -5/32, 16/32+0.001}}, selection_box = {type="fixed", fixed={-16/32-0.0001, -18/32, -16/32-0.001, 16/32+0.001, -5/32, 16/32+0.001}},
node_box = {
type = "fixed",
fixed = {
{ -16/32-0.001, -17/32, -3/32, 16/32+0.001, -13/32, 3/32 },
{ -3/32, -17/32, -16/32-0.001, 3/32, -13/32, -6/32 },
{ -3/32, -13/32, -9/32, 3/32, -6/32, -6/32 },
{ -3/32, -9/32, -9/32, 3/32, -6/32, 9/32 },
{ -3/32, -13/32, 6/32, 3/32, -6/32, 9/32 },
{ -3/32, -17/32, 6/32, 3/32, -13/32, 16/32+0.001 },
},
},
groups = {dig_immediate=3, mesecon=3, not_in_creative_inventory=1}, groups = {dig_immediate=3, mesecon=3, not_in_creative_inventory=1},
sounds = default.node_sound_defaults(),
mesecons = { mesecons = {
conductor = { conductor = {
states = crossover_states, states = crossover_states,
rules = crossover_get_rules(), rules = crossover_get_rules(),
} }
}, },
on_blast = mesecon.on_blastnode,
}) })
minetest.register_node("mesecons_extrawires:crossover_10", { minetest.register_node("mesecons_extrawires:crossover_10", {
description = "You hacker you!", description = "You hacker you!",
drop = "mesecons_extrawires:crossover_off", drop = "mesecons_extrawires:crossover_off",
drawtype = "nodebox", drawtype = "mesh",
mesh = "mesecons_extrawires_crossover.b3d",
tiles = { tiles = {
"jeija_insulated_wire_crossing_tb_10.png", "jeija_insulated_wire_ends_off.png",
"jeija_insulated_wire_crossing_tb_10.png", "jeija_insulated_wire_sides_off.png",
"jeija_insulated_wire_ends_10x.png", "jeija_insulated_wire_sides_on.png",
"jeija_insulated_wire_ends_10x.png", "jeija_insulated_wire_ends_on.png"
"jeija_insulated_wire_ends_10z.png",
"jeija_insulated_wire_ends_10z.png"
}, },
paramtype = "light", paramtype = "light",
is_ground_content = false,
walkable = false, walkable = false,
stack_max = 99, stack_max = 99,
selection_box = {type="fixed", fixed={-16/32-0.0001, -18/32, -16/32-0.001, 16/32+0.001, -5/32, 16/32+0.001}}, selection_box = {type="fixed", fixed={-16/32-0.0001, -18/32, -16/32-0.001, 16/32+0.001, -5/32, 16/32+0.001}},
node_box = {
type = "fixed",
fixed = {
{ -16/32-0.001, -17/32, -3/32, 16/32+0.001, -13/32, 3/32 },
{ -3/32, -17/32, -16/32-0.001, 3/32, -13/32, -6/32 },
{ -3/32, -13/32, -9/32, 3/32, -6/32, -6/32 },
{ -3/32, -9/32, -9/32, 3/32, -6/32, 9/32 },
{ -3/32, -13/32, 6/32, 3/32, -6/32, 9/32 },
{ -3/32, -17/32, 6/32, 3/32, -13/32, 16/32+0.001 },
},
},
groups = {dig_immediate=3, mesecon=3, not_in_creative_inventory=1}, groups = {dig_immediate=3, mesecon=3, not_in_creative_inventory=1},
sounds = default.node_sound_defaults(),
mesecons = { mesecons = {
conductor = { conductor = {
states = crossover_states, states = crossover_states,
rules = crossover_get_rules(), rules = crossover_get_rules(),
} }
}, },
on_blast = mesecon.on_blastnode,
}) })
minetest.register_node("mesecons_extrawires:crossover_on", { minetest.register_node("mesecons_extrawires:crossover_on", {
description = "You hacker you!", description = "You hacker you!",
drop = "mesecons_extrawires:crossover_off", drop = "mesecons_extrawires:crossover_off",
drawtype = "nodebox", drawtype = "mesh",
mesh = "mesecons_extrawires_crossover.b3d",
tiles = { tiles = {
"jeija_insulated_wire_crossing_tb_on.png",
"jeija_insulated_wire_crossing_tb_on.png",
"jeija_insulated_wire_ends_on.png",
"jeija_insulated_wire_ends_on.png",
"jeija_insulated_wire_ends_on.png", "jeija_insulated_wire_ends_on.png",
"jeija_insulated_wire_sides_on.png",
"jeija_insulated_wire_sides_on.png",
"jeija_insulated_wire_ends_on.png" "jeija_insulated_wire_ends_on.png"
}, },
paramtype = "light", paramtype = "light",
is_ground_content = false,
walkable = false, walkable = false,
stack_max = 99, stack_max = 99,
selection_box = {type="fixed", fixed={-16/32-0.0001, -18/32, -16/32-0.001, 16/32+0.001, -5/32, 16/32+0.001}}, selection_box = {type="fixed", fixed={-16/32-0.0001, -18/32, -16/32-0.001, 16/32+0.001, -5/32, 16/32+0.001}},
node_box = {
type = "fixed",
fixed = {
{ -16/32-0.001, -17/32, -3/32, 16/32+0.001, -13/32, 3/32 },
{ -3/32, -17/32, -16/32-0.001, 3/32, -13/32, -6/32 },
{ -3/32, -13/32, -9/32, 3/32, -6/32, -6/32 },
{ -3/32, -9/32, -9/32, 3/32, -6/32, 9/32 },
{ -3/32, -13/32, 6/32, 3/32, -6/32, 9/32 },
{ -3/32, -17/32, 6/32, 3/32, -13/32, 16/32+0.001 },
},
},
groups = {dig_immediate=3, mesecon=3, not_in_creative_inventory=1}, groups = {dig_immediate=3, mesecon=3, not_in_creative_inventory=1},
sounds = default.node_sound_defaults(),
mesecons = { mesecons = {
conductor = { conductor = {
states = crossover_states, states = crossover_states,
rules = crossover_get_rules(), rules = crossover_get_rules(),
} }
}, },
on_blast = mesecon.on_blastnode,
}) })
minetest.register_craft({ minetest.register_craft({

View File

@ -1,2 +1,3 @@
default default
mesecons mesecons
screwdriver?

View File

@ -26,7 +26,8 @@ local powered_def = mesecon.mergetable(minetest.registered_nodes["default:mese"]
offstate = "default:mese", offstate = "default:mese",
rules = mesewire_rules rules = mesewire_rules
}}, }},
groups = {cracky = 1, not_in_creative_inventory = 1} groups = {cracky = 1, not_in_creative_inventory = 1},
on_blast = mesecon.on_blastnode,
}) })
for i, v in pairs(powered_def.tiles) do for i, v in pairs(powered_def.tiles) do

View File

@ -1,3 +1,5 @@
local screwdriver_exists = minetest.global_exists("screwdriver")
local tjunction_nodebox = { local tjunction_nodebox = {
type = "fixed", type = "fixed",
fixed = {{ -16/32-0.001, -17/32, -3/32, 16/32+0.001, -13/32, 3/32 }, fixed = {{ -16/32-0.001, -17/32, -3/32, 16/32+0.001, -13/32, 3/32 },
@ -34,23 +36,27 @@ minetest.register_node("mesecons_extrawires:tjunction_on", {
}, },
paramtype = "light", paramtype = "light",
paramtype2 = "facedir", paramtype2 = "facedir",
is_ground_content = false,
walkable = false, walkable = false,
sunlight_propagates = true, sunlight_propagates = true,
selection_box = tjunction_selectionbox, selection_box = tjunction_selectionbox,
node_box = tjunction_nodebox, node_box = tjunction_nodebox,
groups = {dig_immediate = 3, not_in_creative_inventory = 1}, groups = {dig_immediate = 3, not_in_creative_inventory = 1},
drop = "mesecons_extrawires:tjunction_off", drop = "mesecons_extrawires:tjunction_off",
sounds = default.node_sound_defaults(),
mesecons = {conductor = mesecons = {conductor =
{ {
state = mesecon.state.on, state = mesecon.state.on,
rules = tjunction_get_rules, rules = tjunction_get_rules,
offstate = "mesecons_extrawires:tjunction_off" offstate = "mesecons_extrawires:tjunction_off"
}} }},
on_blast = mesecon.on_blastnode,
on_rotate = screwdriver_exists and screwdriver.rotate_simple,
}) })
minetest.register_node("mesecons_extrawires:tjunction_off", { minetest.register_node("mesecons_extrawires:tjunction_off", {
drawtype = "nodebox", drawtype = "nodebox",
description = "T-junction", description = "Insulated Mesecon T-junction",
tiles = { tiles = {
"jeija_insulated_wire_tjunction_tb_off.png", "jeija_insulated_wire_tjunction_tb_off.png",
"jeija_insulated_wire_tjunction_tb_off.png^[transformR180", "jeija_insulated_wire_tjunction_tb_off.png^[transformR180",
@ -61,17 +67,21 @@ minetest.register_node("mesecons_extrawires:tjunction_off", {
}, },
paramtype = "light", paramtype = "light",
paramtype2 = "facedir", paramtype2 = "facedir",
is_ground_content = false,
walkable = false, walkable = false,
sunlight_propagates = true, sunlight_propagates = true,
selection_box = tjunction_selectionbox, selection_box = tjunction_selectionbox,
node_box = tjunction_nodebox, node_box = tjunction_nodebox,
groups = {dig_immediate = 3}, groups = {dig_immediate = 3},
sounds = default.node_sound_defaults(),
mesecons = {conductor = mesecons = {conductor =
{ {
state = mesecon.state.off, state = mesecon.state.off,
rules = tjunction_get_rules, rules = tjunction_get_rules,
onstate = "mesecons_extrawires:tjunction_on" onstate = "mesecons_extrawires:tjunction_on"
}} }},
on_blast = mesecon.on_blastnode,
on_rotate = screwdriver_exists and screwdriver.rotate_simple,
}) })
minetest.register_craft({ minetest.register_craft({

View File

@ -77,17 +77,19 @@ end
-- Vertical wire -- Vertical wire
mesecon.register_node("mesecons_extrawires:vertical", { mesecon.register_node("mesecons_extrawires:vertical", {
description = "Vertical mesecon", description = "Vertical Mesecon",
drawtype = "nodebox", drawtype = "nodebox",
walkable = false, walkable = false,
paramtype = "light", paramtype = "light",
is_ground_content = false,
sunlight_propagates = true, sunlight_propagates = true,
selection_box = vertical_box, selection_box = vertical_box,
node_box = vertical_box, node_box = vertical_box,
is_vertical_conductor = true, is_vertical_conductor = true,
drop = "mesecons_extrawires:vertical_off", drop = "mesecons_extrawires:vertical_off",
after_place_node = vertical_update, after_place_node = vertical_update,
after_dig_node = vertical_update after_dig_node = vertical_update,
sounds = default.node_sound_defaults(),
},{ },{
tiles = {"mesecons_wire_off.png"}, tiles = {"mesecons_wire_off.png"},
groups = {dig_immediate=3}, groups = {dig_immediate=3},
@ -112,6 +114,7 @@ mesecon.register_node("mesecons_extrawires:vertical_top", {
drawtype = "nodebox", drawtype = "nodebox",
walkable = false, walkable = false,
paramtype = "light", paramtype = "light",
is_ground_content = false,
sunlight_propagates = true, sunlight_propagates = true,
groups = {dig_immediate=3, not_in_creative_inventory=1}, groups = {dig_immediate=3, not_in_creative_inventory=1},
selection_box = top_box, selection_box = top_box,
@ -119,7 +122,8 @@ mesecon.register_node("mesecons_extrawires:vertical_top", {
is_vertical_conductor = true, is_vertical_conductor = true,
drop = "mesecons_extrawires:vertical_off", drop = "mesecons_extrawires:vertical_off",
after_place_node = vertical_update, after_place_node = vertical_update,
after_dig_node = vertical_update after_dig_node = vertical_update,
sounds = default.node_sound_defaults(),
},{ },{
tiles = {"mesecons_wire_off.png"}, tiles = {"mesecons_wire_off.png"},
mesecons = {conductor = { mesecons = {conductor = {
@ -142,6 +146,7 @@ mesecon.register_node("mesecons_extrawires:vertical_bottom", {
drawtype = "nodebox", drawtype = "nodebox",
walkable = false, walkable = false,
paramtype = "light", paramtype = "light",
is_ground_content = false,
sunlight_propagates = true, sunlight_propagates = true,
groups = {dig_immediate = 3, not_in_creative_inventory = 1}, groups = {dig_immediate = 3, not_in_creative_inventory = 1},
selection_box = bottom_box, selection_box = bottom_box,
@ -149,7 +154,8 @@ mesecon.register_node("mesecons_extrawires:vertical_bottom", {
is_vertical_conductor = true, is_vertical_conductor = true,
drop = "mesecons_extrawires:vertical_off", drop = "mesecons_extrawires:vertical_off",
after_place_node = vertical_update, after_place_node = vertical_update,
after_dig_node = vertical_update after_dig_node = vertical_update,
sounds = default.node_sound_defaults(),
},{ },{
tiles = {"mesecons_wire_off.png"}, tiles = {"mesecons_wire_off.png"},
mesecons = {conductor = { mesecons = {conductor = {

View File

@ -0,0 +1,2 @@
mesecons
screwdriver?

View File

@ -0,0 +1,5 @@
FPGAs can be used to chain multiple logic gates together in a compact manner.
They come with 4 I/O ports and 10 internal registers,
which can then be connected with eachother to form logic circuits.<br />
Supported gate types: <b>AND</b>, <b>OR</b>, <b>NOT</b>, <b>XOR</b>, <b>NAND</b>, <b>XNOR</b>, <b>Buffer</b> (=)<br />
I/O ports: <b>A B C D</b>; Registers: numbered <b>0</b> to <b>9</b>

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

View File

@ -0,0 +1,3 @@
The FPGA programmer can be used to copy gate configurations from one FPGA to another.<br />
Shift+Right-Click an FPGA to read its configuration and "remember" it.
Left-click (punch) FPGAs to write the saved configuration to them.

Binary file not shown.

After

Width:  |  Height:  |  Size: 598 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

420
mesecons_fpga/init.lua Normal file
View File

@ -0,0 +1,420 @@
local plg = {}
plg.rules = {}
local lcore = dofile(minetest.get_modpath(minetest.get_current_modname()) .. "/logic.lua")
dofile(minetest.get_modpath(minetest.get_current_modname()) .. "/tool.lua")(plg)
plg.register_nodes = function(template)
-- each loop is for one of the 4 IO ports
for a = 0, 1 do
for b = 0, 1 do
for c = 0, 1 do
for d = 0, 1 do
local ndef = table.copy(template)
local nodename = "mesecons_fpga:fpga"
.. tostring(d) .. tostring(c) .. tostring(b) .. tostring(a)
-- build top texture string
local texture = "jeija_fpga_top.png"
if a == 1 then texture = texture .. "^jeija_microcontroller_LED_A.png" end
if b == 1 then texture = texture .. "^jeija_microcontroller_LED_B.png" end
if c == 1 then texture = texture .. "^jeija_microcontroller_LED_C.png" end
if d == 1 then texture = texture .. "^jeija_microcontroller_LED_D.png" end
ndef.tiles[1] = texture
ndef.inventory_image = texture
if (a + b + c + d) > 0 then
ndef.groups["not_in_creative_inventory"] = 1
end
-- interaction with mesecons (input / output)
local rules_out = {}
if a == 1 then table.insert(rules_out, {x = -1, y = 0, z = 0}) end
if b == 1 then table.insert(rules_out, {x = 0, y = 0, z = 1}) end
if c == 1 then table.insert(rules_out, {x = 1, y = 0, z = 0}) end
if d == 1 then table.insert(rules_out, {x = 0, y = 0, z = -1}) end
plg.rules[nodename] = rules_out
local rules_in = {}
if a == 0 then table.insert(rules_in, {x = -1, y = 0, z = 0}) end
if b == 0 then table.insert(rules_in, {x = 0, y = 0, z = 1}) end
if c == 0 then table.insert(rules_in, {x = 1, y = 0, z = 0}) end
if d == 0 then table.insert(rules_in, {x = 0, y = 0, z = -1}) end
ndef.mesecons.effector.rules = rules_in
if (a + b + c + d) > 0 then
ndef.mesecons.receptor = {
state = mesecon.state.on,
rules = rules_out,
}
end
minetest.register_node(nodename, ndef)
end
end
end
end
end
plg.register_nodes({
description = "FPGA",
drawtype = "nodebox",
tiles = {
"", -- replaced later
"jeija_microcontroller_bottom.png",
"jeija_fpga_sides.png",
"jeija_fpga_sides.png",
"jeija_fpga_sides.png",
"jeija_fpga_sides.png"
},
inventory_image = "", -- replaced later
is_ground_content = false,
sunlight_propagates = true,
paramtype = "light",
walkable = true,
groups = {dig_immediate = 2, mesecon = 3, overheat = 1},
drop = "mesecons_fpga:fpga0000",
selection_box = {
type = "fixed",
fixed = { -8/16, -8/16, -8/16, 8/16, -5/16, 8/16 },
},
node_box = {
type = "fixed",
fixed = {
{ -8/16, -8/16, -8/16, 8/16, -7/16, 8/16 }, -- bottom slab
{ -5/16, -7/16, -5/16, 5/16, -6/16, 5/16 }, -- circuit board
{ -3/16, -6/16, -3/16, 3/16, -5/16, 3/16 }, -- IC
}
},
on_construct = function(pos)
local meta = minetest.get_meta(pos)
local is = { {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {} }
meta:set_string("instr", lcore.serialize(is))
meta:set_int("valid", 0)
meta:set_string("formspec", plg.to_formspec_string(is))
meta:set_string("infotext", "FPGA")
end,
on_receive_fields = function(pos, formname, fields, sender)
if fields.program == nil then return end -- we only care when the user clicks "Program"
local meta = minetest.get_meta(pos)
local is = plg.from_formspec_fields(fields)
meta:set_string("instr", lcore.serialize(is))
plg.update_formspec(pos, is)
end,
sounds = default.node_sound_stone_defaults(),
mesecons = {
effector = {
rules = {}, -- replaced later
action_change = function(pos, node, rule, newstate)
plg.ports_changed(pos, rule, newstate)
plg.update(pos)
end
}
},
after_dig_node = function(pos, node)
mesecon.receptor_off(pos, plg.rules[node.name])
end,
on_blast = mesecon.on_blastnode,
on_rotate = function(pos, node, user, mode)
local abcd1 = {"A", "B", "C", "D"}
local abcd2 = {A = 1, B = 2, C = 3, D = 4}
local ops = {"op1", "op2", "dst"}
local dir = 0
if mode == screwdriver.ROTATE_FACE then -- clock-wise
dir = 1
if user and user:is_player() then
minetest.chat_send_player(user:get_player_name(),
"FPGA ports have been rotated clockwise.")
end
elseif mode == screwdriver.ROTATE_AXIS then -- counter-clockwise
dir = -1
if user and user:is_player() then
minetest.chat_send_player(user:get_player_name(),
"FPGA ports have been rotated counter-clockwise.")
end
end
local meta = minetest.get_meta(pos)
local instr = lcore.deserialize(meta:get_string("instr"))
for i = 1, #instr do
for _, op in ipairs(ops) do
local o = instr[i][op]
if o and o.type == "io" then
local num = abcd2[o.port]
num = num + dir
if num > 4 then num = 1
elseif num < 1 then num = 4 end
instr[i][op].port = abcd1[num]
end
end
end
meta:set_string("instr", lcore.serialize(instr))
plg.update_formspec(pos, instr)
return true
end,
})
plg.to_formspec_string = function(is)
local function dropdown_op(x, y, name, val)
local s = "dropdown[" .. tostring(x) .. "," .. tostring(y) .. ";"
.. "0.75,0.5;" .. name .. ";" -- the height seems to be ignored?
s = s .. " ,A,B,C,D,0,1,2,3,4,5,6,7,8,9;"
if val == nil then
s = s .. "0" -- actually selects no field at all
elseif val.type == "io" then
local mapping = {
["A"] = 1,
["B"] = 2,
["C"] = 3,
["D"] = 4,
}
s = s .. tostring(1 + mapping[val.port])
else -- "reg"
s = s .. tostring(6 + val.n)
end
return s .. "]"
end
local function dropdown_action(x, y, name, val)
local s = "dropdown[" .. tostring(x) .. "," .. tostring(y) .. ";"
.. "1.125,0.5;" .. name .. ";" -- the height seems to be ignored?
s = s .. " , AND, OR, NOT, XOR,NAND, =,XNOR;"
if val == nil then
return s .. "0]" -- actually selects no field at all
end
local mapping = {
["and"] = 1,
["or"] = 2,
["not"] = 3,
["xor"] = 4,
["nand"] = 5,
["buf"] = 6,
["xnor"] = 7,
}
return s .. tostring(1 + mapping[val]) .. "]"
end
local s = "size[9,9]"..
"label[3.4,-0.15;FPGA gate configuration]"..
"button_exit[7,7.5;2,2.5;program;Program]"..
"box[4.2,0.5;0.03,7;#ffffff]"..
"label[0.25,0.25;op. 1]"..
"label[1.0,0.25;gate type]"..
"label[2.125,0.25;op. 2]"..
"label[3.15,0.25;dest]"..
"label[4.5,0.25;op. 1]"..
"label[5.25,0.25;gate type]"..
"label[6.375,0.25;op. 2]"..
"label[7.4,0.25;dest]"
local x = 1 - 0.75
local y = 1 - 0.25
for i = 1, 14 do
local cur = is[i]
s = s .. dropdown_op (x , y, tostring(i).."op1", cur.op1)
s = s .. dropdown_action(x+0.75 , y, tostring(i).."act", cur.action)
s = s .. dropdown_op (x+1.875, y, tostring(i).."op2", cur.op2)
s = s .. "label[" .. tostring(x+2.625) .. "," .. tostring(y+0.1) .. "; ->]"
s = s .. dropdown_op (x+2.9 , y, tostring(i).."dst", cur.dst)
y = y + 1
if i == 7 then
x = 4.5
y = 1 - 0.25
end
end
return s
end
plg.from_formspec_fields = function(fields)
local function read_op(s)
if s == nil or s == " " then
return nil
elseif s == "A" or s == "B" or s == "C" or s == "D" then
return {type = "io", port = s}
else
return {type = "reg", n = tonumber(s)}
end
end
local function read_action(s)
if s == nil or s == " " then
return nil
end
local mapping = {
["AND"] = "and",
["OR"] = "or",
["NOT"] = "not",
["XOR"] = "xor",
["NAND"] = "nand",
["="] = "buf",
["XNOR"] = "xnor",
}
s = s:gsub("^%s*", "") -- remove leading spaces
return mapping[s]
end
local is = {}
for i = 1, 14 do
local cur = {}
cur.op1 = read_op(fields[tonumber(i) .. "op1"])
cur.action = read_action(fields[tonumber(i) .. "act"])
cur.op2 = read_op(fields[tonumber(i) .. "op2"])
cur.dst = read_op(fields[tonumber(i) .. "dst"])
is[#is + 1] = cur
end
return is
end
plg.update_formspec = function(pos, is)
if type(is) == "string" then -- serialized string
is = lcore.deserialize(is)
end
local meta = minetest.get_meta(pos)
local form = plg.to_formspec_string(is)
local err = lcore.validate(is)
if err == nil then
meta:set_int("valid", 1)
meta:set_string("infotext", "FPGA (functional)")
else
meta:set_int("valid", 0)
meta:set_string("infotext", "FPGA")
local fmsg = minetest.colorize("#ff0000", minetest.formspec_escape(err.msg))
form = form .. plg.red_box_around(err.i) ..
"label[0.25,8.25;The gate configuration is erroneous in the marked area:]"..
"label[0.25,8.5;" .. fmsg .. "]"
end
meta:set_string("formspec", form)
-- reset ports and run programmed logic
plg.setports(pos, false, false, false, false)
plg.update(pos)
end
plg.red_box_around = function(i)
local x, y
if i > 7 then
x = 4.5
y = 0.75 + (i - 8)
else
x = 0.25
y = 0.75 + (i - 1)
end
return string.format("box[%f,%f;3.8,0.8;#ff0000]", x-0.1, y-0.05)
end
plg.update = function(pos)
local meta = minetest.get_meta(pos)
if meta:get_int("valid") ~= 1 then
return
elseif mesecon.do_overheat(pos) then
plg.setports(pos, false, false, false, false)
meta:set_int("valid", 0)
meta:set_string("infotext", "FPGA (overheated)")
return
end
local is = lcore.deserialize(meta:get_string("instr"))
local A, B, C, D = plg.getports(pos)
A, B, C, D = lcore.interpret(is, A, B, C, D)
plg.setports(pos, A, B, C, D)
end
plg.ports_changed = function(pos, rule, newstate)
if rule == nil then return end
local meta = minetest.get_meta(pos)
local states
local s = meta:get_string("portstates")
if s == nil then
states = {false, false, false, false}
else
states = {
s:sub(1, 1) == "1",
s:sub(2, 2) == "1",
s:sub(3, 3) == "1",
s:sub(4, 4) == "1",
}
end
-- trick to transform rules (see register_node) into port number
local portno = ({4, 1, nil, 3, 2})[3 + rule.x + 2*rule.z]
states[portno] = (newstate == "on")
meta:set_string("portstates",
(states[1] and "1" or "0") .. (states[2] and "1" or "0") ..
(states[3] and "1" or "0") .. (states[4] and "1" or "0")
)
end
plg.getports = function(pos) -- gets merged states of INPUT & OUTPUT
local sin, sout
local s = minetest.get_meta(pos):get_string("portstates")
if s == nil then
sin = {false, false, false, false}
else
sin = {
s:sub(1, 1) == "1",
s:sub(2, 2) == "1",
s:sub(3, 3) == "1",
s:sub(4, 4) == "1",
}
end
local name = minetest.get_node(pos).name
assert(name:find("mesecons_fpga:fpga") == 1)
local off = #"mesecons_fpga:fpga"
sout = {
name:sub(off+4, off+4) == "1",
name:sub(off+3, off+3) == "1",
name:sub(off+2, off+2) == "1",
name:sub(off+1, off+1) == "1",
}
return unpack({
sin[1] or sout[1],
sin[2] or sout[2],
sin[3] or sout[3],
sin[4] or sout[4],
})
end
plg.setports = function(pos, A, B, C, D) -- sets states of OUTPUT
local base = "mesecons_fpga:fpga"
local name = base
.. (D and "1" or "0") .. (C and "1" or "0")
.. (B and "1" or "0") .. (A and "1" or "0")
minetest.swap_node(pos, {name = name, param2 = minetest.get_node(pos).param2})
if A ~= nil then
local ru = plg.rules[base .. "0001"]
if A then mesecon.receptor_on(pos, ru) else mesecon.receptor_off(pos, ru) end
end
if B ~= nil then
local ru = plg.rules[base .. "0010"]
if B then mesecon.receptor_on(pos, ru) else mesecon.receptor_off(pos, ru) end
end
if C ~= nil then
local ru = plg.rules[base .. "0100"]
if C then mesecon.receptor_on(pos, ru) else mesecon.receptor_off(pos, ru) end
end
if D ~= nil then
local ru = plg.rules[base .. "1000"]
if D then mesecon.receptor_on(pos, ru) else mesecon.receptor_off(pos, ru) end
end
end
minetest.register_craft({
output = "mesecons_fpga:fpga0000 2",
recipe = {
{'group:mesecon_conductor_craftable', 'group:mesecon_conductor_craftable'},
{'mesecons_materials:silicon', 'mesecons_materials:silicon'},
{'group:mesecon_conductor_craftable', 'group:mesecon_conductor_craftable'},
}
})

210
mesecons_fpga/logic.lua Normal file
View File

@ -0,0 +1,210 @@
local lg = {}
-- (de)serialize
lg.serialize = function(t)
local function _op(t)
if t == nil then
return " "
elseif t.type == "io" then
return t.port
else -- t.type == "reg"
return tostring(t.n)
end
end
local function _action(s)
if s == nil then
return " "
end
local mapping = {
["and"] = "&",
["or"] = "|",
["not"] = "~",
["xor"] = "^",
["nand"] = "?", --dunno
["buf"] = "_",
["xnor"] = "=",
}
return mapping[s]
end
local s = ""
for i = 1, 14 do
local cur = t[i]
if next(cur) ~= nil then
s = s .. _op(cur.op1) .. _action(cur.action) .. _op(cur.op2) .. _op(cur.dst)
end
s = s .. "/"
end
return s
end
lg.deserialize = function(s)
local function _op(c)
if c == "A" or c == "B" or c == "C" or c == "D" then
return {type = "io", port = c}
elseif c == " " then
return nil
else
return {type = "reg", n = tonumber(c)}
end
end
local function _action(c)
local mapping = {
["&"] = "and",
["|"] = "or",
["~"] = "not",
["^"] = "xor",
["?"] = "nand",
["_"] = "buf",
["="] = "xnor",
[" "] = nil,
}
return mapping[c]
end
local ret = {}
for part in s:gmatch("(.-)/") do
local parsed
if part == "" then
parsed = {}
else
parsed = {
action = _action( part:sub(2,2) ),
op1 = _op( part:sub(1,1) ),
op2 = _op( part:sub(3,3) ),
dst = _op( part:sub(4,4) ),
}
end
ret[#ret + 1] = parsed
end
-- More than 14 instructions (write to all 10 regs + 4 outputs)
-- will not pass the write-once requirement of the validator
assert(#ret == 14)
return ret
end
-- validation
lg.validate_single = function(t, i)
local function is_reg_written_to(t, n, max)
for i = 1, max-1 do
if next(t[i]) ~= nil
and t[i].dst and t[i].dst.type == "reg"
and t[i].dst.n == n then
return true
end
end
return false
end
local function compare_op(t1, t2, allow_same_io)
if t1 == nil or t2 == nil then
return false
elseif t1.type ~= t2.type then
return false
end
if t1.type == "reg" and t1.n == t2.n then
return true
elseif t1.type == "io" and t1.port == t2.port then
return not allow_same_io
end
return false
end
local elem = t[i]
-- check for completeness
if elem.action == nil then
return {i = i, msg = "Gate type required"}
elseif elem.action == "not" or elem.action == "buf" then
if elem.op1 ~= nil or elem.op2 == nil or elem.dst == nil then
return {i = i, msg = "Second operand (only) and destination required"}
end
else
if elem.op1 == nil or elem.op2 == nil or elem.dst == nil then
return {i = i, msg = "Operands and destination required"}
end
end
-- check whether operands/destination are identical
if compare_op(elem.op1, elem.op2) then
return {i = i, msg = "Operands cannot be identical"}
end
if compare_op(elem.op1, elem.dst, true) or compare_op(elem.op2, elem.dst, true) then
return {i = i, msg = "Destination and operands must be different"}
end
-- check whether operands point to defined registers
if elem.op1 ~= nil and elem.op1.type == "reg"
and not is_reg_written_to(t, elem.op1.n, i) then
return {i = i, msg = "First operand is undefined register"}
end
if elem.op2.type == "reg" and not is_reg_written_to(t, elem.op2.n, i) then
return {i = i, msg = "Second operand is undefined register"}
end
-- check whether destination points to undefined register
if elem.dst.type == "reg" and is_reg_written_to(t, elem.dst.n, i) then
return {i = i, msg = "Destination is already used register"}
end
return nil
end
lg.validate = function(t)
for i = 1, 14 do
if next(t[i]) ~= nil then
local r = lg.validate_single(t, i)
if r ~= nil then
return r
end
end
end
return nil
end
-- interpreter
lg.interpret = function(t, a, b, c, d)
local function _action(s, v1, v2)
if s == "and" then
return v1 and v2
elseif s == "or" then
return v1 or v2
elseif s == "not" then
return not v2
elseif s == "xor" then
return v1 ~= v2
elseif s == "nand" then
return not (v1 and v2)
elseif s == "buf" then
return v2
else -- s == "xnor"
return v1 == v2
end
end
local function _op(t, regs, io_in)
if t.type == "reg" then
return regs[t.n]
else -- t.type == "io"
return io_in[t.port]
end
end
local io_in = {A=a, B=b, C=c, D=d}
local regs = {}
local io_out = {}
for i = 1, 14 do
local cur = t[i]
if next(cur) ~= nil then
local v1, v2
if cur.op1 ~= nil then
v1 = _op(cur.op1, regs, io_in)
end
v2 = _op(cur.op2, regs, io_in)
local result = _action(cur.action, v1, v2)
if cur.dst.type == "reg" then
regs[cur.dst.n] = result
else -- cur.dst.type == "io"
io_out[cur.dst.port] = result
end
end
end
return io_out.A, io_out.B, io_out.C, io_out.D
end
return lg

Binary file not shown.

After

Width:  |  Height:  |  Size: 311 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 536 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 816 B

62
mesecons_fpga/tool.lua Normal file
View File

@ -0,0 +1,62 @@
return function(plg)
minetest.register_tool("mesecons_fpga:programmer", {
description = "FPGA Programmer",
inventory_image = "jeija_fpga_programmer.png",
stack_max = 1,
on_place = function(itemstack, placer, pointed_thing)
if pointed_thing.type ~= "node" then
return itemstack
end
local pos = pointed_thing.under
if minetest.get_node(pos).name:find("mesecons_fpga:fpga") ~= 1 then
return itemstack
end
local meta = minetest.get_meta(pos)
if meta:get_string("instr") == "//////////////" then
minetest.chat_send_player(placer:get_player_name(), "This FPGA is unprogrammed.")
return itemstack
end
itemstack:set_metadata(meta:get_string("instr"))
minetest.chat_send_player(placer:get_player_name(), "FPGA gate configuration was successfully copied!")
return itemstack
end,
on_use = function(itemstack, user, pointed_thing)
if pointed_thing.type ~= "node" then
return itemstack
end
local pos = pointed_thing.under
if minetest.get_node(pos).name:find("mesecons_fpga:fpga") ~= 1 then
return itemstack
end
local imeta = itemstack:get_metadata()
if imeta == "" then
minetest.chat_send_player(user:get_player_name(), "Use shift+right-click to copy a gate configuration first.")
return itemstack
end
local meta = minetest.get_meta(pos)
meta:set_string("instr", imeta)
plg.update_formspec(pos, imeta)
minetest.chat_send_player(user:get_player_name(), "Gate configuration was successfully written to FPGA!")
return itemstack
end
})
minetest.register_craft({
output = "mesecons_fpga:programmer",
recipe = {
{'group:mesecon_conductor_craftable'},
{'mesecons_materials:silicon'},
}
})
end

View File

@ -1 +1 @@
And gates power their output if both inputs (from left and right) are powered. AND gates power their output if both inputs (from left and right) are powered.

View File

@ -1 +1 @@
Mesecon diodes, just like real ones, only transfer power (signals) in one direction only. Diodes conduct signals in one direction only.

View File

@ -1 +1 @@
Nand gates do not power their output if both inputs (from left and right) are powered, but power it in every other case. NAND gates do not power their output if both inputs (from left and right) are powered, but power it in every other case.

View File

@ -1 +1 @@
Nor gates only power their output if none of their two inputs is powered. They are basically or gates with a not gate at their output. NOR gates only power their output if none of their two inputs is powered. They are basically OR gates with a NOT gate at their output.

View File

@ -1 +1 @@
Not gates invert signals, just like a mesecon torch does, but faster. The input is at the opposite side of the output. NOT gates invert signals, just like a mesecon torch does, but faster. The input is at the opposite side of the output.

View File

@ -1 +1 @@
Or gates power their output if either of their inputs (or both) are powered. You could basically get the same behaviour with two diodes, but or gates save some space. OR gates power their output if either of their inputs (or both) are powered. You could basically get the same behaviour with two diodes, but OR gates save some space.

View File

@ -54,10 +54,10 @@ local function update_gate(pos, node, link, newstate)
end end
end end
function register_gate(name, inputnumber, assess, recipe) local function register_gate(name, inputnumber, assess, recipe, description)
local get_inputrules = inputnumber == 2 and gate_get_input_rules_twoinputs or local get_inputrules = inputnumber == 2 and gate_get_input_rules_twoinputs or
gate_get_input_rules_oneinput gate_get_input_rules_oneinput
local description = "Mesecons Logic Gate: "..name description = "Logic Gate: "..name
local basename = "mesecons_gates:"..name local basename = "mesecons_gates:"..name
mesecon.register_node(basename, { mesecon.register_node(basename, {
@ -65,6 +65,7 @@ function register_gate(name, inputnumber, assess, recipe)
inventory_image = "jeija_gate_off.png^jeija_gate_"..name..".png", inventory_image = "jeija_gate_off.png^jeija_gate_"..name..".png",
paramtype = "light", paramtype = "light",
paramtype2 = "facedir", paramtype2 = "facedir",
is_ground_content = false,
drawtype = "nodebox", drawtype = "nodebox",
drop = basename.."_off", drop = basename.."_off",
selection_box = nodebox, selection_box = nodebox,
@ -74,7 +75,8 @@ function register_gate(name, inputnumber, assess, recipe)
assess = assess, assess = assess,
onstate = basename.."_on", onstate = basename.."_on",
offstate = basename.."_off", offstate = basename.."_off",
inputnumber = inputnumber inputnumber = inputnumber,
after_dig_node = mesecon.do_cooldown,
},{ },{
tiles = {"jeija_microcontroller_bottom.png^".."jeija_gate_off.png^".. tiles = {"jeija_microcontroller_bottom.png^".."jeija_gate_off.png^"..
"jeija_gate_"..name..".png"}, "jeija_gate_"..name..".png"},
@ -103,32 +105,39 @@ function register_gate(name, inputnumber, assess, recipe)
end end
register_gate("diode", 1, function (input) return input end, register_gate("diode", 1, function (input) return input end,
{{"mesecons:mesecon", "mesecons_torch:mesecon_torch_on", "mesecons_torch:mesecon_torch_on"}}) {{"mesecons:mesecon", "mesecons_torch:mesecon_torch_on", "mesecons_torch:mesecon_torch_on"}},
"Diode")
register_gate("not", 1, function (input) return not input end, register_gate("not", 1, function (input) return not input end,
{{"mesecons:mesecon", "mesecons_torch:mesecon_torch_on", "mesecons:mesecon"}}) {{"mesecons:mesecon", "mesecons_torch:mesecon_torch_on", "mesecons:mesecon"}},
"NOT Gate")
register_gate("and", 2, function (val1, val2) return val1 and val2 end, register_gate("and", 2, function (val1, val2) return val1 and val2 end,
{{"mesecons:mesecon", "", ""}, {{"mesecons:mesecon", "", ""},
{"", "mesecons_materials:silicon", "mesecons:mesecon"}, {"", "mesecons_materials:silicon", "mesecons:mesecon"},
{"mesecons:mesecon", "", ""}}) {"mesecons:mesecon", "", ""}},
"AND Gate")
register_gate("nand", 2, function (val1, val2) return not (val1 and val2) end, register_gate("nand", 2, function (val1, val2) return not (val1 and val2) end,
{{"mesecons:mesecon", "", ""}, {{"mesecons:mesecon", "", ""},
{"", "mesecons_materials:silicon", "mesecons_torch:mesecon_torch_on"}, {"", "mesecons_materials:silicon", "mesecons_torch:mesecon_torch_on"},
{"mesecons:mesecon", "", ""}}) {"mesecons:mesecon", "", ""}},
"NAND Gate")
register_gate("xor", 2, function (val1, val2) return (val1 or val2) and not (val1 and val2) end, register_gate("xor", 2, function (val1, val2) return (val1 or val2) and not (val1 and val2) end,
{{"mesecons:mesecon", "", ""}, {{"mesecons:mesecon", "", ""},
{"", "mesecons_materials:silicon", "mesecons_materials:silicon"}, {"", "mesecons_materials:silicon", "mesecons_materials:silicon"},
{"mesecons:mesecon", "", ""}}) {"mesecons:mesecon", "", ""}},
"XOR Gate")
register_gate("nor", 2, function (val1, val2) return not (val1 or val2) end, register_gate("nor", 2, function (val1, val2) return not (val1 or val2) end,
{{"mesecons:mesecon", "", ""}, {{"mesecons:mesecon", "", ""},
{"", "mesecons:mesecon", "mesecons_torch:mesecon_torch_on"}, {"", "mesecons:mesecon", "mesecons_torch:mesecon_torch_on"},
{"mesecons:mesecon", "", ""}}) {"mesecons:mesecon", "", ""}},
"NOR Gate")
register_gate("or", 2, function (val1, val2) return (val1 or val2) end, register_gate("or", 2, function (val1, val2) return (val1 or val2) end,
{{"mesecons:mesecon", "", ""}, {{"mesecons:mesecon", "", ""},
{"", "mesecons:mesecon", "mesecons:mesecon"}, {"", "mesecons:mesecon", "mesecons:mesecon"},
{"mesecons:mesecon", "", ""}}) {"mesecons:mesecon", "", ""}},
"OR Gate")

View File

@ -5,14 +5,15 @@
minetest.register_node("mesecons_hydroturbine:hydro_turbine_off", { minetest.register_node("mesecons_hydroturbine:hydro_turbine_off", {
drawtype = "mesh", drawtype = "mesh",
mesh = "jeija_hydro_turbine.obj", mesh = "jeija_hydro_turbine_off.obj",
tiles = { tiles = {
"jeija_hydro_turbine_sides_off.png", "jeija_hydro_turbine_sides_off.png",
"jeija_hydro_turbine_top_bottom.png", "jeija_hydro_turbine_top_bottom.png",
"jeija_hydro_turbine_turbine_top_bottom.png", "jeija_hydro_turbine_turbine_top_bottom_off.png",
"jeija_hydro_turbine_turbine_misc.png" "jeija_hydro_turbine_turbine_misc_off.png"
}, },
inventory_image = "jeija_hydro_turbine_inv.png", inventory_image = "jeija_hydro_turbine_inv.png",
is_ground_content = false,
wield_scale = {x=0.75, y=0.75, z=0.75}, wield_scale = {x=0.75, y=0.75, z=0.75},
groups = {dig_immediate=2}, groups = {dig_immediate=2},
description="Water Turbine", description="Water Turbine",
@ -21,21 +22,25 @@ minetest.register_node("mesecons_hydroturbine:hydro_turbine_off", {
type = "fixed", type = "fixed",
fixed = { -0.5, -0.5, -0.5, 0.5, 1.5, 0.5 }, fixed = { -0.5, -0.5, -0.5, 0.5, 1.5, 0.5 },
}, },
sounds = default.node_sound_stone_defaults(), sounds = default.node_sound_metal_defaults(),
mesecons = {receptor = { mesecons = {receptor = {
state = mesecon.state.off state = mesecon.state.off
}} }},
on_blast = mesecon.on_blastnode,
}) })
minetest.register_node("mesecons_hydroturbine:hydro_turbine_on", { minetest.register_node("mesecons_hydroturbine:hydro_turbine_on", {
drawtype = "mesh", drawtype = "mesh",
mesh = "jeija_hydro_turbine.obj", is_ground_content = false,
mesh = "jeija_hydro_turbine_on.obj",
wield_scale = {x=0.75, y=0.75, z=0.75}, wield_scale = {x=0.75, y=0.75, z=0.75},
tiles = { tiles = {
"jeija_hydro_turbine_sides_on.png", "jeija_hydro_turbine_sides_on.png",
"jeija_hydro_turbine_top_bottom.png", "jeija_hydro_turbine_top_bottom.png",
"jeija_hydro_turbine_turbine_top_bottom.png", { name = "jeija_hydro_turbine_turbine_top_bottom_on.png",
"jeija_hydro_turbine_turbine_misc.png" animation = {type = "vertical_frames", aspect_w = 128, aspect_h = 16, length = 1.6} },
{ name = "jeija_hydro_turbine_turbine_misc_on.png",
animation = {type = "vertical_frames", aspect_w = 256, aspect_h = 32, length = 0.4} }
}, },
inventory_image = "jeija_hydro_turbine_inv.png", inventory_image = "jeija_hydro_turbine_inv.png",
drop = "mesecons_hydroturbine:hydro_turbine_off 1", drop = "mesecons_hydroturbine:hydro_turbine_off 1",
@ -46,22 +51,29 @@ minetest.register_node("mesecons_hydroturbine:hydro_turbine_on", {
type = "fixed", type = "fixed",
fixed = { -0.5, -0.5, -0.5, 0.5, 1.5, 0.5 }, fixed = { -0.5, -0.5, -0.5, 0.5, 1.5, 0.5 },
}, },
sounds = default.node_sound_stone_defaults(), sounds = default.node_sound_metal_defaults(),
mesecons = {receptor = { mesecons = {receptor = {
state = mesecon.state.on state = mesecon.state.on
}} }},
on_blast = mesecon.on_blastnode,
}) })
local function is_flowing_water(pos)
local name = minetest.get_node(pos).name
local is_water = minetest.get_item_group(name, "water") > 0
local is_flowing = minetest.registered_items[name].liquidtype == "flowing"
return (is_water and is_flowing)
end
minetest.register_abm({ minetest.register_abm({
nodenames = {"mesecons_hydroturbine:hydro_turbine_off"}, nodenames = {"mesecons_hydroturbine:hydro_turbine_off"},
interval = 1, interval = 1,
chance = 1, chance = 1,
action = function(pos, node, active_object_count, active_object_count_wider) action = function(pos, node, active_object_count, active_object_count_wider)
local waterpos={x=pos.x, y=pos.y+1, z=pos.z} local waterpos={x=pos.x, y=pos.y+1, z=pos.z}
if minetest.get_node(waterpos).name=="default:water_flowing" then if is_flowing_water(waterpos) then
minetest.set_node(pos, {name="mesecons_hydroturbine:hydro_turbine_on"}) minetest.set_node(pos, {name="mesecons_hydroturbine:hydro_turbine_on"})
nodeupdate(pos)
mesecon.receptor_on(pos) mesecon.receptor_on(pos)
end end
end, end,
@ -73,9 +85,8 @@ nodenames = {"mesecons_hydroturbine:hydro_turbine_on"},
chance = 1, chance = 1,
action = function(pos, node, active_object_count, active_object_count_wider) action = function(pos, node, active_object_count, active_object_count_wider)
local waterpos={x=pos.x, y=pos.y+1, z=pos.z} local waterpos={x=pos.x, y=pos.y+1, z=pos.z}
if minetest.get_node(waterpos).name~="default:water_flowing" then if not is_flowing_water(waterpos) then
minetest.set_node(pos, {name="mesecons_hydroturbine:hydro_turbine_off"}) minetest.set_node(pos, {name="mesecons_hydroturbine:hydro_turbine_off"})
nodeupdate(pos)
mesecon.receptor_off(pos) mesecon.receptor_off(pos)
end end
end, end,

View File

@ -1,21 +1,21 @@
# Blender v2.73 (sub 0) OBJ File: 'mesecons-water-turbine.blend' # Blender v2.72 (sub 0) OBJ File: 'mesecons-water-turbine.blend'
# www.blender.org # www.blender.org
o Cylinder.002_Cylinder.003 o Cylinder.002_Cylinder.003
v 0.000000 0.500000 -0.150000 v 0.000000 0.496094 -0.150000
v 0.000000 0.562500 -0.150000 v 0.000000 0.562500 -0.150000
v 0.106066 0.500000 -0.106066 v 0.106066 0.496094 -0.106066
v 0.106066 0.562500 -0.106066 v 0.106066 0.562500 -0.106066
v 0.150000 0.500000 0.000000 v 0.150000 0.496094 0.000000
v 0.150000 0.562500 0.000000 v 0.150000 0.562500 0.000000
v 0.106066 0.500000 0.106066 v 0.106066 0.496094 0.106066
v 0.106066 0.562500 0.106066 v 0.106066 0.562500 0.106066
v -0.000000 0.500000 0.150000 v -0.000000 0.496094 0.150000
v -0.000000 0.562500 0.150000 v -0.000000 0.562500 0.150000
v -0.106066 0.500000 0.106066 v -0.106066 0.496094 0.106066
v -0.106066 0.562500 0.106066 v -0.106066 0.562500 0.106066
v -0.150000 0.500000 -0.000000 v -0.150000 0.496094 -0.000000
v -0.150000 0.562500 -0.000000 v -0.150000 0.562500 -0.000000
v -0.106066 0.500000 -0.106066 v -0.106066 0.496094 -0.106066
v -0.106066 0.562500 -0.106066 v -0.106066 0.562500 -0.106066
v 0.097545 0.625000 -0.490393 v 0.097545 0.625000 -0.490393
v -0.097545 0.625000 -0.490393 v -0.097545 0.625000 -0.490393
@ -113,38 +113,38 @@ v -0.430779 0.634645 -0.108975
v -0.180802 0.634645 -0.292266 v -0.180802 0.634645 -0.292266
v -0.180802 1.482640 -0.292266 v -0.180802 1.482640 -0.292266
v -0.430779 1.482640 -0.108975 v -0.430779 1.482640 -0.108975
v 0.097545 1.500000 -0.490393 v 0.097545 1.496094 -0.490393
v -0.097545 1.500000 -0.490393 v -0.097545 1.496094 -0.490393
v -0.277785 1.500000 -0.415735 v -0.277785 1.496094 -0.415735
v -0.415735 1.500000 -0.277785 v -0.415735 1.496094 -0.277785
v -0.490393 1.500000 -0.097545 v -0.490393 1.496094 -0.097545
v -0.490393 1.500000 0.097545 v -0.490393 1.496094 0.097545
v -0.415735 1.500000 0.277785 v -0.415735 1.496094 0.277785
v -0.277785 1.500000 0.415735 v -0.277785 1.496094 0.415735
v -0.097545 1.500000 0.490393 v -0.097545 1.496094 0.490393
v 0.097545 1.500000 0.490393 v 0.097545 1.496094 0.490393
v 0.277785 1.500000 0.415735 v 0.277785 1.496094 0.415735
v 0.415735 1.500000 0.277785 v 0.415735 1.496094 0.277785
v 0.490393 1.500000 0.097545 v 0.490393 1.496094 0.097545
v 0.490393 1.500000 -0.097545 v 0.490393 1.496094 -0.097545
v 0.415735 1.500000 -0.277785 v 0.415735 1.496094 -0.277785
v 0.277785 1.500000 -0.415735 v 0.277785 1.496094 -0.415735
v 0.097545 1.468750 -0.490393 v 0.097545 1.464844 -0.490393
v -0.097545 1.468750 -0.490393 v -0.097545 1.464844 -0.490393
v -0.277785 1.468750 -0.415735 v -0.277785 1.464844 -0.415735
v -0.415735 1.468750 -0.277785 v -0.415735 1.464844 -0.277785
v -0.490393 1.468750 -0.097545 v -0.490393 1.464844 -0.097545
v -0.490393 1.468750 0.097545 v -0.490393 1.464844 0.097545
v -0.415735 1.468750 0.277785 v -0.415735 1.464844 0.277785
v -0.277785 1.468750 0.415735 v -0.277785 1.464844 0.415735
v -0.097545 1.468750 0.490393 v -0.097545 1.464844 0.490393
v 0.097545 1.468750 0.490393 v 0.097545 1.464844 0.490393
v 0.277785 1.468750 0.415735 v 0.277785 1.464844 0.415735
v 0.415735 1.468750 0.277785 v 0.415735 1.464844 0.277785
v 0.490393 1.468750 0.097545 v 0.490393 1.464844 0.097545
v 0.490393 1.468750 -0.097545 v 0.490393 1.464844 -0.097545
v 0.415735 1.468750 -0.277785 v 0.415735 1.464844 -0.277785
v 0.277785 1.468750 -0.415735 v 0.277785 1.464844 -0.415735
v 0.025624 0.559630 -0.061863 v 0.025624 0.559630 -0.061863
v 0.025624 1.481372 -0.061863 v 0.025624 1.481372 -0.061863
v 0.061863 0.559630 -0.025624 v 0.061863 0.559630 -0.025624
@ -161,14 +161,14 @@ v -0.061863 0.559630 -0.025624
v -0.061863 1.481372 -0.025624 v -0.061863 1.481372 -0.025624
v -0.025624 0.559630 -0.061863 v -0.025624 0.559630 -0.061863
v -0.025624 1.481372 -0.061863 v -0.025624 1.481372 -0.061863
v 0.499775 -0.499550 -0.499775 v 0.496094 -0.496094 -0.496094
v 0.499775 -0.499550 0.499775 v 0.496094 -0.496094 0.496094
v -0.499775 -0.499550 0.499775 v -0.496094 -0.496094 0.496094
v -0.499775 -0.499550 -0.499775 v -0.496094 -0.496094 -0.496094
v 0.499775 0.500000 -0.499775 v 0.496094 0.496094 -0.496094
v 0.499775 0.500000 0.499775 v 0.496094 0.496094 0.496094
v -0.499775 0.500000 0.499775 v -0.496094 0.496094 0.496094
v -0.499775 0.500000 -0.499775 v -0.496094 0.496094 -0.496094
vt 1.000000 0.000000 vt 1.000000 0.000000
vt 1.000000 1.000000 vt 1.000000 1.000000
vt 0.000000 1.000000 vt 0.000000 1.000000
@ -314,10 +314,10 @@ vt 0.031250 0.875000
vt 0.031250 0.906250 vt 0.031250 0.906250
vt 0.062500 0.906250 vt 0.062500 0.906250
vn 1.000000 0.000000 0.000000 vn 1.000000 0.000000 0.000000
vn -0.000000 -0.000000 1.000000 vn 0.000000 0.000000 1.000000
vn -1.000000 -0.000000 -0.000000 vn -1.000000 0.000000 0.000000
vn 0.000000 0.000000 -1.000000 vn 0.000000 0.000000 -1.000000
vn 0.000000 -1.000000 -0.000000 vn 0.000000 -1.000000 0.000000
vn 0.000000 1.000000 0.000000 vn 0.000000 1.000000 0.000000
vn 0.382700 0.000000 -0.923900 vn 0.382700 0.000000 -0.923900
vn 0.923900 0.000000 -0.382700 vn 0.923900 0.000000 -0.382700

File diff suppressed because it is too large Load Diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

View File

@ -1 +1,2 @@
mesecons mesecons
screwdriver?

View File

@ -1,4 +1,6 @@
function insulated_wire_get_rules(node) local screwdriver_exists = minetest.global_exists("screwdriver")
local function insulated_wire_get_rules(node)
local rules = {{x = 1, y = 0, z = 0}, local rules = {{x = 1, y = 0, z = 0},
{x =-1, y = 0, z = 0}} {x =-1, y = 0, z = 0}}
if node.param2 == 1 or node.param2 == 3 then if node.param2 == 1 or node.param2 == 3 then
@ -9,7 +11,7 @@ end
minetest.register_node("mesecons_insulated:insulated_on", { minetest.register_node("mesecons_insulated:insulated_on", {
drawtype = "nodebox", drawtype = "nodebox",
description = "Insulated Mesecon", description = "Straight Insulated Mesecon",
tiles = { tiles = {
"jeija_insulated_wire_sides_on.png", "jeija_insulated_wire_sides_on.png",
"jeija_insulated_wire_sides_on.png", "jeija_insulated_wire_sides_on.png",
@ -20,6 +22,7 @@ minetest.register_node("mesecons_insulated:insulated_on", {
}, },
paramtype = "light", paramtype = "light",
paramtype2 = "facedir", paramtype2 = "facedir",
is_ground_content = false,
walkable = false, walkable = false,
sunlight_propagates = true, sunlight_propagates = true,
selection_box = { selection_box = {
@ -32,16 +35,19 @@ minetest.register_node("mesecons_insulated:insulated_on", {
}, },
groups = {dig_immediate = 3, not_in_creative_inventory = 1}, groups = {dig_immediate = 3, not_in_creative_inventory = 1},
drop = "mesecons_insulated:insulated_off", drop = "mesecons_insulated:insulated_off",
sounds = default.node_sound_defaults(),
mesecons = {conductor = { mesecons = {conductor = {
state = mesecon.state.on, state = mesecon.state.on,
offstate = "mesecons_insulated:insulated_off", offstate = "mesecons_insulated:insulated_off",
rules = insulated_wire_get_rules rules = insulated_wire_get_rules
}} }},
on_blast = mesecon.on_blastnode,
on_rotate = screwdriver_exists and screwdriver.rotate_simple,
}) })
minetest.register_node("mesecons_insulated:insulated_off", { minetest.register_node("mesecons_insulated:insulated_off", {
drawtype = "nodebox", drawtype = "nodebox",
description = "Insulated Mesecon", description = "Straight Insulated Mesecon",
tiles = { tiles = {
"jeija_insulated_wire_sides_off.png", "jeija_insulated_wire_sides_off.png",
"jeija_insulated_wire_sides_off.png", "jeija_insulated_wire_sides_off.png",
@ -52,6 +58,7 @@ minetest.register_node("mesecons_insulated:insulated_off", {
}, },
paramtype = "light", paramtype = "light",
paramtype2 = "facedir", paramtype2 = "facedir",
is_ground_content = false,
walkable = false, walkable = false,
sunlight_propagates = true, sunlight_propagates = true,
selection_box = { selection_box = {
@ -63,11 +70,14 @@ minetest.register_node("mesecons_insulated:insulated_off", {
fixed = { -16/32-0.001, -17/32, -3/32, 16/32+0.001, -13/32, 3/32 } fixed = { -16/32-0.001, -17/32, -3/32, 16/32+0.001, -13/32, 3/32 }
}, },
groups = {dig_immediate = 3}, groups = {dig_immediate = 3},
sounds = default.node_sound_defaults(),
mesecons = {conductor = { mesecons = {conductor = {
state = mesecon.state.off, state = mesecon.state.off,
onstate = "mesecons_insulated:insulated_on", onstate = "mesecons_insulated:insulated_on",
rules = insulated_wire_get_rules rules = insulated_wire_get_rules
}} }},
on_blast = mesecon.on_blastnode,
on_rotate = screwdriver_exists and screwdriver.rotate_simple,
}) })
minetest.register_craft({ minetest.register_craft({

Binary file not shown.

Before

Width:  |  Height:  |  Size: 305 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 270 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 293 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 209 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 246 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 252 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 238 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 261 B

View File

@ -1 +1 @@
Lamps are effectors that if powered emit light. Mesecon lamps are effectors that if powered emit light.

View File

@ -2,7 +2,7 @@
-- A lamp is "is an electrical device used to create artificial light" (wikipedia) -- A lamp is "is an electrical device used to create artificial light" (wikipedia)
-- guess what? -- guess what?
mesecon_lamp_box = { local mesecon_lamp_box = {
type = "wallmounted", type = "wallmounted",
wall_top = {-0.3125,0.375,-0.3125,0.3125,0.5,0.3125}, wall_top = {-0.3125,0.375,-0.3125,0.3125,0.5,0.3125},
wall_bottom = {-0.3125,-0.5,-0.3125,0.3125,-0.375,0.3125}, wall_bottom = {-0.3125,-0.5,-0.3125,0.3125,-0.375,0.3125},
@ -14,20 +14,23 @@ minetest.register_node("mesecons_lamp:lamp_on", {
tiles = {"jeija_meselamp_on.png"}, tiles = {"jeija_meselamp_on.png"},
paramtype = "light", paramtype = "light",
paramtype2 = "wallmounted", paramtype2 = "wallmounted",
is_ground_content = false,
legacy_wallmounted = true, legacy_wallmounted = true,
sunlight_propagates = true, sunlight_propagates = true,
walkable = true, walkable = true,
light_source = default.LIGHT_MAX, light_source = minetest.LIGHT_MAX,
node_box = mesecon_lamp_box, node_box = mesecon_lamp_box,
selection_box = mesecon_lamp_box, selection_box = mesecon_lamp_box,
groups = {dig_immediate=3,not_in_creative_inventory=1, mesecon_effector_on = 1}, groups = {dig_immediate = 3,not_in_creative_inventory = 1, mesecon_effector_on = 1},
drop="mesecons_lamp:lamp_off 1", drop = "mesecons_lamp:lamp_off 1",
sounds = default.node_sound_glass_defaults(), sounds = default.node_sound_glass_defaults(),
mesecons = {effector = { mesecons = {effector = {
action_off = function (pos, node) action_off = function (pos, node)
minetest.swap_node(pos, {name = "mesecons_lamp:lamp_off", param2 = node.param2}) minetest.swap_node(pos, {name = "mesecons_lamp:lamp_off", param2 = node.param2})
end end,
}} rules = mesecon.rules.wallmounted_get,
}},
on_blast = mesecon.on_blastnode,
}) })
minetest.register_node("mesecons_lamp:lamp_off", { minetest.register_node("mesecons_lamp:lamp_off", {
@ -37,18 +40,21 @@ minetest.register_node("mesecons_lamp:lamp_off", {
wield_image = "jeija_meselamp.png", wield_image = "jeija_meselamp.png",
paramtype = "light", paramtype = "light",
paramtype2 = "wallmounted", paramtype2 = "wallmounted",
is_ground_content = false,
sunlight_propagates = true, sunlight_propagates = true,
walkable = true, walkable = true,
node_box = mesecon_lamp_box, node_box = mesecon_lamp_box,
selection_box = mesecon_lamp_box, selection_box = mesecon_lamp_box,
groups = {dig_immediate=3, mesecon_receptor_off = 1, mesecon_effector_off = 1}, groups = {dig_immediate=3, mesecon_receptor_off = 1, mesecon_effector_off = 1},
description="Meselamp", description = "Mesecon Lamp",
sounds = default.node_sound_glass_defaults(), sounds = default.node_sound_glass_defaults(),
mesecons = {effector = { mesecons = {effector = {
action_on = function (pos, node) action_on = function (pos, node)
minetest.swap_node(pos, {name = "mesecons_lamp:lamp_on", param2 = node.param2}) minetest.swap_node(pos, {name = "mesecons_lamp:lamp_on", param2 = node.param2})
end end,
}} rules = mesecon.rules.wallmounted_get,
}},
on_blast = mesecon.on_blastnode,
}) })
minetest.register_craft({ minetest.register_craft({

View File

@ -14,31 +14,38 @@ local lightstone_rules = {
{x=0, y=-1, z=0}, {x=0, y=-1, z=0},
} }
function mesecon.lightstone_add(name, base_item, texture_off, texture_on) function mesecon.lightstone_add(name, base_item, texture_off, texture_on, desc)
if not desc then
desc = name .. " Lightstone"
end
minetest.register_node("mesecons_lightstone:lightstone_" .. name .. "_off", { minetest.register_node("mesecons_lightstone:lightstone_" .. name .. "_off", {
tiles = {texture_off}, tiles = {texture_off},
groups = {cracky=2, mesecon_effector_off = 1, mesecon = 2}, is_ground_content = false,
description=name.." Lightstone", groups = {cracky = 2, mesecon_effector_off = 1, mesecon = 2},
description = desc,
sounds = default.node_sound_stone_defaults(), sounds = default.node_sound_stone_defaults(),
mesecons = {effector = { mesecons = {effector = {
rules = lightstone_rules, rules = lightstone_rules,
action_on = function (pos, node) action_on = function (pos, node)
minetest.swap_node(pos, {name = "mesecons_lightstone:lightstone_" .. name .. "_on", param2 = node.param2}) minetest.swap_node(pos, {name = "mesecons_lightstone:lightstone_" .. name .. "_on", param2 = node.param2})
end, end,
}} }},
on_blast = mesecon.on_blastnode,
}) })
minetest.register_node("mesecons_lightstone:lightstone_" .. name .. "_on", { minetest.register_node("mesecons_lightstone:lightstone_" .. name .. "_on", {
tiles = {texture_on}, tiles = {texture_on},
groups = {cracky=2,not_in_creative_inventory=1, mesecon = 2}, is_ground_content = false,
drop = "mesecons_lightstone:lightstone_" .. name .. "_off", groups = {cracky = 2, not_in_creative_inventory = 1, mesecon = 2},
light_source = default.LIGHT_MAX-2, drop = "mesecons_lightstone:lightstone_" .. name .. "_off",
sounds = default.node_sound_stone_defaults(), light_source = minetest.LIGHT_MAX - 2,
mesecons = {effector = { sounds = default.node_sound_stone_defaults(),
rules = lightstone_rules, mesecons = {effector = {
action_off = function (pos, node) rules = lightstone_rules,
minetest.swap_node(pos, {name = "mesecons_lightstone:lightstone_" .. name .. "_off", param2 = node.param2}) action_off = function (pos, node)
end, minetest.swap_node(pos, {name = "mesecons_lightstone:lightstone_" .. name .. "_off", param2 = node.param2})
}} end,
}},
on_blast = mesecon.on_blastnode,
}) })
minetest.register_craft({ minetest.register_craft({
@ -52,9 +59,15 @@ function mesecon.lightstone_add(name, base_item, texture_off, texture_on)
end end
mesecon.lightstone_add("red", "dye:red", "jeija_lightstone_red_off.png", "jeija_lightstone_red_on.png") mesecon.lightstone_add("red", "dye:red", "jeija_lightstone_red_off.png", "jeija_lightstone_red_on.png", "Red Lightstone")
mesecon.lightstone_add("green", "dye:green", "jeija_lightstone_green_off.png", "jeija_lightstone_green_on.png") mesecon.lightstone_add("green", "dye:green", "jeija_lightstone_green_off.png", "jeija_lightstone_green_on.png", "Green Lightstone")
mesecon.lightstone_add("blue", "dye:blue", "jeija_lightstone_blue_off.png", "jeija_lightstone_blue_on.png") mesecon.lightstone_add("blue", "dye:blue", "jeija_lightstone_blue_off.png", "jeija_lightstone_blue_on.png", "Blue Lightstone")
mesecon.lightstone_add("gray", "dye:grey", "jeija_lightstone_gray_off.png", "jeija_lightstone_gray_on.png") mesecon.lightstone_add("gray", "dye:grey", "jeija_lightstone_gray_off.png", "jeija_lightstone_gray_on.png", "Grey Lightstone")
mesecon.lightstone_add("darkgray", "dye:dark_grey", "jeija_lightstone_darkgray_off.png", "jeija_lightstone_darkgray_on.png") mesecon.lightstone_add("darkgray", "dye:dark_grey", "jeija_lightstone_darkgray_off.png", "jeija_lightstone_darkgray_on.png", "Dark Grey Lightstone")
mesecon.lightstone_add("yellow", "dye:yellow", "jeija_lightstone_yellow_off.png", "jeija_lightstone_yellow_on.png") mesecon.lightstone_add("yellow", "dye:yellow", "jeija_lightstone_yellow_off.png", "jeija_lightstone_yellow_on.png", "Yellow Lightstone")
mesecon.lightstone_add("orange", "dye:orange", "jeija_lightstone_orange_off.png", "jeija_lightstone_orange_on.png", "Orange Lightstone")
mesecon.lightstone_add("white", "dye:white", "jeija_lightstone_white_off.png", "jeija_lightstone_white_on.png", "White Lightstone")
mesecon.lightstone_add("pink", "dye:pink", "jeija_lightstone_pink_off.png", "jeija_lightstone_pink_on.png", "Pink Lightstone")
mesecon.lightstone_add("magenta", "dye:magenta", "jeija_lightstone_magenta_off.png", "jeija_lightstone_magenta_on.png", "Magenta Lightstone")
mesecon.lightstone_add("cyan", "dye:cyan", "jeija_lightstone_cyan_off.png", "jeija_lightstone_cyan_on.png", "Cyan Lightstone")
mesecon.lightstone_add("violet", "dye:violet", "jeija_lightstone_violet_off.png", "jeija_lightstone_violet_on.png", "Violet Lightstone")

Binary file not shown.

After

Width:  |  Height:  |  Size: 443 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 663 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 387 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 633 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 407 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 641 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 349 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 546 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 387 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 633 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 429 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 357 B

View File

@ -1,5 +1,5 @@
The luacontroller is an advanced programmable component. The Luacontroller is an advanced programmable component.
You can simply code it in the language mesecons uses itself: Lua! You can simply code it in the language Mesecons uses itself: Lua!
All the code runs in a sandbox, so it's completely safe (but I won't guarantee that for absolute certainty!). All the code runs in a sandbox, so it's completely safe (but I won't guarantee that for absolute certainty!).
<a href="http://mesecons.net/luacontroller/">Documentation is available here!</a> <a href="http://mesecons.net/luacontroller/">Documentation is available here!</a>

View File

@ -12,16 +12,16 @@
-- ports = get_real_port_states(pos): gets if inputs are powered from outside -- ports = get_real_port_states(pos): gets if inputs are powered from outside
-- newport = merge_port_states(state1, state2): just does result = state1 or state2 for every port -- newport = merge_port_states(state1, state2): just does result = state1 or state2 for every port
-- set_port(pos, rule, state): activates/deactivates the mesecons according to the port states -- set_port(pos, rule, state): activates/deactivates the mesecons according to the port states
-- set_port_states(pos, ports): Applies new port states to a LuaController at pos -- set_port_states(pos, ports): Applies new port states to a Luacontroller at pos
-- run(pos): runs the code in the controller at pos -- run_inner(pos, code, event): runs code on the controller at pos and event
-- reset_meta(pos, code, errmsg): performs a software-reset, installs new code and prints error messages -- reset_formspec(pos, code, errmsg): installs new code and prints error messages, without resetting LCID
-- reset_meta(pos, code, errmsg): performs a software-reset, installs new code and prints error message
-- run(pos, event): a wrapper for run_inner which gets code & handles errors via reset_meta
-- resetn(pos): performs a hardware reset, turns off all ports -- resetn(pos): performs a hardware reset, turns off all ports
-- --
-- The Sandbox -- The Sandbox
-- The whole code of the controller runs in a sandbox, -- The whole code of the controller runs in a sandbox,
-- a very restricted environment. -- a very restricted environment.
-- However, as this does not prevent you from using e.g. loops,
-- we need to check for these prohibited commands first.
-- Actually the only way to damage the server is to -- Actually the only way to damage the server is to
-- use too much memory from the sandbox. -- use too much memory from the sandbox.
-- You can add more functions to the environment -- You can add more functions to the environment
@ -143,7 +143,7 @@ local function set_port_states(pos, ports)
-- Solution / Workaround: -- Solution / Workaround:
-- Remember which output was turned off and ignore next "off" event. -- Remember which output was turned off and ignore next "off" event.
local meta = minetest.get_meta(pos) local meta = minetest.get_meta(pos)
local ign = minetest.deserialize(meta:get_string("ignore_offevents")) or {} local ign = minetest.deserialize(meta:get_string("ignore_offevents"), true) or {}
if ports.a and not vports.a and not mesecon.is_powered(pos, rules.a) then ign.A = true end if ports.a and not vports.a and not mesecon.is_powered(pos, rules.a) then ign.A = true end
if ports.b and not vports.b and not mesecon.is_powered(pos, rules.b) then ign.B = true end if ports.b and not vports.b and not mesecon.is_powered(pos, rules.b) then ign.B = true end
if ports.c and not vports.c and not mesecon.is_powered(pos, rules.c) then ign.C = true end if ports.c and not vports.c and not mesecon.is_powered(pos, rules.c) then ign.C = true end
@ -185,7 +185,7 @@ end
local function ignore_event(event, meta) local function ignore_event(event, meta)
if event.type ~= "off" then return false end if event.type ~= "off" then return false end
local ignore_offevents = minetest.deserialize(meta:get_string("ignore_offevents")) or {} local ignore_offevents = minetest.deserialize(meta:get_string("ignore_offevents"), true) or {}
if ignore_offevents[event.pin.name] then if ignore_offevents[event.pin.name] then
ignore_offevents[event.pin.name] = nil ignore_offevents[event.pin.name] = nil
meta:set_string("ignore_offevents", minetest.serialize(ignore_offevents)) meta:set_string("ignore_offevents", minetest.serialize(ignore_offevents))
@ -198,7 +198,11 @@ end
------------------------- -------------------------
local function safe_print(param) local function safe_print(param)
local string_meta = getmetatable("")
local sandbox = string_meta.__index
string_meta.__index = string -- Leave string sandbox temporarily
print(dump(param)) print(dump(param))
string_meta.__index = sandbox -- Restore string sandbox
end end
local function safe_date() local function safe_date()
@ -221,7 +225,7 @@ end
local function safe_string_find(...) local function safe_string_find(...)
if (select(4, ...)) ~= true then if (select(4, ...)) ~= true then
debug.sethook() -- Clear hook debug.sethook() -- Clear hook
error("string.find: 'plain' (fourth parameter) must always be true in a LuaController") error("string.find: 'plain' (fourth parameter) must always be true in a Luacontroller")
end end
return string.find(...) return string.find(...)
@ -234,10 +238,11 @@ local function remove_functions(x)
end end
-- Make sure to not serialize the same table multiple times, otherwise -- Make sure to not serialize the same table multiple times, otherwise
-- writing mem.test = mem in the LuaController will lead to infinite recursion -- writing mem.test = mem in the Luacontroller will lead to infinite recursion
local seen = {} local seen = {}
local function rfuncs(x) local function rfuncs(x)
if x == nil then return end
if seen[x] then return end if seen[x] then return end
seen[x] = true seen[x] = true
if type(x) ~= "table" then return end if type(x) ~= "table" then return end
@ -261,50 +266,180 @@ local function remove_functions(x)
return x return x
end end
local function get_interrupt(pos) -- itbl: Flat table of functions to run after sandbox cleanup, used to prevent various security hazards
local function get_interrupt(pos, itbl, send_warning)
-- iid = interrupt id -- iid = interrupt id
local function interrupt(time, iid) local function interrupt(time, iid)
-- NOTE: This runs within string metatable sandbox, so don't *rely* on anything of the form (""):y
-- Hence the values get moved out. Should take less time than original, so totally compatible
if type(time) ~= "number" then return end if type(time) ~= "number" then return end
local luac_id = minetest.get_meta(pos):get_int("luac_id") table.insert(itbl, function ()
mesecon.queue:add_action(pos, "lc_interrupt", {luac_id, iid}, time, iid, 1) -- Outside string metatable sandbox, can safely run this now
local luac_id = minetest.get_meta(pos):get_int("luac_id")
-- Check if IID is dodgy, so you can't use interrupts to store an infinite amount of data.
-- Note that this is safe from alter-after-free because this code gets run after the sandbox has ended.
-- This runs outside of the timer and *shouldn't* harm perf. unless dodgy data is being sent in the first place
iid = remove_functions(iid)
local msg_ser = minetest.serialize(iid)
if #msg_ser <= mesecon.setting("luacontroller_interruptid_maxlen", 256) then
mesecon.queue:add_action(pos, "lc_interrupt", {luac_id, iid}, time, iid, 1)
else
send_warning("An interrupt ID was too large!")
end
end)
end end
return interrupt return interrupt
end end
local function get_digiline_send(pos) -- Given a message object passed to digiline_send, clean it up into a form
if not digiline then return end -- which is safe to transmit over the network and compute its "cost" (a very
-- rough estimate of its memory usage).
--
-- The cleaning comprises the following:
-- 1. Functions (and userdata, though user scripts ought not to get hold of
-- those in the first place) are removed, because they break the model of
-- Digilines as a network that carries basic data, and they could exfiltrate
-- references to mutable objects from one Luacontroller to another, allowing
-- inappropriate high-bandwidth, no-wires communication.
-- 2. Tables are duplicated because, being mutable, they could otherwise be
-- modified after the send is complete in order to change what data arrives
-- at the recipient, perhaps in violation of the previous cleaning rule or
-- in violation of the message size limit.
--
-- The cost indication is only approximate; its not a perfect measurement of
-- the number of bytes of memory used by the message object.
--
-- Parameters:
-- msg -- the message to clean
-- back_references -- for internal use only; do not provide
--
-- Returns:
-- 1. The cleaned object.
-- 2. The approximate cost of the object.
local function clean_and_weigh_digiline_message(msg, back_references)
local t = type(msg)
if t == "string" then
-- Strings are immutable so can be passed by reference, and cost their
-- length plus the size of the Lua object header (24 bytes on a 64-bit
-- platform) plus one byte for the NUL terminator.
return msg, #msg + 25
elseif t == "number" then
-- Numbers are passed by value so need not be touched, and cost 8 bytes
-- as all numbers in Lua are doubles.
return msg, 8
elseif t == "boolean" then
-- Booleans are passed by value so need not be touched, and cost 1
-- byte.
return msg, 1
elseif t == "table" then
-- Tables are duplicated. Check if this table has been seen before
-- (self-referential or shared table); if so, reuse the cleaned value
-- of the previous occurrence, maintaining table topology and avoiding
-- infinite recursion, and charge zero bytes for this as the object has
-- already been counted.
back_references = back_references or {}
local bref = back_references[msg]
if bref then
return bref, 0
end
-- Construct a new table by cleaning all the keys and values and adding
-- up their costs, plus 8 bytes as a rough estimate of table overhead.
local cost = 8
local ret = {}
back_references[msg] = ret
for k, v in pairs(msg) do
local k_cost, v_cost
k, k_cost = clean_and_weigh_digiline_message(k, back_references)
v, v_cost = clean_and_weigh_digiline_message(v, back_references)
if k ~= nil and v ~= nil then
-- Only include an element if its key and value are of legal
-- types.
ret[k] = v
end
-- If we only counted the cost of a table element when we actually
-- used it, we would be vulnerable to the following attack:
-- 1. Construct a huge table (too large to pass the cost limit).
-- 2. Insert it somewhere in a table, with a function as a key.
-- 3. Insert it somewhere in another table, with a number as a key.
-- 4. The first occurrence doesnt pay the cost because functions
-- are stripped and therefore the element is dropped.
-- 5. The second occurrence doesnt pay the cost because its in
-- back_references.
-- By counting the costs regardless of whether the objects will be
-- included, we avoid this attack; it may overestimate the cost of
-- some messages, but only those that wont be delivered intact
-- anyway because they contain illegal object types.
cost = cost + k_cost + v_cost
end
return ret, cost
else
return nil, 0
end
end
-- itbl: Flat table of functions to run after sandbox cleanup, used to prevent various security hazards
local function get_digiline_send(pos, itbl, send_warning)
if not minetest.global_exists("digilines") then return end
local chan_maxlen = mesecon.setting("luacontroller_digiline_channel_maxlen", 256)
local maxlen = mesecon.setting("luacontroller_digiline_maxlen", 50000)
return function(channel, msg) return function(channel, msg)
minetest.after(0, function() -- NOTE: This runs within string metatable sandbox, so don't *rely* on anything of the form (""):y
digiline:receptor_send(pos, digiline.rules.default, channel, msg) -- or via anything that could.
-- Make sure channel is string, number or boolean
if type(channel) == "string" then
if #channel > chan_maxlen then
send_warning("Channel string too long.")
return false
end
elseif (type(channel) ~= "string" and type(channel) ~= "number" and type(channel) ~= "boolean") then
send_warning("Channel must be string, number or boolean.")
return false
end
local msg_cost
msg, msg_cost = clean_and_weigh_digiline_message(msg)
if msg == nil or msg_cost > maxlen then
send_warning("Message was too complex, or contained invalid data.")
return false
end
table.insert(itbl, function ()
-- Runs outside of string metatable sandbox
local luac_id = minetest.get_meta(pos):get_int("luac_id")
mesecon.queue:add_action(pos, "lc_digiline_relay", {channel, luac_id, msg})
end) end)
return true
end end
end end
local safe_globals = { local safe_globals = {
-- Don't add pcall/xpcall unless willing to deal with the consequences (unless very careful, incredibly likely to allow killing server indirectly)
"assert", "error", "ipairs", "next", "pairs", "select", "assert", "error", "ipairs", "next", "pairs", "select",
"tonumber", "tostring", "type", "unpack", "_VERSION" "tonumber", "tostring", "type", "unpack", "_VERSION"
} }
local function create_environment(pos, mem, event)
local function create_environment(pos, mem, event, itbl, send_warning)
-- Gather variables for the environment -- Gather variables for the environment
local vports = minetest.registered_nodes[minetest.get_node(pos).name].virtual_portstates local vports = minetest.registered_nodes[minetest.get_node(pos).name].virtual_portstates
local vports_copy = {} local vports_copy = {}
for k, v in pairs(vports) do vports_copy[k] = v end for k, v in pairs(vports) do vports_copy[k] = v end
local rports = get_real_port_states(pos) local rports = get_real_port_states(pos)
-- Create new library tables on each call to prevent one LuaController -- Create new library tables on each call to prevent one Luacontroller
-- from breaking a library and messing up other LuaControllers. -- from breaking a library and messing up other Luacontrollers.
local env = { local env = {
pin = merge_port_states(vports, rports), pin = merge_port_states(vports, rports),
port = vports_copy, port = vports_copy,
event = event, event = event,
mem = mem, mem = mem,
heat = minetest.get_meta(pos):get_int("heat"), heat = mesecon.get_heat(pos),
heat_max = mesecon.setting("overheat_max", 20), heat_max = mesecon.setting("overheat_max", 20),
print = safe_print, print = safe_print,
interrupt = get_interrupt(pos), interrupt = get_interrupt(pos, itbl, send_warning),
digiline_send = get_digiline_send(pos), digiline_send = get_digiline_send(pos, itbl, send_warning),
string = { string = {
byte = string.byte, byte = string.byte,
char = string.char, char = string.char,
@ -392,10 +527,11 @@ local function create_sandbox(code, env)
jit.off(f, true) jit.off(f, true)
end end
local maxevents = mesecon.setting("luacontroller_maxevents", 10000)
return function(...) return function(...)
-- NOTE: This runs within string metatable sandbox, so the setting's been moved out for safety
-- Use instruction counter to stop execution -- Use instruction counter to stop execution
-- after luacontroller_maxevents -- after luacontroller_maxevents
local maxevents = mesecon.setting("luacontroller_maxevents", 10000)
debug.sethook(timeout, "", maxevents) debug.sethook(timeout, "", maxevents)
local ok, ret = pcall(f, ...) local ok, ret = pcall(f, ...)
debug.sethook() -- Clear hook debug.sethook() -- Clear hook
@ -406,7 +542,7 @@ end
local function load_memory(meta) local function load_memory(meta)
return minetest.deserialize(meta:get_string("lc_memory")) or {} return minetest.deserialize(meta:get_string("lc_memory"), true) or {}
end end
@ -423,26 +559,42 @@ local function save_memory(pos, meta, mem)
end end
end end
-- Returns success (boolean), errmsg (string)
local function run(pos, event) -- run (as opposed to run_inner) is responsible for setting up meta according to this output
local function run_inner(pos, code, event)
local meta = minetest.get_meta(pos) local meta = minetest.get_meta(pos)
if overheat(pos) then return end -- Note: These return success, presumably to avoid changing LC ID.
if ignore_event(event, meta) then return end if overheat(pos) then return true, "" end
if ignore_event(event, meta) then return true, "" end
-- Load code & mem from meta -- Load code & mem from meta
local mem = load_memory(meta) local mem = load_memory(meta)
local code = meta:get_string("code") local code = meta:get_string("code")
-- 'Last warning' label.
local warning = ""
local function send_warning(str)
warning = "Warning: " .. str
end
-- Create environment -- Create environment
local env = create_environment(pos, mem, event) local itbl = {}
local env = create_environment(pos, mem, event, itbl, send_warning)
-- Create the sandbox and execute code -- Create the sandbox and execute code
local f, msg = create_sandbox(code, env) local f, msg = create_sandbox(code, env)
if not f then return msg end if not f then return false, msg end
-- Start string true sandboxing
local onetruestring = getmetatable("")
-- If a string sandbox is already up yet inconsistent, something is very wrong
assert(onetruestring.__index == string)
onetruestring.__index = env.string
local success, msg = pcall(f) local success, msg = pcall(f)
if not success then return msg end onetruestring.__index = string
-- End string true sandboxing
if not success then return false, msg end
if type(env.port) ~= "table" then if type(env.port) ~= "table" then
return "Ports set are invalid." return false, "Ports set are invalid."
end end
-- Actually set the ports -- Actually set the ports
@ -450,8 +602,56 @@ local function run(pos, event)
-- Save memory. This may burn the luacontroller if a memory overflow occurs. -- Save memory. This may burn the luacontroller if a memory overflow occurs.
save_memory(pos, meta, env.mem) save_memory(pos, meta, env.mem)
-- Execute deferred tasks
for _, v in ipairs(itbl) do
local failure = v()
if failure then
return false, failure
end
end
return true, warning
end end
local function reset_formspec(meta, code, errmsg)
meta:set_string("code", code)
code = minetest.formspec_escape(code or "")
errmsg = minetest.formspec_escape(tostring(errmsg or ""))
meta:set_string("formspec", "size[12,10]"..
"background[-0.2,-0.25;12.4,10.75;jeija_luac_background.png]"..
"textarea[0.2,0.2;12.2,9.5;code;;"..code.."]"..
"image_button[4.75,8.75;2.5,1;jeija_luac_runbutton.png;program;]"..
"image_button_exit[11.72,-0.25;0.425,0.4;jeija_close_window.png;exit;]"..
"label[0.1,9;"..errmsg.."]")
end
local function reset_meta(pos, code, errmsg)
local meta = minetest.get_meta(pos)
reset_formspec(meta, code, errmsg)
meta:set_int("luac_id", math.random(1, 65535))
end
-- Wraps run_inner with LC-reset-on-error
local function run(pos, event)
local meta = minetest.get_meta(pos)
local code = meta:get_string("code")
local ok, errmsg = run_inner(pos, code, event)
if not ok then
reset_meta(pos, code, errmsg)
else
reset_formspec(meta, code, errmsg)
end
return ok, errmsg
end
local function reset(pos)
set_port_states(pos, {a=false, b=false, c=false, d=false})
end
-----------------------
-- A.Queue callbacks --
-----------------------
mesecon.queue:add_function("lc_interrupt", function (pos, luac_id, iid) mesecon.queue:add_function("lc_interrupt", function (pos, luac_id, iid)
-- There is no luacontroller anymore / it has been reprogrammed / replaced / burnt -- There is no luacontroller anymore / it has been reprogrammed / replaced / burnt
if (minetest.get_meta(pos):get_int("luac_id") ~= luac_id) then return end if (minetest.get_meta(pos):get_int("luac_id") ~= luac_id) then return end
@ -459,25 +659,14 @@ mesecon.queue:add_function("lc_interrupt", function (pos, luac_id, iid)
run(pos, {type="interrupt", iid = iid}) run(pos, {type="interrupt", iid = iid})
end) end)
local function reset_meta(pos, code, errmsg) mesecon.queue:add_function("lc_digiline_relay", function (pos, channel, luac_id, msg)
local meta = minetest.get_meta(pos) if not digiline then return end
meta:set_string("code", code) -- This check is only really necessary because in case of server crash, old actions can be thrown into the future
code = minetest.formspec_escape(code or "") if (minetest.get_meta(pos):get_int("luac_id") ~= luac_id) then return end
errmsg = minetest.formspec_escape(errmsg or "") if (minetest.registered_nodes[minetest.get_node(pos).name].is_burnt) then return end
meta:set_string("formspec", "size[10,8]".. -- The actual work
"background[-0.2,-0.25;10.4,8.75;jeija_luac_background.png]".. digiline:receptor_send(pos, digiline.rules.default, channel, msg)
"textarea[0.2,0.6;10.2,5;code;;"..code.."]".. end)
"image_button[3.75,6;2.5,1;jeija_luac_runbutton.png;program;]"..
"image_button_exit[9.72,-0.25;0.425,0.4;jeija_close_window.png;exit;]"..
"label[0.1,5;"..errmsg.."]")
meta:set_int("heat", 0)
meta:set_int("luac_id", math.random(1, 65535))
end
local function reset(pos)
set_port_states(pos, {a=false, b=false, c=false, d=false})
end
----------------------- -----------------------
-- Node Registration -- -- Node Registration --
@ -504,20 +693,36 @@ local digiline = {
receptor = {}, receptor = {},
effector = { effector = {
action = function(pos, node, channel, msg) action = function(pos, node, channel, msg)
msg = clean_and_weigh_digiline_message(msg)
run(pos, {type = "digiline", channel = channel, msg = msg}) run(pos, {type = "digiline", channel = channel, msg = msg})
end end
} }
} }
local function on_receive_fields(pos, form_name, fields)
local function get_program(pos)
local meta = minetest.get_meta(pos)
return meta:get_string("code")
end
local function set_program(pos, code)
reset(pos)
reset_meta(pos, code)
return run(pos, {type="program"})
end
local function on_receive_fields(pos, form_name, fields, sender)
if not fields.program then if not fields.program then
return return
end end
reset(pos) local name = sender:get_player_name()
reset_meta(pos, fields.code) if minetest.is_protected(pos, name) and not minetest.check_player_privs(name, {protection_bypass=true}) then
local err = run(pos, {type="program"}) minetest.record_protection_violation(pos, name)
if err then return
print(err) end
reset_meta(pos, fields.code, err) local ok, err = set_program(pos, fields.code)
if not ok then
-- it's not an error from the server perspective
minetest.log("action", "Lua controller programming error: " .. tostring(err))
end end
end end
@ -571,11 +776,15 @@ for d = 0, 1 do
receptor = { receptor = {
state = mesecon.state.on, state = mesecon.state.on,
rules = output_rules[cid] rules = output_rules[cid]
} },
luacontroller = {
get_program = get_program,
set_program = set_program,
},
} }
minetest.register_node(node_name, { minetest.register_node(node_name, {
description = "LuaController", description = "Luacontroller",
drawtype = "nodebox", drawtype = "nodebox",
tiles = { tiles = {
top, top,
@ -587,6 +796,7 @@ for d = 0, 1 do
}, },
inventory_image = top, inventory_image = top,
paramtype = "light", paramtype = "light",
is_ground_content = false,
groups = groups, groups = groups,
drop = BASENAME.."0000", drop = BASENAME.."0000",
sunlight_propagates = true, sunlight_propagates = true,
@ -606,9 +816,11 @@ for d = 0, 1 do
d = d == 1, d = d == 1,
}, },
after_dig_node = function (pos, node) after_dig_node = function (pos, node)
mesecon.do_cooldown(pos)
mesecon.receptor_off(pos, output_rules) mesecon.receptor_off(pos, output_rules)
end, end,
is_luacontroller = true, is_luacontroller = true,
on_blast = mesecon.on_blastnode,
}) })
end end
end end
@ -616,7 +828,7 @@ end
end end
------------------------------ ------------------------------
-- Overheated LuaController -- -- Overheated Luacontroller --
------------------------------ ------------------------------
minetest.register_node(BASENAME .. "_burnt", { minetest.register_node(BASENAME .. "_burnt", {
@ -632,6 +844,7 @@ minetest.register_node(BASENAME .. "_burnt", {
inventory_image = "jeija_luacontroller_burnt_top.png", inventory_image = "jeija_luacontroller_burnt_top.png",
is_burnt = true, is_burnt = true,
paramtype = "light", paramtype = "light",
is_ground_content = false,
groups = {dig_immediate=2, not_in_creative_inventory=1}, groups = {dig_immediate=2, not_in_creative_inventory=1},
drop = BASENAME.."0000", drop = BASENAME.."0000",
sunlight_propagates = true, sunlight_propagates = true,
@ -649,6 +862,7 @@ minetest.register_node(BASENAME .. "_burnt", {
end, end,
}, },
}, },
on_blast = mesecon.on_blastnode,
}) })
------------------------ ------------------------

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 718 B

View File

@ -1,6 +1,7 @@
EEPROM_SIZE = 255 local EEPROM_SIZE = 255
local microc_rules = {} local microc_rules = {}
local yc = {}
for a = 0, 1 do for a = 0, 1 do
for b = 0, 1 do for b = 0, 1 do
@ -20,6 +21,7 @@ end
if tostring(d) == "1" then if tostring(d) == "1" then
top = top.."^jeija_microcontroller_LED_D.png" top = top.."^jeija_microcontroller_LED_D.png"
end end
local groups
if tostring(d)..tostring(c)..tostring(b)..tostring(a) ~= "0000" then if tostring(d)..tostring(c)..tostring(b)..tostring(a) ~= "0000" then
groups = {dig_immediate=2, not_in_creative_inventory=1, mesecon = 3, overheat = 1} groups = {dig_immediate=2, not_in_creative_inventory=1, mesecon = 3, overheat = 1}
else else
@ -42,8 +44,8 @@ local mesecons = {effector =
{ {
rules = input_rules, rules = input_rules,
action_change = function (pos, node, rulename, newstate) action_change = function (pos, node, rulename, newstate)
yc_update_real_portstates(pos, node, rulename, newstate) yc.update_real_portstates(pos, node, rulename, newstate)
update_yc(pos) yc.update(pos)
end end
}} }}
if nodename ~= "mesecons_microcontroller:microcontroller0000" then if nodename ~= "mesecons_microcontroller:microcontroller0000" then
@ -67,6 +69,7 @@ minetest.register_node(nodename, {
sunlight_propagates = true, sunlight_propagates = true,
paramtype = "light", paramtype = "light",
is_ground_content = false,
walkable = true, walkable = true,
groups = groups, groups = groups,
drop = "mesecons_microcontroller:microcontroller0000 1", drop = "mesecons_microcontroller:microcontroller0000 1",
@ -100,6 +103,12 @@ minetest.register_node(nodename, {
meta:set_string("eeprom", r) meta:set_string("eeprom", r)
end, end,
on_receive_fields = function(pos, formanme, fields, sender) on_receive_fields = function(pos, formanme, fields, sender)
local player_name = sender:get_player_name()
if minetest.is_protected(pos, player_name) and
not minetest.check_player_privs(player_name, {protection_bypass=true}) then
minetest.record_protection_violation(pos, player_name)
return
end
local meta = minetest.get_meta(pos) local meta = minetest.get_meta(pos)
if fields.band then if fields.band then
fields.code = "sbi(C, A&B) :A and B are inputs, C is output" fields.code = "sbi(C, A&B) :A and B are inputs, C is output"
@ -127,8 +136,8 @@ minetest.register_node(nodename, {
"button[7.5,0.2;1.5,3;brsflop;RS-Flop]".. "button[7.5,0.2;1.5,3;brsflop;RS-Flop]"..
"button_exit[3.5,1;2,3;program;Program]") "button_exit[3.5,1;2,3;program;Program]")
meta:set_string("infotext", "Programmed Microcontroller") meta:set_string("infotext", "Programmed Microcontroller")
yc_reset (pos) yc.reset (pos)
update_yc(pos) yc.update(pos)
end, end,
sounds = default.node_sound_stone_defaults(), sounds = default.node_sound_stone_defaults(),
mesecons = mesecons, mesecons = mesecons,
@ -136,23 +145,37 @@ minetest.register_node(nodename, {
rules = microc_rules[node.name] rules = microc_rules[node.name]
mesecon.receptor_off(pos, rules) mesecon.receptor_off(pos, rules)
end, end,
on_blast = mesecon.on_blastnode,
}) })
end end
end end
end end
end end
minetest.register_craft({ if minetest.get_modpath("mesecons_luacontroller") then
output = 'craft "mesecons_microcontroller:microcontroller0000" 2', minetest.register_craft({
recipe = { type = "shapeless",
{'mesecons_materials:silicon', 'mesecons_materials:silicon', 'group:mesecon_conductor_craftable'}, output = "mesecons_microcontroller:microcontroller0000",
{'mesecons_materials:silicon', 'mesecons_materials:silicon', 'group:mesecon_conductor_craftable'}, recipe = {"mesecons_luacontroller:luacontroller0000"},
{'group:mesecon_conductor_craftable', 'group:mesecon_conductor_craftable', ''}, })
} minetest.register_craft({
}) type = "shapeless",
output = "mesecons_luacontroller:luacontroller0000",
recipe = {"mesecons_microcontroller:microcontroller0000"},
})
else
minetest.register_craft({
output = 'craft "mesecons_microcontroller:microcontroller0000" 2',
recipe = {
{'mesecons_materials:silicon', 'mesecons_materials:silicon', 'group:mesecon_conductor_craftable'},
{'mesecons_materials:silicon', 'mesecons_materials:silicon', 'group:mesecon_conductor_craftable'},
{'group:mesecon_conductor_craftable', 'group:mesecon_conductor_craftable', ''},
}
})
end
function yc_reset(pos) yc.reset = function(pos)
yc_action(pos, {a=false, b=false, c=false, d=false}) yc.action(pos, {a=false, b=false, c=false, d=false})
local meta = minetest.get_meta(pos) local meta = minetest.get_meta(pos)
meta:set_int("afterid", 0) meta:set_int("afterid", 0)
local r = "" local r = ""
@ -160,7 +183,7 @@ function yc_reset(pos)
meta:set_string("eeprom", r) meta:set_string("eeprom", r)
end end
function update_yc(pos) yc.update = function(pos)
local meta = minetest.get_meta(pos) local meta = minetest.get_meta(pos)
if (mesecon.do_overheat(pos)) then if (mesecon.do_overheat(pos)) then
@ -172,10 +195,10 @@ function update_yc(pos)
end end
local code = meta:get_string("code") local code = meta:get_string("code")
code = yc_code_remove_commentary(code) code = yc.code_remove_commentary(code)
code = string.gsub(code, " ", "") --Remove all spaces code = string.gsub(code, " ", "") --Remove all spaces
code = string.gsub(code, " ", "") --Remove all tabs code = string.gsub(code, " ", "") --Remove all tabs
if yc_parsecode(code, pos) == nil then if yc.parsecode(code, pos) == nil then
meta:set_string("infotext", "Code not valid!\n"..code) meta:set_string("infotext", "Code not valid!\n"..code)
else else
meta:set_string("infotext", "Working Microcontroller\n"..code) meta:set_string("infotext", "Working Microcontroller\n"..code)
@ -184,7 +207,7 @@ end
--Code Parsing --Code Parsing
function yc_code_remove_commentary(code) yc.code_remove_commentary = function(code)
local is_string = false local is_string = false
for i = 1, #code do for i = 1, #code do
if code:sub(i, i) == '"' then if code:sub(i, i) == '"' then
@ -196,50 +219,50 @@ function yc_code_remove_commentary(code)
return code return code
end end
function yc_parsecode(code, pos) yc.parsecode = function(code, pos)
local meta = minetest.get_meta(pos) local meta = minetest.get_meta(pos)
local endi = 1 local endi = 1
local Lreal = yc_get_real_portstates(pos) local Lreal = yc.get_real_portstates(pos)
local Lvirtual = yc_get_virtual_portstates(pos) local Lvirtual = yc.get_virtual_portstates(pos)
if Lvirtual == nil then return nil end if Lvirtual == nil then return nil end
local c local c
local eeprom = meta:get_string("eeprom") local eeprom = meta:get_string("eeprom")
while true do while true do
local command, params local command, params
command, endi = parse_get_command(code, endi) command, endi = yc.parse_get_command(code, endi)
if command == nil then return nil end if command == nil then return nil end
if command == true then break end --end of code if command == true then break end --end of code
if command == "if" then if command == "if" then
local r local r
r, endi = yc_command_if(code, endi, yc_merge_portstates(Lreal, Lvirtual), eeprom) r, endi = yc.command_if(code, endi, yc.merge_portstates(Lreal, Lvirtual), eeprom)
if r == nil then return nil end if r == nil then return nil end
if r == true then -- nothing if r == true then -- nothing
elseif r == false then elseif r == false then
local endi_new = yc_skip_to_else (code, endi) local endi_new = yc.skip_to_else (code, endi)
if endi_new == nil then --else > not found if endi_new == nil then --else > not found
endi = yc_skip_to_endif(code, endi) endi = yc.skip_to_endif(code, endi)
else else
endi = endi_new endi = endi_new
end end
if endi == nil then return nil end if endi == nil then return nil end
end end
else else
params, endi = parse_get_params(code, endi) params, endi = yc.parse_get_params(code, endi)
if not params then return nil end if not params then return nil end
end end
if command == "on" then if command == "on" then
L = yc_command_on (params, Lvirtual) L = yc.command_on (params, Lvirtual)
elseif command == "off" then elseif command == "off" then
L = yc_command_off(params, Lvirtual) L = yc.command_off(params, Lvirtual)
elseif command == "print" then elseif command == "print" then
local su = yc_command_print(params, eeprom, yc_merge_portstates(Lreal, Lvirtual)) local su = yc.command_print(params, eeprom, yc.merge_portstates(Lreal, Lvirtual))
if su ~= true then return nil end if su ~= true then return nil end
elseif command == "after" then elseif command == "after" then
local su = yc_command_after(params, pos) local su = yc.command_after(params, pos)
if su == nil then return nil end if su == nil then return nil end
elseif command == "sbi" then elseif command == "sbi" then
local new_eeprom local new_eeprom
new_eeprom, Lvirtual = yc_command_sbi (params, eeprom, yc_merge_portstates(Lreal, Lvirtual), Lvirtual) new_eeprom, Lvirtual = yc.command_sbi (params, eeprom, yc.merge_portstates(Lreal, Lvirtual), Lvirtual)
if new_eeprom == nil then return nil if new_eeprom == nil then return nil
else eeprom = new_eeprom end else eeprom = new_eeprom end
elseif command == "if" then --nothing elseif command == "if" then --nothing
@ -250,12 +273,12 @@ function yc_parsecode(code, pos)
if eeprom == nil then return nil else if eeprom == nil then return nil else
minetest.get_meta(pos):set_string("eeprom", eeprom) end minetest.get_meta(pos):set_string("eeprom", eeprom) end
end end
yc_action(pos, Lvirtual) yc.action(pos, Lvirtual)
return true return true
end end
function parse_get_command(code, starti) yc.parse_get_command = function(code, starti)
i = starti local i = starti
local s local s
while s ~= "" do while s ~= "" do
s = string.sub(code, i, i) s = string.sub(code, i, i)
@ -266,7 +289,7 @@ function parse_get_command(code, starti)
starti = starti + 1 starti = starti + 1
i = starti i = starti
elseif s == ">" then elseif s == ">" then
starti = yc_skip_to_endif(code, starti) starti = yc.skip_to_endif(code, starti)
if starti == nil then return nil end if starti == nil then return nil end
i = starti i = starti
else else
@ -280,8 +303,8 @@ function parse_get_command(code, starti)
return nil, nil return nil, nil
end end
function parse_get_params(code, starti) yc.parse_get_params = function(code, starti)
i = starti local i = starti
local s local s
local params = {} local params = {}
local is_string = false local is_string = false
@ -303,8 +326,8 @@ function parse_get_params(code, starti)
return nil, nil return nil, nil
end end
function yc_parse_get_eeprom_param(cond, starti) yc.parse_get_eeprom_param = function(cond, starti)
i = starti local i = starti
local s local s
local addr local addr
while s ~= "" do while s ~= "" do
@ -319,7 +342,7 @@ function yc_parse_get_eeprom_param(cond, starti)
return nil, nil return nil, nil
end end
function yc_skip_to_endif(code, starti) yc.skip_to_endif = function(code, starti)
local i = starti local i = starti
local s = false local s = false
local open_ifs = 1 local open_ifs = 1
@ -339,7 +362,7 @@ function yc_skip_to_endif(code, starti)
return nil return nil
end end
function yc_skip_to_else(code, starti) yc.skip_to_else = function(code, starti)
local i = starti local i = starti
local s = false local s = false
local open_ifs = 1 local open_ifs = 1
@ -360,29 +383,29 @@ function yc_skip_to_else(code, starti)
end end
--Commands --Commands
function yc_command_on(params, L) yc.command_on = function(params, L)
local rules = {} local rules = {}
for i, port in ipairs(params) do for i, port in ipairs(params) do
L = yc_set_portstate (port, true, L) L = yc.set_portstate (port, true, L)
end end
return L return L
end end
function yc_command_off(params, L) yc.command_off = function(params, L)
local rules = {} local rules = {}
for i, port in ipairs(params) do for i, port in ipairs(params) do
L = yc_set_portstate (port, false, L) L = yc.set_portstate (port, false, L)
end end
return L return L
end end
function yc_command_print(params, eeprom, L) yc.command_print = function(params, eeprom, L)
local s = "" local s = ""
for i, param in ipairs(params) do for i, param in ipairs(params) do
if param:sub(1,1) == '"' and param:sub(#param, #param) == '"' then if param:sub(1,1) == '"' and param:sub(#param, #param) == '"' then
s = s..param:sub(2, #param-1) s = s..param:sub(2, #param-1)
else else
r = yc_command_parsecondition(param, L, eeprom) r = yc.command_parsecondition(param, L, eeprom)
if r == "1" or r == "0" then if r == "1" or r == "0" then
s = s..r s = s..r
else return nil end else return nil end
@ -392,17 +415,17 @@ function yc_command_print(params, eeprom, L)
return true return true
end end
function yc_command_sbi(params, eeprom, L, Lv) yc.command_sbi = function(params, eeprom, L, Lv)
if params[1]==nil or params[2]==nil or params[3] ~=nil then return nil end if params[1]==nil or params[2]==nil or params[3] ~=nil then return nil end
local status = yc_command_parsecondition(params[2], L, eeprom) local status = yc.command_parsecondition(params[2], L, eeprom)
if status == nil then return nil, nil end if status == nil then return nil, nil end
if string.find("ABCD", params[1])~=nil and #params[1]==1 then --is a port if string.find("ABCD", params[1])~=nil and #params[1]==1 then --is a port
if status == "1" then if status == "1" then
Lv = yc_set_portstate (params[1], true, Lv) Lv = yc.set_portstate (params[1], true, Lv)
else else
Lv = yc_set_portstate (params[1], false, Lv) Lv = yc.set_portstate (params[1], false, Lv)
end end
return eeprom, Lv; return eeprom, Lv;
end end
@ -420,7 +443,7 @@ function yc_command_sbi(params, eeprom, L, Lv)
end end
-- after (delay) -- after (delay)
function yc_command_after(params, pos) yc.command_after = function(params, pos)
if params[1] == nil or params[2] == nil or params[3] ~= nil then return nil end if params[1] == nil or params[2] == nil or params[3] ~= nil then return nil end
--get time (maximum time is 200) --get time (maximum time is 200)
@ -436,14 +459,14 @@ function yc_command_after(params, pos)
local afterid = math.random(10000) local afterid = math.random(10000)
local meta = minetest.get_meta(pos) local meta = minetest.get_meta(pos)
meta:set_int("afterid", afterid) meta:set_int("afterid", afterid)
minetest.after(time, yc_command_after_execute, {pos = pos, code = code, afterid = afterid}) minetest.after(time, yc.command_after_execute, {pos = pos, code = code, afterid = afterid})
return true return true
end end
function yc_command_after_execute(params) yc.command_after_execute = function(params)
local meta = minetest.get_meta(params.pos) local meta = minetest.get_meta(params.pos)
if meta:get_int("afterid") == params.afterid then --make sure the node has not been changed if meta:get_int("afterid") == params.afterid then --make sure the node has not been changed
if yc_parsecode(params.code, params.pos) == nil then if yc.parsecode(params.code, params.pos) == nil then
meta:set_string("infotext", "Code in after() not valid!") meta:set_string("infotext", "Code in after() not valid!")
else else
if code ~= nil then if code ~= nil then
@ -456,22 +479,22 @@ function yc_command_after_execute(params)
end end
--If --If
function yc_command_if(code, starti, L, eeprom) yc.command_if = function(code, starti, L, eeprom)
local cond, endi = yc_command_if_getcondition(code, starti) local cond, endi = yc.command_if_getcondition(code, starti)
if cond == nil then return nil end if cond == nil then return nil end
cond = yc_command_parsecondition(cond, L, eeprom) cond = yc.command_parsecondition(cond, L, eeprom)
local result local result
if cond == "0" then result = false if cond == "0" then result = false
elseif cond == "1" then result = true end elseif cond == "1" then result = true end
if not result then end if not result then end
return result, endi --endi from local cond, endi = yc_command_if_getcondition(code, starti) return result, endi --endi from local cond, endi = yc.command_if_getcondition(code, starti)
end end
--Condition parsing --Condition parsing
function yc_command_if_getcondition(code, starti) yc.command_if_getcondition = function(code, starti)
i = starti local i = starti
local s local s
local brackets = 1 --1 Bracket to close local brackets = 1 --1 Bracket to close
while s ~= "" do while s ~= "" do
@ -494,7 +517,7 @@ function yc_command_if_getcondition(code, starti)
return nil, nil return nil, nil
end end
function yc_command_parsecondition(cond, L, eeprom) yc.command_parsecondition = function(cond, L, eeprom)
cond = string.gsub(cond, "A", tonumber(L.a and 1 or 0)) cond = string.gsub(cond, "A", tonumber(L.a and 1 or 0))
cond = string.gsub(cond, "B", tonumber(L.b and 1 or 0)) cond = string.gsub(cond, "B", tonumber(L.b and 1 or 0))
cond = string.gsub(cond, "C", tonumber(L.c and 1 or 0)) cond = string.gsub(cond, "C", tonumber(L.c and 1 or 0))
@ -506,8 +529,8 @@ function yc_command_parsecondition(cond, L, eeprom)
while i<=l do while i<=l do
local s = cond:sub(i,i) local s = cond:sub(i,i)
if s == "#" then if s == "#" then
local addr, endi = yc_parse_get_eeprom_param(cond, i+1) local addr, endi = yc.parse_get_eeprom_param(cond, i+1)
local buf = yc_eeprom_read(tonumber(addr), eeprom) local buf = yc.eeprom_read(tonumber(addr), eeprom)
if buf == nil then return nil end if buf == nil then return nil end
local call = cond:sub(i, endi-1) local call = cond:sub(i, endi-1)
cond = string.gsub(cond, call, buf) cond = string.gsub(cond, call, buf)
@ -580,14 +603,14 @@ function yc_command_parsecondition(cond, L, eeprom)
end end
--Virtual-Hardware functions --Virtual-Hardware functions
function yc_eeprom_read(number, eeprom) yc.eeprom_read = function(number, eeprom)
if not number then return end if not number then return end
return eeprom:sub(number, number) return eeprom:sub(number, number)
end end
--Real I/O functions --Real I/O functions
function yc_action(pos, L) --L-->Lvirtual yc.action = function(pos, L) --L-->Lvirtual
local Lv = yc_get_virtual_portstates(pos) local Lv = yc.get_virtual_portstates(pos)
local name = "mesecons_microcontroller:microcontroller" local name = "mesecons_microcontroller:microcontroller"
..tonumber(L.d and 1 or 0) ..tonumber(L.d and 1 or 0)
..tonumber(L.c and 1 or 0) ..tonumber(L.c and 1 or 0)
@ -596,10 +619,10 @@ function yc_action(pos, L) --L-->Lvirtual
local node = minetest.get_node(pos) local node = minetest.get_node(pos)
minetest.swap_node(pos, {name = name, param2 = node.param2}) minetest.swap_node(pos, {name = name, param2 = node.param2})
yc_action_setports(pos, L, Lv) yc.action_setports(pos, L, Lv)
end end
function yc_action_setports(pos, L, Lv) yc.action_setports = function(pos, L, Lv)
local name = "mesecons_microcontroller:microcontroller" local name = "mesecons_microcontroller:microcontroller"
local rules local rules
if Lv.a ~= L.a then if Lv.a ~= L.a then
@ -624,7 +647,7 @@ function yc_action_setports(pos, L, Lv)
end end
end end
function yc_set_portstate(port, state, L) yc.set_portstate = function(port, state, L)
if port == "A" then L.a = state if port == "A" then L.a = state
elseif port == "B" then L.b = state elseif port == "B" then L.b = state
elseif port == "C" then L.c = state elseif port == "C" then L.c = state
@ -633,7 +656,7 @@ function yc_set_portstate(port, state, L)
return L return L
end end
function yc_update_real_portstates(pos, node, rulename, newstate) yc.update_real_portstates = function(pos, node, rulename, newstate)
local meta = minetest.get_meta(pos) local meta = minetest.get_meta(pos)
if rulename == nil then if rulename == nil then
meta:set_int("real_portstates", 1) meta:set_int("real_portstates", 1)
@ -657,7 +680,7 @@ function yc_update_real_portstates(pos, node, rulename, newstate)
meta:set_int("real_portstates", 1 + L[1] + 2*L[2] + 4*L[3] + 8*L[4]) meta:set_int("real_portstates", 1 + L[1] + 2*L[2] + 4*L[3] + 8*L[4])
end end
function yc_get_real_portstates(pos) -- determine if ports are powered (by itself or from outside) yc.get_real_portstates = function(pos) -- determine if ports are powered (by itself or from outside)
local meta = minetest.get_meta(pos) local meta = minetest.get_meta(pos)
local L = {} local L = {}
local n = meta:get_int("real_portstates") - 1 local n = meta:get_int("real_portstates") - 1
@ -668,7 +691,7 @@ function yc_get_real_portstates(pos) -- determine if ports are powered (by itsel
return L return L
end end
function yc_get_virtual_portstates(pos) -- portstates according to the name yc.get_virtual_portstates = function(pos) -- portstates according to the name
local name = minetest.get_node(pos).name local name = minetest.get_node(pos).name
local b, a = string.find(name, ":microcontroller") local b, a = string.find(name, ":microcontroller")
if a == nil then return nil end if a == nil then return nil end
@ -682,7 +705,7 @@ function yc_get_virtual_portstates(pos) -- portstates according to the name
return Lvirtual return Lvirtual
end end
function yc_merge_portstates(Lreal, Lvirtual) yc.merge_portstates = function(Lreal, Lvirtual)
local L = {a=false, b=false, c=false, d=false} local L = {a=false, b=false, c=false, d=false}
if Lvirtual.a or Lreal.a then L.a = true end if Lvirtual.a or Lreal.a then L.a = true end
if Lvirtual.b or Lreal.b then L.b = true end if Lvirtual.b or Lreal.b then L.b = true end

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 9.6 KiB

View File

@ -8,124 +8,156 @@
-- Pushes all block in front of it -- Pushes all block in front of it
-- Pull all blocks in its back -- Pull all blocks in its back
function mesecon.get_movestone_direction(pos) -- settings:
local lpos local timer_interval = 1 / mesecon.setting("movestone_speed", 3)
local rules = { local max_push = mesecon.setting("movestone_max_push", 50)
{x=0, y=1, z=-1}, local max_pull = mesecon.setting("movestone_max_pull", 50)
{x=0, y=0, z=-1},
{x=0, y=-1, z=-1},
{x=0, y=1, z=1},
{x=0, y=-1, z=1},
{x=0, y=0, z=1},
{x=1, y=0, z=0},
{x=1, y=1, z=0},
{x=1, y=-1, z=0},
{x=-1, y=1, z=0},
{x=-1, y=-1, z=0},
{x=-1, y=0, z=0}}
lpos = {x=pos.x+1, y=pos.y, z=pos.z} -- helper functions:
for n = 1, 3 do local function get_movestone_direction(rulename, is_vertical)
if mesecon.is_power_on(lpos, rules[n].x, rules[n].y, rules[n].z) then if is_vertical then
return {x=0, y=0, z=-1} if rulename.z > 0 then
return {x = 0, y = -1, z = 0}
elseif rulename.z < 0 then
return {x = 0, y = 1, z = 0}
elseif rulename.x > 0 then
return {x = 0, y = -1, z = 0}
elseif rulename.x < 0 then
return {x = 0, y = 1, z = 0}
end end
end else
if rulename.z > 0 then
lpos = {x = pos.x-1, y = pos.y, z = pos.z} return {x = -1, y = 0, z = 0}
for n=4, 6 do elseif rulename.z < 0 then
if mesecon.is_power_on(lpos, rules[n].x, rules[n].y, rules[n].z) then return {x = 1, y = 0, z = 0}
return {x=0, y=0, z=1} elseif rulename.x > 0 then
end return {x = 0, y = 0, z = -1}
end elseif rulename.x < 0 then
return {x = 0, y = 0, z = 1}
lpos = {x = pos.x, y = pos.y, z = pos.z+1}
for n=7, 9 do
if mesecon.is_power_on(lpos, rules[n].x, rules[n].y, rules[n].z) then
return {x=-1, y=0, z=0}
end
end
lpos = {x = pos.x, y = pos.y, z = pos.z-1}
for n=10, 12 do
if mesecon.is_power_on(lpos, rules[n].x, rules[n].y, rules[n].z) then
return {x=1, y=0, z=0}
end end
end end
end end
function mesecon.register_movestone(name, def, is_sticky) -- registration functions:
local timer_interval = 1 / mesecon.setting("movestone_speed", 3) function mesecon.register_movestone(name, def, is_sticky, is_vertical)
local name_active = name.."_active" local function movestone_move(pos, node, rulename)
local direction = get_movestone_direction(rulename, is_vertical)
local function movestone_move (pos)
if minetest.get_node(pos).name ~= name_active then
return
end
local direction = mesecon.get_movestone_direction(pos)
if not direction then
minetest.set_node(pos, {name = name})
return
end
local frontpos = vector.add(pos, direction) local frontpos = vector.add(pos, direction)
local backpos = vector.subtract(pos, direction)
-- ### Step 1: Push nodes in front ### -- ### Step 1: Push nodes in front ###
local maxpush = mesecon.setting("movestone_max_push", 50) local success, stack, oldstack = mesecon.mvps_push(frontpos, direction, max_push)
local maxpull = mesecon.setting("movestone_max_pull", 50) if not success then
local success, stack, oldstack = mesecon.mvps_push(frontpos, direction, maxpush) minetest.get_node_timer(pos):start(timer_interval)
if success then
mesecon.mvps_process_stack(stack)
mesecon.mvps_move_objects(frontpos, direction, oldstack)
-- Too large stack/stopper in the way: try again very soon
else
minetest.after(0.05, movestone_move, pos)
return return
end end
mesecon.mvps_move_objects(frontpos, direction, oldstack)
-- ### Step 2: Move the movestone ### -- ### Step 2: Move the movestone ###
local node = minetest.get_node(pos)
minetest.set_node(frontpos, node) minetest.set_node(frontpos, node)
minetest.remove_node(pos) minetest.remove_node(pos)
mesecon.on_dignode(pos, node) mesecon.on_dignode(pos, node)
mesecon.on_placenode(frontpos, node) mesecon.on_placenode(frontpos, node)
minetest.after(timer_interval, movestone_move, frontpos) minetest.get_node_timer(frontpos):start(timer_interval)
-- ### Step 3: If sticky, pull stack behind ### -- ### Step 3: If sticky, pull stack behind ###
if is_sticky then if is_sticky then
mesecon.mvps_pull_all(backpos, direction, maxpull) local backpos = vector.subtract(pos, direction)
success, stack, oldstack = mesecon.mvps_pull_all(backpos, direction, max_pull)
if success then
mesecon.mvps_move_objects(backpos, vector.multiply(direction, -1), oldstack, -1)
end
end end
-- ### Step 4: Let things fall ###
minetest.check_for_falling(vector.add(pos, {x=0, y=1, z=0}))
end end
def.is_ground_content = false
def.mesecons = {effector = { def.mesecons = {effector = {
action_on = function (pos) action_on = function(pos, node, rulename)
if minetest.get_node(pos).name ~= name_active then if rulename and not minetest.get_node_timer(pos):is_started() then
minetest.set_node(pos, {name = name_active}) movestone_move(pos, node, rulename)
movestone_move(pos)
end end
end, end,
action_off = function (pos) rules = mesecon.rules.default,
minetest.set_node(pos, {name = name})
end
}} }}
def.drop = name def.on_timer = function(pos, elapsed)
local sourcepos = mesecon.is_powered(pos)
if not sourcepos then
return
end
local rulename = vector.subtract(sourcepos[1], pos)
mesecon.activate(pos, minetest.get_node(pos), rulename, 0)
end
def.on_blast = mesecon.on_blastnode
minetest.register_node(name, def) minetest.register_node(name, def)
-- active node only
local def_active = table.copy(def)
def_active.groups.not_in_creative_inventory = 1
minetest.register_node(name_active, def_active)
end end
mesecon.register_movestone("mesecons_movestones:movestone", {
tiles = {"jeija_movestone_side.png", "jeija_movestone_side.png", "jeija_movestone_side.png", "jeija_movestone_side.png", "jeija_movestone_arrows.png", "jeija_movestone_arrows.png"},
groups = {cracky=3},
description="Movestone",
sounds = default.node_sound_stone_defaults()
}, false)
-- registration:
mesecon.register_movestone("mesecons_movestones:movestone", {
tiles = {
"jeija_movestone_side.png",
"jeija_movestone_side.png",
"jeija_movestone_arrows.png^[transformFX",
"jeija_movestone_arrows.png^[transformFX",
"jeija_movestone_arrows.png",
"jeija_movestone_arrows.png",
},
groups = {cracky = 3},
description = "Movestone",
sounds = default.node_sound_stone_defaults()
}, false, false)
mesecon.register_movestone("mesecons_movestones:sticky_movestone", {
tiles = {
"jeija_movestone_side.png",
"jeija_movestone_side.png",
"jeija_sticky_movestone.png^[transformFX",
"jeija_sticky_movestone.png^[transformFX",
"jeija_sticky_movestone.png",
"jeija_sticky_movestone.png",
},
groups = {cracky = 3},
description = "Sticky Movestone",
sounds = default.node_sound_stone_defaults(),
}, true, false)
mesecon.register_movestone("mesecons_movestones:movestone_vertical", {
tiles = {
"jeija_movestone_side.png",
"jeija_movestone_side.png",
"jeija_movestone_arrows.png^[transformFXR90",
"jeija_movestone_arrows.png^[transformR90",
"jeija_movestone_arrows.png^[transformFXR90",
"jeija_movestone_arrows.png^[transformR90",
},
groups = {cracky = 3},
description = "Vertical Movestone",
sounds = default.node_sound_stone_defaults()
}, false, true)
mesecon.register_movestone("mesecons_movestones:sticky_movestone_vertical", {
tiles = {
"jeija_movestone_side.png",
"jeija_movestone_side.png",
"jeija_sticky_movestone.png^[transformFXR90",
"jeija_sticky_movestone.png^[transformR90",
"jeija_sticky_movestone.png^[transformFXR90",
"jeija_sticky_movestone.png^[transformR90",
},
groups = {cracky = 3},
description = "Vertical Sticky Movestone",
sounds = default.node_sound_stone_defaults(),
}, true, true)
-- crafting:
-- base recipe:
minetest.register_craft({ minetest.register_craft({
output = "mesecons_movestones:movestone 2", output = "mesecons_movestones:movestone 2",
recipe = { recipe = {
@ -135,22 +167,51 @@ minetest.register_craft({
} }
}) })
-- STICKY_MOVESTONE -- conversation:
mesecon.register_movestone("mesecons_movestones:sticky_movestone", { minetest.register_craft({
tiles = {"jeija_movestone_side.png", "jeija_movestone_side.png", "jeija_movestone_side.png", "jeija_movestone_side.png", "jeija_sticky_movestone.png", "jeija_sticky_movestone.png"}, type = "shapeless",
inventory_image = minetest.inventorycube("jeija_sticky_movestone.png", "jeija_movestone_side.png", "jeija_movestone_side.png"), output = "mesecons_movestones:movestone",
groups = {cracky=3}, recipe = {"mesecons_movestones:movestone_vertical"},
description="Sticky Movestone", })
sounds = default.node_sound_stone_defaults(),
}, true)
minetest.register_craft({ minetest.register_craft({
output = "mesecons_movestones:sticky_movestone 2", type = "shapeless",
output = "mesecons_movestones:movestone_vertical",
recipe = {"mesecons_movestones:movestone"},
})
minetest.register_craft({
type = "shapeless",
output = "mesecons_movestones:sticky_movestone",
recipe = {"mesecons_movestones:sticky_movestone_vertical"},
})
minetest.register_craft({
type = "shapeless",
output = "mesecons_movestones:sticky_movestone_vertical",
recipe = {"mesecons_movestones:sticky_movestone"},
})
-- make sticky:
minetest.register_craft({
output = "mesecons_movestones:sticky_movestone",
recipe = { recipe = {
{"mesecons_materials:glue", "mesecons_movestones:movestone", "mesecons_materials:glue"}, {"mesecons_materials:glue", "mesecons_movestones:movestone", "mesecons_materials:glue"},
} }
}) })
-- Don't allow pushing movestones while they're active minetest.register_craft({
mesecon.register_mvps_stopper("mesecons_movestones:movestone_active") output = "mesecons_movestones:sticky_movestone_vertical",
mesecon.register_mvps_stopper("mesecons_movestones:sticky_movestone_active") recipe = {
{"mesecons_materials:glue"},
{"mesecons_movestones:movestone_vertical"},
{"mesecons_materials:glue"},
}
})
-- legacy code:
minetest.register_alias("mesecons_movestones:movestone_active",
"mesecons_movestones:movestone")
minetest.register_alias("mesecons_movestones:sticky_movestone_active",
"mesecons_movestones:sticky_movestone")

View File

@ -165,6 +165,10 @@ function mesecon.mvps_push_or_pull(pos, stackdir, movedir, maximum, all_pull_sti
-- remove all nodes -- remove all nodes
for _, n in ipairs(nodes) do for _, n in ipairs(nodes) do
n.meta = minetest.get_meta(n.pos):to_table() n.meta = minetest.get_meta(n.pos):to_table()
local node_timer = minetest.get_node_timer(n.pos)
if node_timer:is_started() then
n.node_timer = {node_timer:get_timeout(), node_timer:get_elapsed()}
end
minetest.remove_node(n.pos) minetest.remove_node(n.pos)
end end
@ -179,6 +183,9 @@ function mesecon.mvps_push_or_pull(pos, stackdir, movedir, maximum, all_pull_sti
minetest.set_node(np, n.node) minetest.set_node(np, n.node)
minetest.get_meta(np):from_table(n.meta) minetest.get_meta(np):from_table(n.meta)
if n.node_timer then
minetest.get_node_timer(np):set(unpack(n.node_timer))
end
end end
local moved_nodes = {} local moved_nodes = {}
@ -190,6 +197,7 @@ function mesecon.mvps_push_or_pull(pos, stackdir, movedir, maximum, all_pull_sti
moved_nodes[i].pos = nodes[i].pos moved_nodes[i].pos = nodes[i].pos
moved_nodes[i].node = nodes[i].node moved_nodes[i].node = nodes[i].node
moved_nodes[i].meta = nodes[i].meta moved_nodes[i].meta = nodes[i].meta
moved_nodes[i].node_timer = nodes[i].node_timer
end end
on_mvps_move(moved_nodes) on_mvps_move(moved_nodes)
@ -197,46 +205,56 @@ function mesecon.mvps_push_or_pull(pos, stackdir, movedir, maximum, all_pull_sti
return true, nodes, oldstack return true, nodes, oldstack
end end
mesecon.register_on_mvps_move(function(moved_nodes) function mesecon.mvps_move_objects(pos, dir, nodestack, movefactor)
for _, n in ipairs(moved_nodes) do
mesecon.on_placenode(n.pos, n.node)
mesecon.update_autoconnect(n.pos)
end
end)
function mesecon.mvps_move_objects(pos, dir, nodestack)
local objects_to_move = {} local objects_to_move = {}
local dir_k
-- Move object at tip of stack, pushpos is position at tip of stack local dir_l
local pushpos = vector.add(pos, vector.multiply(dir, #nodestack)) for k, v in pairs(dir) do
if v ~= 0 then
local objects = minetest.get_objects_inside_radius(pushpos, 1) dir_k = k
for _, obj in ipairs(objects) do dir_l = v
table.insert(objects_to_move, obj) break
end
-- Move objects lying/standing on the stack (before it was pushed - oldstack)
if tonumber(minetest.setting_get("movement_gravity")) > 0 and dir.y == 0 then
-- If gravity positive and dir horizontal, push players standing on the stack
for _, n in ipairs(nodestack) do
local p_above = vector.add(n.pos, {x=0, y=1, z=0})
local objects = minetest.get_objects_inside_radius(p_above, 1)
for _, obj in ipairs(objects) do
table.insert(objects_to_move, obj)
end
end end
end end
movefactor = movefactor or 1
for _, obj in ipairs(objects_to_move) do dir = vector.multiply(dir, movefactor)
local entity = obj:get_luaentity() for id, obj in pairs(minetest.object_refs) do
if not entity or not mesecon.is_mvps_unmov(entity.name) then local obj_pos = obj:getpos()
local np = vector.add(obj:getpos(), dir) local cbox = obj:get_properties().collisionbox
local min_pos = vector.add(obj_pos, vector.new(cbox[1], cbox[2], cbox[3]))
--move only if destination is not solid local max_pos = vector.add(obj_pos, vector.new(cbox[4], cbox[5], cbox[6]))
local nn = minetest.get_node(np) local ok = true
if not ((not minetest.registered_nodes[nn.name]) for k, v in pairs(pos) do
or minetest.registered_nodes[nn.name].walkable) then local edge1, edge2
obj:setpos(np) if k ~= dir_k then
edge1 = v - 0.51 -- More than 0.5 to move objects near to the stack.
edge2 = v + 0.51
else
edge1 = v - 0.5 * dir_l
edge2 = v + (#nodestack + 0.5 * movefactor) * dir_l
-- Make sure, edge1 is bigger than edge2:
if edge1 > edge2 then
edge1, edge2 = edge2, edge1
end
end
if min_pos[k] > edge2 or max_pos[k] < edge1 then
ok = false
break
end
end
if ok then
local ent = obj:get_luaentity()
if obj:is_player() or (ent and not mesecon.is_mvps_unmov(ent.name)) then
local np = vector.add(obj_pos, dir)
-- Move only if destination is not solid or object is inside stack:
local nn = minetest.get_node(np)
local node_def = minetest.registered_nodes[nn.name]
local obj_offset = dir_l * (obj_pos[dir_k] - pos[dir_k])
if (node_def and not node_def.walkable) or
(obj_offset >= 0 and
obj_offset <= #nodestack - 0.5) then
obj:move_to(np)
end
end end
end end
end end
@ -247,3 +265,19 @@ mesecon.register_mvps_stopper("doors:door_steel_t_1")
mesecon.register_mvps_stopper("doors:door_steel_b_2") mesecon.register_mvps_stopper("doors:door_steel_b_2")
mesecon.register_mvps_stopper("doors:door_steel_t_2") mesecon.register_mvps_stopper("doors:door_steel_t_2")
mesecon.register_mvps_stopper("default:chest_locked") mesecon.register_mvps_stopper("default:chest_locked")
mesecon.register_on_mvps_move(mesecon.move_hot_nodes)
mesecon.register_on_mvps_move(function(moved_nodes)
for i = 1, #moved_nodes do
local moved_node = moved_nodes[i]
mesecon.on_placenode(moved_node.pos, moved_node.node)
minetest.after(0, function()
minetest.check_for_falling(moved_node.oldpos)
minetest.check_for_falling(moved_node.pos)
end)
local node_def = minetest.registered_nodes[moved_node.node.name]
if node_def and node_def.mesecon and node_def.mesecon.on_mvps_move then
node_def.mesecon.on_mvps_move(moved_node.pos, moved_node.node,
moved_node.oldpos, moved_node.meta)
end
end
end)

View File

@ -1,6 +1,7 @@
minetest.register_node("mesecons_noteblock:noteblock", { minetest.register_node("mesecons_noteblock:noteblock", {
description = "Noteblock", description = "Noteblock",
tiles = {"mesecons_noteblock.png"}, tiles = {"mesecons_noteblock.png"},
is_ground_content = false,
groups = {snappy=2, choppy=2, oddly_breakable_by_hand=2}, groups = {snappy=2, choppy=2, oddly_breakable_by_hand=2},
on_punch = function(pos, node) -- change sound when punched on_punch = function(pos, node) -- change sound when punched
node.param2 = (node.param2+1)%12 node.param2 = (node.param2+1)%12
@ -12,7 +13,8 @@ minetest.register_node("mesecons_noteblock:noteblock", {
action_on = function(pos, node) action_on = function(pos, node)
mesecon.noteblock_play(pos, node.param2) mesecon.noteblock_play(pos, node.param2)
end end
}} }},
on_blast = mesecon.on_blastnode,
}) })
minetest.register_craft({ minetest.register_craft({

View File

@ -1,62 +1,63 @@
local specs = {
normal = {
offname = "mesecons_pistons:piston_normal_off",
onname = "mesecons_pistons:piston_normal_on",
pusher = "mesecons_pistons:piston_pusher_normal",
},
sticky = {
offname = "mesecons_pistons:piston_sticky_off",
onname = "mesecons_pistons:piston_sticky_on",
pusher = "mesecons_pistons:piston_pusher_sticky",
sticky = true,
},
}
local function get_pistonspec_name(name, part)
if part then
for spec_name, spec in pairs(specs) do
if name == spec[part] then
return spec_name, part
end
end
return
end
for spec_name, spec in pairs(specs) do
for part, value in pairs(spec) do
if name == value then
return spec_name, part
end
end
end
end
local function get_pistonspec(name, part)
return specs[get_pistonspec_name(name, part)]
end
local max_push = mesecon.setting("piston_max_push", 15)
local max_pull = mesecon.setting("piston_max_pull", 15)
-- Get mesecon rules of pistons -- Get mesecon rules of pistons
piston_rules = local function piston_get_rules(node)
{{x=0, y=0, z=1}, --everything apart from z- (pusher side) local dir = minetest.facedir_to_dir(node.param2)
{x=1, y=0, z=0}, for k, v in pairs(dir) do
{x=-1, y=0, z=0}, if v ~= 0 then
{x=1, y=1, z=0}, dir = {k, -v}
{x=1, y=-1, z=0}, break
{x=-1, y=1, z=0}, end
{x=-1, y=-1, z=0}, end
{x=0, y=1, z=1}, local rules = table.copy(mesecon.rules.default)
{x=0, y=-1, z=1}} for i, rule in ipairs(rules) do
if rule[dir[1]] == dir[2] then
local piston_up_rules = table.remove(rules, i)
{{x=0, y=0, z=-1}, --everything apart from y+ (pusher side) end
{x=1, y=0, z=0},
{x=-1, y=0, z=0},
{x=0, y=0, 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}}
local piston_down_rules =
{{x=0, y=0, z=-1}, --everything apart from y- (pusher side)
{x=1, y=0, z=0},
{x=-1, y=0, z=0},
{x=0, y=0, 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}}
local piston_get_rules = function (node)
local rules = piston_rules
for i = 1, node.param2 do
rules = mesecon.rotate_rules_left(rules)
end end
return rules return rules
end end
piston_facedir_direction = function (node) local function piston_remove_pusher(pos, node)
local rules = {{x = 0, y = 0, z = -1}} local pistonspec = get_pistonspec(node.name, "onname")
for i = 1, node.param2 do local dir = vector.multiply(minetest.facedir_to_dir(node.param2), -1)
rules = mesecon.rotate_rules_left(rules)
end
return rules[1]
end
piston_get_direction = function(dir, node)
if type(dir) == "function" then
return dir(node)
else
return dir
end
end
local piston_remove_pusher = function(pos, node)
local pistonspec = minetest.registered_nodes[node.name].mesecons_piston
local dir = piston_get_direction(pistonspec.dir, node)
local pusherpos = vector.add(pos, dir) local pusherpos = vector.add(pos, dir)
local pushername = minetest.get_node(pusherpos).name local pushername = minetest.get_node(pusherpos).name
@ -71,67 +72,166 @@ local piston_remove_pusher = function(pos, node)
max_hear_distance = 20, max_hear_distance = 20,
gain = 0.3, gain = 0.3,
}) })
nodeupdate(pusherpos) minetest.check_for_falling(pusherpos)
end end
local piston_on = function(pos, node) local piston_on = function(pos, node)
local pistonspec = minetest.registered_nodes[node.name].mesecons_piston local pistonspec = get_pistonspec(node.name, "offname")
local dir = vector.multiply(minetest.facedir_to_dir(node.param2), -1)
local dir = piston_get_direction(pistonspec.dir, node) local pusher_pos = vector.add(pos, dir)
local np = vector.add(pos, dir) local success, stack, oldstack = mesecon.mvps_push(pusher_pos, dir, max_push)
local maxpush = mesecon.setting("piston_max_push", 15) if not success then
local success, stack, oldstack = mesecon.mvps_push(np, dir, maxpush) return
if success then
minetest.set_node(pos, {param2 = node.param2, name = pistonspec.onname})
minetest.set_node(np, {param2 = node.param2, name = pistonspec.pusher})
minetest.sound_play("piston_extend", {
pos = pos,
max_hear_distance = 20,
gain = 0.3,
})
mesecon.mvps_process_stack(stack)
mesecon.mvps_move_objects(np, dir, oldstack)
end end
minetest.set_node(pos, {param2 = node.param2, name = pistonspec.onname})
minetest.set_node(pusher_pos, {param2 = node.param2, name = pistonspec.pusher})
minetest.sound_play("piston_extend", {
pos = pos,
max_hear_distance = 20,
gain = 0.3,
})
mesecon.mvps_process_stack(stack)
mesecon.mvps_move_objects(pusher_pos, dir, oldstack)
end end
local piston_off = function(pos, node) local function piston_off(pos, node)
local pistonspec = minetest.registered_nodes[node.name].mesecons_piston local pistonspec = get_pistonspec(node.name, "onname")
minetest.set_node(pos, {param2 = node.param2, name = pistonspec.offname}) minetest.set_node(pos, {param2 = node.param2, name = pistonspec.offname})
piston_remove_pusher(pos, node) piston_remove_pusher(pos, node)
if pistonspec.sticky then if not pistonspec.sticky then
local maxpull = mesecon.setting("piston_max_pull", 15) return
local dir = piston_get_direction(pistonspec.dir, node) end
local pullpos = vector.add(pos, vector.multiply(dir, 2)) local dir = minetest.facedir_to_dir(node.param2)
local stack = mesecon.mvps_pull_single(pullpos, vector.multiply(dir, -1), maxpull) local pullpos = vector.add(pos, vector.multiply(dir, -2))
mesecon.mvps_process_stack(pos, dir, stack) local success, stack, oldstack = mesecon.mvps_pull_single(pullpos, dir, max_pull)
if success then
mesecon.mvps_move_objects(pullpos, vector.multiply(dir, -1), oldstack, -1)
end end
end end
local piston_orientate = function(pos, placer) local orientations = {
-- not placed by player [0] = { 4, 8},
if not placer then return end {13, 17},
{10, 6},
-- placer pitch in degrees {20, 15},
local pitch = placer:get_look_pitch() * (180 / math.pi) }
local function piston_orientate(pos, placer)
if not placer then
return
end
local pitch = math.deg(placer:get_look_vertical())
local node = minetest.get_node(pos) local node = minetest.get_node(pos)
local pistonspec = minetest.registered_nodes[node.name].mesecons_piston if pitch > 55 then
node.param2 = orientations[node.param2][1]
elseif pitch < -55 then
node.param2 = orientations[node.param2][2]
else
return
end
minetest.swap_node(pos, node)
-- minetest.after, because on_placenode for unoriented piston must be processed first
minetest.after(0, mesecon.on_placenode, pos, node)
end
-- looking upwards (pitch > 55) / looking downwards (pitch < -55) local rotations = {
local nn = nil {0, 16, 20, 12},
if pitch > 55 then nn = {name = pistonspec.piston_down} end {2, 14, 22, 18},
if pitch < -55 then nn = {name = pistonspec.piston_up} end {1, 5, 23, 9},
{3, 11, 21, 7},
{4, 13, 10, 19},
{6, 15, 8, 17},
}
if nn then local function get_rotation(param2)
minetest.set_node(pos, nn) for a = 1, #rotations do
-- minetest.after, because on_placenode for unoriented piston must be processed first for f = 1, #rotations[a] do
minetest.after(0, mesecon.on_placenode, pos, nn) if rotations[a][f] == param2 then
return a, f
end
end
end end
end end
local function rotate(param2, mode)
local axis, face = get_rotation(param2)
if mode == screwdriver.ROTATE_FACE then
face = face + 1
if face > 4 then
face = 1
end
elseif mode == screwdriver.ROTATE_AXIS then
axis = axis + 1
if axis > 6 then
axis = 1
end
face = 1
else
return param2
end
return rotations[axis][face]
end
-- Horizontal pistons local function piston_rotate(pos, node, _, mode)
node.param2 = rotate(node.param2, mode)
minetest.swap_node(pos, node)
mesecon.execute_autoconnect_hooks_now(pos, node)
return true
end
local function piston_rotate_on(pos, node, player, mode)
local pistonspec = get_pistonspec(node.name, "onname")
local dir = vector.multiply(minetest.facedir_to_dir(node.param2), -1)
local pusher_pos = vector.add(dir, pos)
local pusher_node = minetest.get_node(pusher_pos)
if pusher_node.name ~= pistonspec.pusher then
return piston_rotate(pos, node, nil, mode)
end
if mode == screwdriver.ROTATE_FACE then
piston_rotate(pusher_pos, pusher_node, nil, mode)
return piston_rotate(pos, node, nil, mode)
elseif mode ~= screwdriver.ROTATE_AXIS then
return false
end
local player_name = player and player:is_player() and player:get_player_name() or ""
local ok, dir_after, pusher_pos_after
for i = 1, 5 do
node.param2 = rotate(node.param2, mode)
dir_after = vector.multiply(minetest.facedir_to_dir(node.param2), -1)
pusher_pos_after = vector.add(dir_after, pos)
local pusher_pos_after_node_name = minetest.get_node(pusher_pos_after).name
local pusher_pos_after_node_def = minetest.registered_nodes[pusher_pos_after_node_name]
if pusher_pos_after_node_def and pusher_pos_after_node_def.buildable_to and
not minetest.is_protected(pusher_pos_after, player_name) then
ok = true
break
end
end
if not ok then
return false
end
pusher_node.param2 = node.param2
minetest.remove_node(pusher_pos)
minetest.set_node(pusher_pos_after, pusher_node)
minetest.swap_node(pos, node)
mesecon.execute_autoconnect_hooks_now(pos, node)
return true
end
local function piston_rotate_pusher(pos, node, player, mode)
local pistonspec = get_pistonspec(node.name, "pusher")
local piston_pos = vector.add(pos, minetest.facedir_to_dir(node.param2))
local piston_node = minetest.get_node(piston_pos)
if piston_node.name ~= pistonspec.onname then
minetest.remove_node(pos) -- Make it possible to remove alone pushers.
return false
end
return piston_rotate_on(piston_pos, piston_node, player, mode)
end
-- Boxes:
local pt = 3/16 -- pusher thickness local pt = 3/16 -- pusher thickness
@ -140,28 +240,18 @@ local piston_pusher_box = {
fixed = { fixed = {
{-2/16, -2/16, -.5 + pt, 2/16, 2/16, .5 + pt}, {-2/16, -2/16, -.5 + pt, 2/16, 2/16, .5 + pt},
{-.5 , -.5 , -.5 , .5 , .5 , -.5 + pt}, {-.5 , -.5 , -.5 , .5 , .5 , -.5 + pt},
} },
} }
local piston_on_box = { local piston_on_box = {
type = "fixed", type = "fixed",
fixed = { fixed = {
{-.5, -.5, -.5 + pt, .5, .5, .5} {-.5, -.5, -.5 + pt, .5, .5, .5}
} },
} }
-- Normal (non-sticky) ones: -- Normal (non-sticky) Pistons:
local pistonspec_normal = {
offname = "mesecons_pistons:piston_normal_off",
onname = "mesecons_pistons:piston_normal_on",
dir = piston_facedir_direction,
pusher = "mesecons_pistons:piston_pusher_normal",
piston_down = "mesecons_pistons:piston_down_normal_off",
piston_up = "mesecons_pistons:piston_up_normal_off",
}
-- offstate -- offstate
minetest.register_node("mesecons_pistons:piston_normal_off", { minetest.register_node("mesecons_pistons:piston_normal_off", {
description = "Piston", description = "Piston",
@ -172,20 +262,23 @@ minetest.register_node("mesecons_pistons:piston_normal_off", {
"mesecons_piston_right.png", "mesecons_piston_right.png",
"mesecons_piston_back.png", "mesecons_piston_back.png",
"mesecons_piston_pusher_front.png" "mesecons_piston_pusher_front.png"
}, },
groups = {cracky = 3}, groups = {cracky = 3},
paramtype2 = "facedir", paramtype2 = "facedir",
is_ground_content = false,
after_place_node = piston_orientate, after_place_node = piston_orientate,
mesecons_piston = pistonspec_normal,
sounds = default.node_sound_wood_defaults(), sounds = default.node_sound_wood_defaults(),
mesecons = {effector={ mesecons = {effector={
action_on = piston_on, action_on = piston_on,
rules = piston_get_rules rules = piston_get_rules,
}} }},
on_rotate = piston_rotate,
on_blast = mesecon.on_blastnode,
}) })
-- onstate -- onstate
minetest.register_node("mesecons_pistons:piston_normal_on", { minetest.register_node("mesecons_pistons:piston_normal_on", {
description = "Activated Piston Base",
drawtype = "nodebox", drawtype = "nodebox",
tiles = { tiles = {
"mesecons_piston_top.png", "mesecons_piston_top.png",
@ -194,26 +287,27 @@ minetest.register_node("mesecons_pistons:piston_normal_on", {
"mesecons_piston_right.png", "mesecons_piston_right.png",
"mesecons_piston_back.png", "mesecons_piston_back.png",
"mesecons_piston_on_front.png" "mesecons_piston_on_front.png"
}, },
inventory_image = "mesecons_piston_top.png",
wield_image = "mesecons_piston_top.png",
groups = {cracky = 3, not_in_creative_inventory = 1}, groups = {cracky = 3, not_in_creative_inventory = 1},
paramtype = "light", paramtype = "light",
paramtype2 = "facedir", paramtype2 = "facedir",
is_ground_content = false,
drop = "mesecons_pistons:piston_normal_off", drop = "mesecons_pistons:piston_normal_off",
after_dig_node = piston_remove_pusher, after_dig_node = piston_remove_pusher,
node_box = piston_on_box, node_box = piston_on_box,
selection_box = piston_on_box, selection_box = piston_on_box,
mesecons_piston = pistonspec_normal,
sounds = default.node_sound_wood_defaults(), sounds = default.node_sound_wood_defaults(),
mesecons = {effector={ mesecons = {effector={
action_off = piston_off, action_off = piston_off,
rules = piston_get_rules rules = piston_get_rules,
}} }},
on_rotate = piston_rotate_on,
on_blast = mesecon.on_blastnode,
}) })
-- pusher -- pusher
minetest.register_node("mesecons_pistons:piston_pusher_normal", { minetest.register_node("mesecons_pistons:piston_pusher_normal", {
description = "Piston Pusher",
drawtype = "nodebox", drawtype = "nodebox",
tiles = { tiles = {
"mesecons_piston_pusher_top.png", "mesecons_piston_pusher_top.png",
@ -222,27 +316,20 @@ minetest.register_node("mesecons_pistons:piston_pusher_normal", {
"mesecons_piston_pusher_right.png", "mesecons_piston_pusher_right.png",
"mesecons_piston_pusher_back.png", "mesecons_piston_pusher_back.png",
"mesecons_piston_pusher_front.png" "mesecons_piston_pusher_front.png"
}, },
groups = {not_in_creative_inventory = 1},
paramtype = "light", paramtype = "light",
paramtype2 = "facedir", paramtype2 = "facedir",
is_ground_content = false,
diggable = false, diggable = false,
corresponding_piston = "mesecons_pistons:piston_normal_on",
selection_box = piston_pusher_box, selection_box = piston_pusher_box,
node_box = piston_pusher_box, node_box = piston_pusher_box,
on_rotate = piston_rotate_pusher,
drop = "",
sounds = default.node_sound_wood_defaults(),
}) })
-- Sticky ones -- Sticky ones
local pistonspec_sticky = {
offname = "mesecons_pistons:piston_sticky_off",
onname = "mesecons_pistons:piston_sticky_on",
dir = piston_facedir_direction,
pusher = "mesecons_pistons:piston_pusher_sticky",
sticky = true,
piston_down = "mesecons_pistons:piston_down_sticky_off",
piston_up = "mesecons_pistons:piston_up_sticky_off",
}
-- offstate -- offstate
minetest.register_node("mesecons_pistons:piston_sticky_off", { minetest.register_node("mesecons_pistons:piston_sticky_off", {
description = "Sticky Piston", description = "Sticky Piston",
@ -253,20 +340,23 @@ minetest.register_node("mesecons_pistons:piston_sticky_off", {
"mesecons_piston_right.png", "mesecons_piston_right.png",
"mesecons_piston_back.png", "mesecons_piston_back.png",
"mesecons_piston_pusher_front_sticky.png" "mesecons_piston_pusher_front_sticky.png"
}, },
groups = {cracky = 3}, groups = {cracky = 3},
paramtype2 = "facedir", paramtype2 = "facedir",
is_ground_content = false,
after_place_node = piston_orientate, after_place_node = piston_orientate,
mesecons_piston = pistonspec_sticky,
sounds = default.node_sound_wood_defaults(), sounds = default.node_sound_wood_defaults(),
mesecons = {effector={ mesecons = {effector={
action_on = piston_on, action_on = piston_on,
rules = piston_get_rules rules = piston_get_rules,
}} }},
on_rotate = piston_rotate,
on_blast = mesecon.on_blastnode,
}) })
-- onstate -- onstate
minetest.register_node("mesecons_pistons:piston_sticky_on", { minetest.register_node("mesecons_pistons:piston_sticky_on", {
description = "Activated Sticky Piston Base",
drawtype = "nodebox", drawtype = "nodebox",
tiles = { tiles = {
"mesecons_piston_top.png", "mesecons_piston_top.png",
@ -275,26 +365,27 @@ minetest.register_node("mesecons_pistons:piston_sticky_on", {
"mesecons_piston_right.png", "mesecons_piston_right.png",
"mesecons_piston_back.png", "mesecons_piston_back.png",
"mesecons_piston_on_front.png" "mesecons_piston_on_front.png"
}, },
inventory_image = "mesecons_piston_top.png",
wield_image = "mesecons_piston_top.png",
groups = {cracky = 3, not_in_creative_inventory = 1}, groups = {cracky = 3, not_in_creative_inventory = 1},
paramtype = "light", paramtype = "light",
paramtype2 = "facedir", paramtype2 = "facedir",
is_ground_content = false,
drop = "mesecons_pistons:piston_sticky_off", drop = "mesecons_pistons:piston_sticky_off",
after_dig_node = piston_remove_pusher, after_dig_node = piston_remove_pusher,
node_box = piston_on_box, node_box = piston_on_box,
selection_box = piston_on_box, selection_box = piston_on_box,
mesecons_piston = pistonspec_sticky,
sounds = default.node_sound_wood_defaults(), sounds = default.node_sound_wood_defaults(),
mesecons = {effector={ mesecons = {effector={
action_off = piston_off, action_off = piston_off,
rules = piston_get_rules rules = piston_get_rules,
}} }},
on_rotate = piston_rotate_on,
on_blast = mesecon.on_blastnode,
}) })
-- pusher -- pusher
minetest.register_node("mesecons_pistons:piston_pusher_sticky", { minetest.register_node("mesecons_pistons:piston_pusher_sticky", {
description = "Sticky Piston Pusher",
drawtype = "nodebox", drawtype = "nodebox",
tiles = { tiles = {
"mesecons_piston_pusher_top.png", "mesecons_piston_pusher_top.png",
@ -303,399 +394,38 @@ minetest.register_node("mesecons_pistons:piston_pusher_sticky", {
"mesecons_piston_pusher_right.png", "mesecons_piston_pusher_right.png",
"mesecons_piston_pusher_back.png", "mesecons_piston_pusher_back.png",
"mesecons_piston_pusher_front_sticky.png" "mesecons_piston_pusher_front_sticky.png"
}, },
groups = {not_in_creative_inventory = 1},
paramtype = "light", paramtype = "light",
paramtype2 = "facedir", paramtype2 = "facedir",
is_ground_content = false,
diggable = false, diggable = false,
corresponding_piston = "mesecons_pistons:piston_sticky_on",
selection_box = piston_pusher_box, selection_box = piston_pusher_box,
node_box = piston_pusher_box, node_box = piston_pusher_box,
}) on_rotate = piston_rotate_pusher,
drop = "",
--
--
-- UP
--
--
local piston_up_pusher_box = {
type = "fixed",
fixed = {
{-2/16, -.5 - pt, -2/16, 2/16, .5 - pt, 2/16},
{-.5 , .5 - pt, -.5 , .5 , .5 , .5},
}
}
local piston_up_on_box = {
type = "fixed",
fixed = {
{-.5, -.5, -.5 , .5, .5-pt, .5}
}
}
-- Normal
local pistonspec_normal_up = {
offname = "mesecons_pistons:piston_up_normal_off",
onname = "mesecons_pistons:piston_up_normal_on",
dir = {x = 0, y = 1, z = 0},
pusher = "mesecons_pistons:piston_up_pusher_normal"
}
-- offstate
minetest.register_node("mesecons_pistons:piston_up_normal_off", {
tiles = {
"mesecons_piston_pusher_front.png",
"mesecons_piston_back.png",
"mesecons_piston_left.png^[transformR270",
"mesecons_piston_right.png^[transformR90",
"mesecons_piston_bottom.png",
"mesecons_piston_top.png^[transformR180",
},
inventory_image = "mesecons_piston_top.png",
wield_image = "mesecons_piston_top.png",
groups = {cracky = 3, not_in_creative_inventory = 1},
paramtype2 = "facedir",
drop = "mesecons_pistons:piston_normal_off",
mesecons_piston = pistonspec_normal_up,
mesecons = {effector={
action_on = piston_on,
rules = piston_up_rules,
}}
})
-- onstate
minetest.register_node("mesecons_pistons:piston_up_normal_on", {
drawtype = "nodebox",
tiles = {
"mesecons_piston_on_front.png",
"mesecons_piston_back.png",
"mesecons_piston_left.png^[transformR270",
"mesecons_piston_right.png^[transformR90",
"mesecons_piston_bottom.png",
"mesecons_piston_top.png^[transformR180",
},
inventory_image = "mesecons_piston_top.png",
wield_image = "mesecons_piston_top.png",
groups = {cracky = 3, not_in_creative_inventory = 1},
paramtype = "light",
paramtype2 = "facedir",
drop = "mesecons_pistons:piston_normal_off",
after_dig_node = piston_remove_pusher,
node_box = piston_up_on_box,
selection_box = piston_up_on_box,
mesecons_piston = pistonspec_normal_up,
sounds = default.node_sound_wood_defaults(), sounds = default.node_sound_wood_defaults(),
mesecons = {effector={
action_off = piston_off,
rules = piston_up_rules,
}}
})
-- pusher
minetest.register_node("mesecons_pistons:piston_up_pusher_normal", {
drawtype = "nodebox",
tiles = {
"mesecons_piston_pusher_front.png",
"mesecons_piston_pusher_back.png",
"mesecons_piston_pusher_left.png^[transformR270",
"mesecons_piston_pusher_right.png^[transformR90",
"mesecons_piston_pusher_bottom.png",
"mesecons_piston_pusher_top.png^[transformR180",
},
paramtype = "light",
paramtype2 = "facedir",
diggable = false,
corresponding_piston = "mesecons_pistons:piston_up_normal_on",
selection_box = piston_up_pusher_box,
node_box = piston_up_pusher_box,
})
-- Sticky
local pistonspec_sticky_up = {
offname = "mesecons_pistons:piston_up_sticky_off",
onname = "mesecons_pistons:piston_up_sticky_on",
dir = {x = 0, y = 1, z = 0},
pusher = "mesecons_pistons:piston_up_pusher_sticky",
sticky = true
}
-- offstate
minetest.register_node("mesecons_pistons:piston_up_sticky_off", {
tiles = {
"mesecons_piston_pusher_front_sticky.png",
"mesecons_piston_back.png",
"mesecons_piston_left.png^[transformR270",
"mesecons_piston_right.png^[transformR90",
"mesecons_piston_bottom.png",
"mesecons_piston_top.png^[transformR180",
"mesecons_piston_tb.png"
},
inventory_image = "mesecons_piston_top.png",
wield_image = "mesecons_piston_top.png",
groups = {cracky = 3, not_in_creative_inventory = 1},
paramtype2 = "facedir",
drop = "mesecons_pistons:piston_sticky_off",
mesecons_piston = pistonspec_sticky_up,
sounds = default.node_sound_wood_defaults(),
mesecons = {effector={
action_on = piston_on,
rules = piston_up_rules,
}}
})
-- onstate
minetest.register_node("mesecons_pistons:piston_up_sticky_on", {
drawtype = "nodebox",
tiles = {
"mesecons_piston_on_front.png",
"mesecons_piston_back.png",
"mesecons_piston_left.png^[transformR270",
"mesecons_piston_right.png^[transformR90",
"mesecons_piston_bottom.png",
"mesecons_piston_top.png^[transformR180",
},
inventory_image = "mesecons_piston_top.png",
wield_image = "mesecons_piston_top.png",
groups = {cracky = 3, not_in_creative_inventory = 1},
paramtype = "light",
paramtype2 = "facedir",
drop = "mesecons_pistons:piston_normal_off",
after_dig_node = piston_remove_pusher,
node_box = piston_up_on_box,
selection_box = piston_up_on_box,
mesecons_piston = pistonspec_sticky_up,
sounds = default.node_sound_wood_defaults(),
mesecons = {effector={
action_off = piston_off,
rules = piston_up_rules,
}}
})
-- pusher
minetest.register_node("mesecons_pistons:piston_up_pusher_sticky", {
drawtype = "nodebox",
tiles = {
"mesecons_piston_pusher_front_sticky.png",
"mesecons_piston_pusher_back.png",
"mesecons_piston_pusher_left.png^[transformR270",
"mesecons_piston_pusher_right.png^[transformR90",
"mesecons_piston_pusher_bottom.png",
"mesecons_piston_pusher_top.png^[transformR180",
},
paramtype = "light",
paramtype2 = "facedir",
diggable = false,
corresponding_piston = "mesecons_pistons:piston_up_sticky_on",
selection_box = piston_up_pusher_box,
node_box = piston_up_pusher_box,
})
--
--
-- DOWN
--
--
local piston_down_pusher_box = {
type = "fixed",
fixed = {
{-2/16, -.5 + pt, -2/16, 2/16, .5 + pt, 2/16},
{-.5 , -.5 , -.5 , .5 , -.5 + pt, .5},
}
}
local piston_down_on_box = {
type = "fixed",
fixed = {
{-.5, -.5+pt, -.5 , .5, .5, .5}
}
}
-- Normal
local pistonspec_normal_down = {
offname = "mesecons_pistons:piston_down_normal_off",
onname = "mesecons_pistons:piston_down_normal_on",
dir = {x = 0, y = -1, z = 0},
pusher = "mesecons_pistons:piston_down_pusher_normal",
}
-- offstate
minetest.register_node("mesecons_pistons:piston_down_normal_off", {
tiles = {
"mesecons_piston_back.png",
"mesecons_piston_pusher_front.png",
"mesecons_piston_left.png^[transformR90",
"mesecons_piston_right.png^[transformR270",
"mesecons_piston_bottom.png^[transformR180",
"mesecons_piston_top.png",
},
inventory_image = "mesecons_piston_top.png",
wield_image = "mesecons_piston_top.png",
groups = {cracky = 3, not_in_creative_inventory = 1},
paramtype2 = "facedir",
drop = "mesecons_pistons:piston_normal_off",
mesecons_piston = pistonspec_normal_down,
sounds = default.node_sound_wood_defaults(),
mesecons = {effector={
action_on = piston_on,
rules = piston_down_rules,
}}
})
-- onstate
minetest.register_node("mesecons_pistons:piston_down_normal_on", {
drawtype = "nodebox",
tiles = {
"mesecons_piston_back.png",
"mesecons_piston_on_front.png",
"mesecons_piston_left.png^[transformR90",
"mesecons_piston_right.png^[transformR270",
"mesecons_piston_bottom.png^[transformR180",
"mesecons_piston_top.png",
},
inventory_image = "mesecons_piston_top.png",
wield_image = "mesecons_piston_top.png",
groups = {cracky = 3, not_in_creative_inventory = 1},
paramtype = "light",
paramtype2 = "facedir",
drop = "mesecons_pistons:piston_normal_off",
after_dig_node = piston_remove_pusher,
node_box = piston_down_on_box,
selection_box = piston_down_on_box,
mesecons_piston = pistonspec_normal_down,
sounds = default.node_sound_wood_defaults(),
mesecons = {effector={
action_off = piston_off,
rules = piston_down_rules,
}}
})
-- pusher
minetest.register_node("mesecons_pistons:piston_down_pusher_normal", {
drawtype = "nodebox",
tiles = {
"mesecons_piston_pusher_back.png",
"mesecons_piston_pusher_front.png",
"mesecons_piston_pusher_left.png^[transformR90",
"mesecons_piston_pusher_right.png^[transformR270",
"mesecons_piston_pusher_bottom.png^[transformR180",
"mesecons_piston_pusher_top.png",
},
paramtype = "light",
paramtype2 = "facedir",
diggable = false,
corresponding_piston = "mesecons_pistons:piston_down_normal_on",
selection_box = piston_down_pusher_box,
node_box = piston_down_pusher_box,
})
-- Sticky
local pistonspec_sticky_down = {
onname = "mesecons_pistons:piston_down_sticky_on",
offname = "mesecons_pistons:piston_down_sticky_off",
dir = {x = 0, y = -1, z = 0},
pusher = "mesecons_pistons:piston_down_pusher_sticky",
sticky = true
}
-- offstate
minetest.register_node("mesecons_pistons:piston_down_sticky_off", {
tiles = {
"mesecons_piston_back.png",
"mesecons_piston_pusher_front_sticky.png",
"mesecons_piston_left.png^[transformR90",
"mesecons_piston_right.png^[transformR270",
"mesecons_piston_bottom.png^[transformR180",
"mesecons_piston_top.png",
},
inventory_image = "mesecons_piston_top.png",
wield_image = "mesecons_piston_top.png",
groups = {cracky = 3, not_in_creative_inventory = 1},
paramtype2 = "facedir",
drop = "mesecons_pistons:piston_sticky_off",
mesecons_piston = pistonspec_sticky_down,
sounds = default.node_sound_wood_defaults(),
mesecons = {effector={
action_on = piston_on,
rules = piston_down_rules,
}}
})
-- onstate
minetest.register_node("mesecons_pistons:piston_down_sticky_on", {
drawtype = "nodebox",
tiles = {
"mesecons_piston_back.png",
"mesecons_piston_on_front.png",
"mesecons_piston_left.png^[transformR90",
"mesecons_piston_right.png^[transformR270",
"mesecons_piston_bottom.png^[transformR180",
"mesecons_piston_top.png",
},
inventory_image = "mesecons_piston_top.png",
wield_image = "mesecons_piston_top.png",
groups = {cracky = 3, not_in_creative_inventory = 1},
paramtype = "light",
paramtype2 = "facedir",
drop = "mesecons_pistons:piston_sticky_off",
after_dig_node = piston_remove_pusher,
node_box = piston_down_on_box,
selection_box = piston_down_on_box,
mesecons_piston = pistonspec_sticky_down,
sounds = default.node_sound_wood_defaults(),
mesecons = {effector={
action_off = piston_off,
rules = piston_down_rules,
}}
})
-- pusher
minetest.register_node("mesecons_pistons:piston_down_pusher_sticky", {
drawtype = "nodebox",
tiles = {
"mesecons_piston_pusher_back.png",
"mesecons_piston_pusher_front_sticky.png",
"mesecons_piston_pusher_left.png^[transformR90",
"mesecons_piston_pusher_right.png^[transformR270",
"mesecons_piston_pusher_bottom.png^[transformR180",
"mesecons_piston_pusher_top.png",
},
paramtype = "light",
paramtype2 = "facedir",
diggable = false,
corresponding_piston = "mesecons_pistons:piston_down_sticky_on",
selection_box = piston_down_pusher_box,
node_box = piston_down_pusher_box,
}) })
-- Register pushers as stoppers if they would be seperated from the piston -- Register pushers as stoppers if they would be seperated from the piston
local piston_pusher_get_stopper = function (node, dir, stack, stackid) local function piston_pusher_get_stopper(node, dir, stack, stackid)
if (stack[stackid + 1] if (stack[stackid + 1]
and stack[stackid + 1].node.name == minetest.registered_nodes[node.name].corresponding_piston and stack[stackid + 1].node.name == get_pistonspec(node.name, "pusher").onname
and stack[stackid + 1].node.param2 == node.param2) and stack[stackid + 1].node.param2 == node.param2)
or (stack[stackid - 1] or (stack[stackid - 1]
and stack[stackid - 1].node.name == minetest.registered_nodes[node.name].corresponding_piston and stack[stackid - 1].node.name == get_pistonspec(node.name, "pusher").onname
and stack[stackid - 1].node.param2 == node.param2) then and stack[stackid - 1].node.param2 == node.param2) then
return false return false
end end
return true return true
end end
local piston_pusher_up_down_get_stopper = function (node, dir, stack, stackid) local function piston_pusher_up_down_get_stopper(node, dir, stack, stackid)
if (stack[stackid + 1] if (stack[stackid + 1]
and stack[stackid + 1].node.name == minetest.registered_nodes[node.name].corresponding_piston) and stack[stackid + 1].node.name == get_pistonspec(node.name, "pusher").onname)
or (stack[stackid - 1] or (stack[stackid - 1]
and stack[stackid - 1].node.name == minetest.registered_nodes[node.name].corresponding_piston) then and stack[stackid - 1].node.name == get_pistonspec(node.name, "pusher").onname) then
return false return false
end end
return true return true
@ -704,31 +434,24 @@ end
mesecon.register_mvps_stopper("mesecons_pistons:piston_pusher_normal", piston_pusher_get_stopper) mesecon.register_mvps_stopper("mesecons_pistons:piston_pusher_normal", piston_pusher_get_stopper)
mesecon.register_mvps_stopper("mesecons_pistons:piston_pusher_sticky", piston_pusher_get_stopper) mesecon.register_mvps_stopper("mesecons_pistons:piston_pusher_sticky", piston_pusher_get_stopper)
mesecon.register_mvps_stopper("mesecons_pistons:piston_up_pusher_normal", piston_pusher_up_down_get_stopper)
mesecon.register_mvps_stopper("mesecons_pistons:piston_up_pusher_sticky", piston_pusher_up_down_get_stopper)
mesecon.register_mvps_stopper("mesecons_pistons:piston_down_pusher_normal", piston_pusher_up_down_get_stopper)
mesecon.register_mvps_stopper("mesecons_pistons:piston_down_pusher_sticky", piston_pusher_up_down_get_stopper)
-- Register pistons as stoppers if they would be seperated from the stopper -- Register pistons as stoppers if they would be seperated from the stopper
local piston_up_down_get_stopper = function (node, dir, stack, stackid) local piston_up_down_get_stopper = function (node, dir, stack, stackid)
if (stack[stackid + 1] if (stack[stackid + 1]
and stack[stackid + 1].node.name == minetest.registered_nodes[node.name].mesecons_piston.pusher) and stack[stackid + 1].node.name == get_pistonspec(node.name, "onname").pusher)
or (stack[stackid - 1] or (stack[stackid - 1]
and stack[stackid - 1].node.name == minetest.registered_nodes[node.name].mesecons_piston.pusher) then and stack[stackid - 1].node.name == get_pistonspec(node.name, "onname").pusher) then
return false return false
end end
return true return true
end end
local piston_get_stopper = function (node, dir, stack, stackid) local function piston_get_stopper(node, dir, stack, stackid)
pistonspec = minetest.registered_nodes[node.name].mesecons_piston local pistonspec = get_pistonspec(node.name, "onname")
dir = piston_get_direction(pistonspec.dir, node) local dir = vector.multiply(minetest.facedir_to_dir(node.param2), -1)
local pusherpos = vector.add(stack[stackid].pos, dir) local pusherpos = vector.add(stack[stackid].pos, dir)
local pushernode = minetest.get_node(pusherpos) local pushernode = minetest.get_node(pusherpos)
if pistonspec.pusher == pushernode.name then
if minetest.registered_nodes[node.name].mesecons_piston.pusher == pushernode.name then
for _, s in ipairs(stack) do for _, s in ipairs(stack) do
if vector.equals(s.pos, pusherpos) -- pusher is also to be pushed if vector.equals(s.pos, pusherpos) -- pusher is also to be pushed
and s.node.param2 == node.param2 then and s.node.param2 == node.param2 then
@ -742,18 +465,13 @@ end
mesecon.register_mvps_stopper("mesecons_pistons:piston_normal_on", piston_get_stopper) mesecon.register_mvps_stopper("mesecons_pistons:piston_normal_on", piston_get_stopper)
mesecon.register_mvps_stopper("mesecons_pistons:piston_sticky_on", piston_get_stopper) mesecon.register_mvps_stopper("mesecons_pistons:piston_sticky_on", piston_get_stopper)
mesecon.register_mvps_stopper("mesecons_pistons:piston_up_normal_on", piston_up_down_get_stopper)
mesecon.register_mvps_stopper("mesecons_pistons:piston_up_sticky_on", piston_up_down_get_stopper)
mesecon.register_mvps_stopper("mesecons_pistons:piston_down_normal_on", piston_up_down_get_stopper)
mesecon.register_mvps_stopper("mesecons_pistons:piston_down_sticky_on", piston_up_down_get_stopper)
--craft recipes --craft recipes
minetest.register_craft({ minetest.register_craft({
output = "mesecons_pistons:piston_normal_off 2", output = "mesecons_pistons:piston_normal_off 2",
recipe = { recipe = {
{"group:wood", "group:wood", "group:wood"}, {"group:wood", "group:wood", "group:wood"},
{"default:cobble", "default:steel_ingot", "default:cobble"}, {"default:cobble", "default:steel_ingot", "default:cobble"},
{"default:cobble", "group:mesecon_conductor_craftable", "default:cobble"}, {"default:cobble", "group:mesecon_conductor_craftable", "default:cobble"},
} }
}) })
@ -765,3 +483,7 @@ minetest.register_craft({
{"mesecons_pistons:piston_normal_off"}, {"mesecons_pistons:piston_normal_off"},
} }
}) })
-- load legacy code
dofile(minetest.get_modpath("mesecons_pistons")..DIR_DELIM.."legacy.lua")

View File

@ -0,0 +1,48 @@
local ground_dir = {
[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},
}
minetest.register_lbm({
label = "Upgrade legacy pistons pointing up",
name = "mesecons_pistons:replace_legacy_piston_up",
nodenames = {
"mesecons_pistons:piston_up_normal_off",
"mesecons_pistons:piston_up_normal_on",
"mesecons_pistons:piston_up_pusher_normal",
"mesecons_pistons:piston_up_sticky_off",
"mesecons_pistons:piston_up_sticky_on",
"mesecons_pistons:piston_up_pusher_sticky",
},
run_at_every_load = false,
action = function(pos, node)
local dir = ground_dir[math.floor(node.param2/4)]
node.param2 = minetest.dir_to_facedir(dir, true)
node.name = node.name:sub(1, 24)..node.name:sub(28)
minetest.swap_node(pos, node)
end,
})
minetest.register_lbm({
label = "Upgrade legacy pistons pointing down",
name = "mesecons_pistons:replace_legacy_piston_down",
nodenames = {
"mesecons_pistons:piston_down_normal_off",
"mesecons_pistons:piston_down_normal_on",
"mesecons_pistons:piston_down_pusher_normal",
"mesecons_pistons:piston_down_sticky_off",
"mesecons_pistons:piston_down_sticky_on",
"mesecons_pistons:piston_down_pusher_sticky",
},
run_at_every_load = false,
action = function(pos, node)
local dir = vector.multiply(ground_dir[math.floor(node.param2/4)], -1)
node.param2 = minetest.dir_to_facedir(dir, true)
node.name = node.name:sub(1, 24)..node.name:sub(30)
minetest.swap_node(pos, node)
end,
})

View File

@ -7,6 +7,7 @@ minetest.register_node("mesecons_powerplant:power_plant", {
tiles = {"jeija_power_plant.png"}, tiles = {"jeija_power_plant.png"},
inventory_image = "jeija_power_plant.png", inventory_image = "jeija_power_plant.png",
paramtype = "light", paramtype = "light",
is_ground_content = false,
walkable = false, walkable = false,
groups = {dig_immediate=3, mesecon = 2}, groups = {dig_immediate=3, mesecon = 2},
light_source = default.LIGHT_MAX-9, light_source = default.LIGHT_MAX-9,
@ -18,7 +19,8 @@ minetest.register_node("mesecons_powerplant:power_plant", {
sounds = default.node_sound_leaves_defaults(), sounds = default.node_sound_leaves_defaults(),
mesecons = {receptor = { mesecons = {receptor = {
state = mesecon.state.on state = mesecon.state.on
}} }},
on_blast = mesecon.on_blastnode,
}) })
minetest.register_craft({ minetest.register_craft({

View File

@ -8,7 +8,7 @@ local pp_box_on = {
fixed = { -7/16, -8/16, -7/16, 7/16, -7.5/16, 7/16 }, fixed = { -7/16, -8/16, -7/16, 7/16, -7.5/16, 7/16 },
} }
pp_on_timer = function (pos, elapsed) local function pp_on_timer(pos, elapsed)
local node = minetest.get_node(pos) local node = minetest.get_node(pos)
local basename = minetest.registered_nodes[node.name].pressureplate_basename local basename = minetest.registered_nodes[node.name].pressureplate_basename
@ -42,30 +42,42 @@ end
-- tiles_on: textures of the pressure plate when active -- tiles_on: textures of the pressure plate when active
-- image: inventory and wield image of the pressure plate -- image: inventory and wield image of the pressure plate
-- recipe: crafting recipe of the pressure plate -- recipe: crafting recipe of the pressure plate
-- groups: groups
-- sounds: sound table
function mesecon.register_pressure_plate(basename, description, textures_off, textures_on, image_w, image_i, recipe, groups, sounds)
local groups_off, groups_on
if not groups then
groups = {}
end
local groups_off = table.copy(groups)
local groups_on = table.copy(groups)
groups_on.not_in_creative_inventory = 1
function mesecon.register_pressure_plate(basename, description, textures_off, textures_on, image_w, image_i, recipe)
mesecon.register_node(basename, { mesecon.register_node(basename, {
drawtype = "nodebox", drawtype = "nodebox",
inventory_image = image_i, inventory_image = image_i,
wield_image = image_w, wield_image = image_w,
paramtype = "light", paramtype = "light",
description = description, is_ground_content = false,
description = description,
pressureplate_basename = basename, pressureplate_basename = basename,
on_timer = pp_on_timer, on_timer = pp_on_timer,
on_construct = function(pos) on_construct = function(pos)
minetest.get_node_timer(pos):start(mesecon.setting("pplate_interval", 0.1)) minetest.get_node_timer(pos):start(mesecon.setting("pplate_interval", 0.1))
end, end,
sounds = sounds,
},{ },{
mesecons = {receptor = { state = mesecon.state.off, rules = mesecon.rules.pplate }}, mesecons = {receptor = { state = mesecon.state.off, rules = mesecon.rules.pplate }},
node_box = pp_box_off, node_box = pp_box_off,
selection_box = pp_box_off, selection_box = pp_box_off,
groups = {snappy = 2, oddly_breakable_by_hand = 3}, groups = groups_off,
tiles = textures_off tiles = textures_off
},{ },{
mesecons = {receptor = { state = mesecon.state.on, rules = mesecon.rules.pplate }}, mesecons = {receptor = { state = mesecon.state.on, rules = mesecon.rules.pplate }},
node_box = pp_box_on, node_box = pp_box_on,
selection_box = pp_box_on, selection_box = pp_box_on,
groups = {snappy = 2, oddly_breakable_by_hand = 3, not_in_creative_inventory = 1}, groups = groups_on,
tiles = textures_on tiles = textures_on
}) })
@ -82,7 +94,9 @@ mesecon.register_pressure_plate(
{"jeija_pressure_plate_wood_on.png","jeija_pressure_plate_wood_on.png","jeija_pressure_plate_wood_on_edges.png"}, {"jeija_pressure_plate_wood_on.png","jeija_pressure_plate_wood_on.png","jeija_pressure_plate_wood_on_edges.png"},
"jeija_pressure_plate_wood_wield.png", "jeija_pressure_plate_wood_wield.png",
"jeija_pressure_plate_wood_inv.png", "jeija_pressure_plate_wood_inv.png",
{{"group:wood", "group:wood"}}) {{"group:wood", "group:wood"}},
{ choppy = 3, oddly_breakable_by_hand = 3 },
default.node_sound_wood_defaults())
mesecon.register_pressure_plate( mesecon.register_pressure_plate(
"mesecons_pressureplates:pressure_plate_stone", "mesecons_pressureplates:pressure_plate_stone",
@ -91,4 +105,6 @@ mesecon.register_pressure_plate(
{"jeija_pressure_plate_stone_on.png","jeija_pressure_plate_stone_on.png","jeija_pressure_plate_stone_on_edges.png"}, {"jeija_pressure_plate_stone_on.png","jeija_pressure_plate_stone_on.png","jeija_pressure_plate_stone_on_edges.png"},
"jeija_pressure_plate_stone_wield.png", "jeija_pressure_plate_stone_wield.png",
"jeija_pressure_plate_stone_inv.png", "jeija_pressure_plate_stone_inv.png",
{{"default:cobble", "default:cobble"}}) {{"default:cobble", "default:cobble"}},
{ cracky = 3, oddly_breakable_by_hand = 3 },
default.node_sound_stone_defaults())

Some files were not shown because too many files have changed in this diff Show More