Compare commits

..

110 Commits

Author SHA1 Message Date
Carter Kolwey
199fb62108 Properly handle missing screwdriver mod 2017-03-04 09:40:07 +01:00
Carter Kolwey
c7136b72cb Fix crash when pushing a turned-on piston 2017-03-04 09:39:40 +01:00
Carter Kolwey
774aac6e90 Piston and wire cleanups and minor rotation fixes 2017-03-04 09:39:40 +01:00
Carter Kolwey
410f43bbc1 Convert pistons to use 6D facedir (also prevent rotating when on, fixes ) 2017-03-04 09:38:35 +01:00
Carter Kolwey
5e8c3584d1 Prevent rotating wires (fixes ) 2017-03-04 09:37:32 +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
Wuzzy
03ab151c87 Fix active ghoststones being droppable with sand
Fixes 
2017-02-15 23:00:02 +01:00
Vanessa Ezekowitz
dd2b36c41c fix wrong UV mapping on "on" turbine blades 2017-02-13 14:24:29 -05:00
Vanessa Ezekowitz
0cb286b425 Merge pull request from Jeija/animated_turbine
Make "on" water turbine animated!
2017-02-12 19:56:29 -05:00
Vanessa Ezekowitz
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
Vanessa Ezekowitz
fa3bd19270 fix Z-fighting on water turbine 2017-02-12 10:56:54 -05:00
sfan5
2bc3c5d97c fpga: Make formspec usage less prone to breakage 2017-01-28 11:54:27 +01:00
sfan5
07d074075c FPGAs () 2017-01-28 11:33:13 +01:00
sfan5
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
sfan5
7667e7d8c5 Fix Lua error with microcontrollers
caused by an oversight in ececf525b6f717956a38fa314d2472f72451159d
2017-01-19 16:31:36 +01:00
sfan5
ececf525b6 Fix remaining namespace pollutions (closes ) 2017-01-15 23:12:13 +01:00
Jeija
54daee236e Luacontroller: Revert function stripping from digiline messages 2017-01-15 20:11:12 +01:00
sfan5
c2e3d7c4e5 Fix most of the namespace pollutions reported in 2017-01-15 11:53:49 +01:00
DS-Minetest
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
Carter Kolwey
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
Carter Kolwey
79edbed8d7 Allow water turbines to work with river water (fixes )
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
Jeija
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
Jeija
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
Yutao Yuan
67cd17aa79 Fix crash with movestones 2016-12-04 19:37:31 +08:00
Christopher Head
203aaf3c90 Remove an unused function. 2016-11-17 14:55:02 +01:00
Jeija
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
Jeija
433778c2ec Add Hawk777 to contributor list, update developer documentation URL 2016-09-04 09:32:41 +02:00
Jeija
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
Jeija
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
Jeija
6dacdaee1f Small cleanups in internal.lua, move forceloading reversal to legacy 2016-08-30 19:37:43 +02:00
Jeija
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
Jeija
89153f6909 Further simplification of turnon/turnoff 2016-08-30 18:24:08 +02:00
Christopher Head
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
Christopher Head
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
Christopher Head
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
Christopher Head
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
Carter Kolwey
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
Carter Kolwey
4816dee396 Move shared textures into base mod (fixes a few LuaC issues) 2016-08-23 11:02:12 +02:00
Florian Euchner
a3042b44fc Merge pull request from Hawk777/luacontroller-comment
Remove an obsolete comment.
2016-08-16 12:14:33 +02:00
Christopher Head
53eaf2af11 Remove an obsolete comment. 2016-08-16 00:16:24 -07:00
Jeija
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 , thanks to @darkfeels
2016-07-31 22:26:33 +02:00
Jeija
7c7595fd7d Fix : Fix bugs in block forceloading in turnon / turnoff
Thanks to @Hawk777 for reporting this problem
2016-07-25 10:01:43 +02:00
Carter Kolwey
acd41b5773 Don't bother checking if a node can overheat before cooling it 2016-07-09 11:17:08 +02:00
number Zero
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
Carter Kolwey
40487a65f4 Add protection support to Luacontrollers,
protection is ignored with protection_bypass_priv
2016-05-17 07:58:50 +02:00
Florian Euchner
75308f73e4 Merge pull request from Emon-Omen/patch-1
Fixed missing capital letter in "ghoststone"
2016-05-17 07:53:35 +02:00
Emon
478680292c fixed missing capital letter @ line 29 2016-05-16 22:24:56 +02:00
Jeija
85bc62a65d Add COPYING.txt file to clarify coprights and licenses 2016-05-16 08:04:57 +02:00
Jeija
ed3964da80 Remove microcontroller documentation files from the source tree
The files are still available for download in a GitHub release
2016-05-15 19:04:18 +02:00
electrodude
6cae381c27 Luacontroller: Fix remove_functions stack overflow bug 2016-04-26 20:40:12 +02:00
Jeija
4249ed4986 Mese as conductor: Fix light source, make code more flexible
Closes 
2016-04-26 19:44:05 +02:00
Florian Euchner
c4f0c5c169 Merge pull request from cheapie/master
Escape command block commands for formspec
2016-04-21 19:26:28 +02:00
Carter Kolwey
2dea21f9ef Escape command block commands for formspec 2016-04-21 02:15:54 -05:00
Pedro Gimeno
b487783c23 Disable JIT optimization for user code and allow string.find in plain mode
Disabling LuaJIT for user code enables normal working of debug.sethook() even for loops. The drawback is that that code will run more slowly.

The fourth parameter of string.find indicates whether the second parameter should be interpreted literally (true) or as a pattern (false). Allowing patterns enables DoS attacks, but it's possible to
allow literal matching with little effort, by disallowing the function only if the fourth parameter (plain mode) is not `true`.
2016-04-02 17:31:40 +02:00
Jeija
72e513ecbd Luacontroller: Put clearing debug hook before throwing error back in 2016-03-14 12:51:57 +01:00
Jeija
1e77b193dd Luacontroller: Add safe version of string.rep and remove string.gsub,
fixes 
2016-03-13 22:01:46 +01:00
Jeija
08b14e3af0 Luacontroller: Fix function usage in LuaJIT, make 'do' no longer
prohibited, remove pcall and xpcall, fix global lookup of "jit"
variable, correct error locations

Thanks to @ShadowNinja and @gamemanj for fixing this in 
2016-03-13 21:16:16 +01:00
Jeija
e5dba66c21 Revert "Toggle trapdoors on signal, workaround for "
Please use the screwdriver if you want to rotate trapdoors.
This reverts commit 417a136c5e6842a6c54a98690746b0aa41ad69e5.
2016-02-28 07:16:45 +01:00
Jeija
417a136c5e Toggle trapdoors on signal, workaround for 2016-02-27 20:40:16 +01:00
Jeija
2dc8101fa1 Merge branch 'ssieb-master' 2016-02-23 10:20:09 +01:00
Samuel Sieb
4b9039266e Fix crash due to force loading changes. 2016-02-22 15:47:18 -08:00
Jeija
c7428d8135 Remove unused VERSION file
and remove debug output
2016-02-19 12:20:52 +01:00
Jeija
cfd4f7c287 Force-load areas with mesecon usage
This is a major speedup for large mesecon machines / structures.
Force-loaded areas are stored in a file to be persistent over server
reboots. By default, areas are unloaded after 10 minutes (600s) without
usage, this can be customized with the mesecon.forceload_timeout
setting. Please turn max_forceloaded_blocks up for better performance.
2016-02-19 12:11:38 +01:00
Jeija
f099b43e11 Update documentation: Fix mesecons.net links 2016-02-16 19:55:46 +01:00
Jeija
7b84105512 Consistently use UNIX line endings (LF instead of CR LF) 2016-02-15 23:05:21 +01:00
Jeija
80f72b2621 Fix vertical wires not updating power when adding to / removing from a vertical line
Call mesecon.on_dignode / mesecon.on_placenode to take care of that.
2016-02-15 22:52:56 +01:00
Jeija
fe9c6871de Fix pistons not connecting to wire and not activating when placing
up/down pistons from certain directions
2016-02-15 16:36:27 +01:00
Jeija
7865d42834 Always use minetest.set_node instead of minetest.add_node for consistency 2016-02-14 21:00:37 +01:00
Jeija
809192f353 Use vector helper functions instead of old builtin cmpPos and addPosRule functions 2016-02-14 20:55:50 +01:00
Jeija
6b54f025c1 Merge branch 'playerdetector_update' of https://github.com/HybridDog/minetest-mod-mesecons into HybridDog-playerdetector_update 2016-02-14 13:41:48 +01:00
Jeija
c98805a5b5 Merge branch 'fix_pistons' of https://github.com/HybridDog/minetest-mod-mesecons into HybridDog-fix_pistons 2016-02-14 12:55:18 +01:00
Auke Kok
fb4c440265 Doors: Use new mesh door API if available
I've implemented a new door API in minetest_game that
performs all the needed things to assure doors are
properly openend and closed, without mods needing to
know the inner details of what needs to be done.

Mesecons can just fetch a reference to the door object
and call the appropriate open or close method, which
simplifies this code a lot.

For compatibility, this code retains the old code path
and tests whether the new API is available, so this
code remains functional if the new API is not available.

Since the metal trapdoor was only recently added, I added
it to the new API codepath only, it's unlikely to be
present on older versions of minetest_game anyway.

As a benefit from the new door API, there is now
absolutely no more accidental switching closed trapdoors
to open on power off, which could happen with the
old method - since that was just a simple toggle.
2016-02-14 11:30:52 +01:00
HybridDog
cf45e24c57 this way it works better because unknown nodes may not stay unknown 2016-02-09 16:58:49 +01:00
HybridDog
3f00c1d1cb fix pistons not working in every buildable_to node 2016-02-09 11:32:09 +01:00
HybridDog
c1d0481f8f playerdetector: short code and don't get scanname for every object 2016-01-03 14:56:32 +01:00
Jeija
f56c4ce35c Merge branch 'HybridDog-noteblock_update' 2016-01-02 23:01:08 +01:00
HybridDog
0ec503f32c Noteblock: Code cleanup 2016-01-02 22:58:08 +01:00
Carter Kolwey
35b647ed4a Add os.datetable(), a (very) limited wrapper for os.date(). Fixes . 2016-01-02 01:13:38 -06:00
Jeija
eab09b9d73 Merge branch 'sofar-sound' 2015-12-29 22:20:42 +01:00
Auke Kok
2682d09291 Fix sound volume level of noteblock.
Playing stereo sounds positionally in OpenAL causes it to play
the sounds unattenuated - same volume for all distances. This
shouldn't happen, and makes noteblocks unneccesarily loud from
very far away.

Convert all noteblock samples to mono, 22kHz 64kbit.
2015-12-26 22:41:16 -08:00
Jeija
a6b28d1f11 Gates: Update nor gate craft recipe, fixes 2015-12-15 22:25:39 +01:00
Jeija
0ec771bf7d Major change: Documentation is now included with mesecons, the website just extracts the documentation in a more readable format
This makes development of new features easier, as documentation can automatically be updated on the website without modifying the website's code!
Every mod that has nodes in the mesecons modpack has a "doc" folder that contains subfolders with recipe, description and preview of the block. The website will discover which documentation is available
by reading the documentation.json file.
2015-11-20 20:14:50 +01:00
Jeija
75bd081a67 Gates: Add OR and NOR gate 2015-11-20 20:13:59 +01:00
Jeija
b89fe52469 Luacontroller: Add configurable size limit for mem table, 100kBytes by default, fixes
If size limit is exceeded, the luacontroller overheats. Overheating will cause the memory
to be erased.
2015-10-18 11:28:35 +02:00
Jeija
97f7b5745f Remove trailing whitespace 2015-10-04 13:30:34 +02:00
Jeija
24958e253b Revert "Do not send action_off signal when newly placing nodes"
This caused , reverting that commit fixes .

This reverts commit 30468b09cf35b3122e05f1e2867923fdcad5a5d2.
2015-10-04 12:30:04 +02:00
Jeija
0e7f68ea92 Doors: Use new sound name (fixes ) 2015-10-04 12:21:35 +02:00
Florian Euchner
6ef3b965df Merge pull request from beyondlimits/master
Use right mouse button instead of left to press button and change state of switch and lever.
2015-10-04 12:09:15 +02:00
Marcin
6e326a6a03 Use right mouse button instead of left to press button and change state of switch and lever. 2015-10-01 19:13:12 +02:00
Vanessa Ezekowitz
d95ccf86f8 update "sticky block" to use 0.4.13-style footprints 2015-08-25 20:23:23 -04:00
Jeija
d0354d0dab Fix 2015-07-27 11:51:02 +02:00
Vanessa Ezekowitz
fec43a3243 reworked hydroturbine model for the same reasons
also shrunk the base part down by a very tiny amount to help avoid z-fighting with neighboring
water (scaled to 0.9995 percent)
2015-05-20 03:40:59 -04:00
Vanessa Ezekowitz
5612f84243 revamp wall lever models
corrected misaligned verticies, removed doubles, made better UV maps that use multiple
materials (allows to use multiple small textures)
2015-05-20 03:00:06 -04:00
Florian Euchner
3066346d75 Merge pull request from technomancy/default-light-max
Don't refer to LIGHT_MAX global; use default.
2015-05-11 07:08:24 +02:00
Phil Hagelberg
52ea2c3c66 Don't refer to LIGHT_MAX global; use default.
The LIGHT_MAX global is created in the legacy.lua file in the default
mod; it states that it's there for backwards compatibility, but it would
be better to reference the proper value inside the default table.
2015-05-11 11:28:56 +07:00
Jeija
b6ae419b00 Return if invalid parameters are given to node_detector_scan (e.g. unloaded area), should fix 2015-03-26 07:29:34 +01:00
Jeija
a6d0a523ba Add support for sticky blocks for pistons and a a sample sticky block 2015-02-28 13:42:39 +01:00
Jeija
aa5538a734 Fix pressure plates calling receptor_on on a regular basis 2015-02-25 21:01:00 +01:00
Jeija
eb416475cc Re-add mesecon.register_mvps_unmov(objectname) since other mods (pipeworks) are using it 2015-02-19 14:27:20 +01:00
Jeija
1ee3b2107d Fix movestones sometimes not starting to move again when they are at the
end of the wire
2015-02-17 20:02:24 +01:00
Jeija
1df6e5a03b Rewrite movestones, make them nodes instead of entities 2015-02-14 13:35:50 +01:00
Florian Euchner
b7076e635c Merge pull request from MT-Modder/stoppers-2
Register only locked nodes as stoppers
2015-02-14 09:22:56 +01:00
MT-Modder
6d9f44455c Register only locked nodes as stoppers
This was suggested here:
https://github.com/Jeija/minetest-mod-mesecons/pull/216
2015-02-13 23:58:36 -05:00
Jeija
8bf5b7d0e4 Fix , do not try to override unregistered doors 2015-02-14 00:02:19 +01:00
Florian Euchner
14281a1bd4 Merge pull request from MT-Modder/remove-from-group
Remove insulated t-junction and crossover from craftable group
2015-02-13 23:51:42 +01:00
MT-Modder
1d93a51f6e Remove insulated t-junction and crossover from craftable group 2015-02-13 17:02:09 -05:00
Jeija
639fc8988e Fix onstate sticky piston drop: Must be sticky instead of normal piston
Thanks to HybridDog for spotting that
2015-02-05 20:26:51 +01:00
Florian Euchner
a9ec0a10c0 Merge pull request from MT-Modder/mvps-additions
Register chests and bookshelves as stoppers
2015-02-05 16:23:58 +01:00
Vanessa Ezekowitz
775d250112 Add meshes for water turbine and and wall lever instead of nodeboxes
Adjust textures and inventory images to it
2015-02-05 15:40:08 +01:00
MT-Modder
3c06da7908 Register chests and bookshelves as stoppers 2015-02-05 00:57:33 -05:00
275 changed files with 5398 additions and 2644 deletions
COPYING.txtREADME.mddocumentation.json
mesecons
mesecons_blinkyplant/doc/blinkyplant
mesecons_button
mesecons_commandblock
mesecons_delayer
mesecons_detector
mesecons_doors
mesecons_extrawires
mesecons_fpga
mesecons_gates

30
COPYING.txt Normal 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/

@ -22,7 +22,7 @@ OK, I want in.
--------------
Go get it!
[DOWNLOADS PAGE](http://mesecons.net/downloads.php)
[DOWNLOAD IT NOW](https://github.com/Jeija/minetest-mod-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:
@ -39,7 +39,7 @@ How do I use this thing?
------------------------
How about a [quick overview video](https://www.youtube.com/watch?v=6kmeQj6iW5k)?
Or maybe a [comprehensive reference](http://mesecons.net/items.php) is your style?
Or maybe a [comprehensive reference](http://mesecons.net/items.html) is your style?
An overview for the very newest of new beginners? How does [this one](http://uberi.mesecons.net/projects/MeseconsBasics/index.html) look?
@ -53,6 +53,7 @@ These awesome people made Mesecons possible!
| Contributor | Contribution |
| --------------- | -------------------------------- |
| Hawk777 | Code for VoxelManip caching |
| Jat15 | Various tweaks. |
| Jeija | **Main developer! Everything.** |
| Jordach | Noteblock sounds. |

64
documentation.json Normal file

@ -0,0 +1,64 @@
{
"Conductors" : {
"Mesecon" : "mesecons_wires/doc/mesecon",
"Insulated Wire" : "mesecons_insulated/doc/insulated",
"T-Junction" : "mesecons_extrawires/doc/tjunction",
"Crossing" : "mesecons_extrawires/doc/crossing",
"Corner" : "mesecons_extrawires/doc/corner",
"Vertical Wire" : "mesecons_extrawires/doc/vertical",
"Mese" : "mesecons_extrawires/doc/mese"
},
"Receptors" : {
"Power Plant" : "mesecons_powerplant/doc/powerplant",
"Blinky Plant" : "mesecons_blinkyplant/doc/blinkyplant",
"Switch" : "mesecons_switch/doc/switch",
"Object Detector" : "mesecons_detector/doc/objectdetector",
"Node Detector" : "mesecons_detector/doc/nodedetector",
"Wall Lever" : "mesecons_walllever/doc/walllever",
"Pressure Plate" : "mesecons_pressureplates/doc/pressureplate_wood",
"Pressure Plate" : "mesecons_pressureplates/doc/pressureplate_stone",
"Water Turbine" : "mesecons_hydroturbine/doc/waterturbine",
"Solar Panel" : "mesecons_solarpanel/doc/solarpanel",
"Wall Button" : "mesecons_button/doc/button"
},
"Effectors" : {
"Noteblock" : "mesecons_noteblock/doc/noteblock",
"Lamp" : "mesecons_lamp/doc/lamp",
"Piston" : "mesecons_pistons/doc/piston",
"Sticky Piston" : "mesecons_pistons/doc/piston_sticky",
"Movestone" : "mesecons_movestones/doc/movestone",
"Sticky Movestone" : "mesecons_movestones/doc/movestone_sticky",
"Removestone" : "mesecons_random/doc/removestone",
"Ghoststone" : "mesecons_random/doc/ghoststone",
"Command Block" : "mesecons_commandblock/doc/commandblock",
"Lightstones" : {
"Dark Grey" : "mesecons_lightstone/doc/lightstone_darkgrey",
"Light Grey" : "mesecons_lightstone/doc/lightstone_lightgrey",
"Green" : "mesecons_lightstone/doc/lightstone_green",
"Red" : "mesecons_lightstone/doc/lightstone_red",
"Blue" : "mesecons_lightstone/doc/lightstone_blue",
"Yellow" : "mesecons_lightstone/doc/lightstone_yellow"
}
},
"Logic" : {
"Luacontroller" : "mesecons_luacontroller/doc/luacontroller",
"FPGA" : "mesecons_fpga/doc/fpga",
"FPGA Programmer" : "mesecons_fpga/doc/programmer",
"Torch" : "mesecons_torch/doc/torch",
"Delayer" : "mesecons_delayer/doc/delayer",
"Gates" : {
"Diode" : "mesecons_gates/doc/diode",
"NOT Gate" : "mesecons_gates/doc/not",
"AND Gate" : "mesecons_gates/doc/and",
"NAND Gate" : "mesecons_gates/doc/nand",
"OR Gate" : "mesecons_gates/doc/or",
"NOR Gate" : "mesecons_gates/doc/nor",
"XOR Gate" : "mesecons_gates/doc/xor"
}
},
"Crafts" : {
"Silicon" : "mesecons_materials/doc/silicon",
"Glue" : "mesecons_materials/doc/glue",
"Fiber" : "mesecons_materials/doc/fiber"
}
}

@ -1 +0,0 @@
0.41 DEV

@ -23,7 +23,7 @@ function mesecon.queue:add_action(pos, func, params, time, overwritecheck, prior
-- Otherwise, add the action to the queue
if overwritecheck then -- check if old action has to be overwritten / removed:
for i, ac in ipairs(mesecon.queue.actions) do
if(mesecon.cmpPos(pos, ac.pos)
if(vector.equals(pos, ac.pos)
and mesecon.cmpAny(overwritecheck, ac.owcheck)) then
toremove = i
break
@ -87,32 +87,19 @@ minetest.register_globalstep(function (dtime)
end)
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
-- Store and read the ActionQueue to / from a file
-- so that upcoming actions are remembered when the game
-- is restarted
local wpath = minetest.get_worldpath()
local function file2table(filename)
local f = io.open(filename, "r")
if f==nil then return {} end
local t = f:read("*all")
f:close()
if t=="" or t==nil then return {} end
return minetest.deserialize(t)
end
local function table2file(filename, table)
local f = io.open(filename, "w")
f:write(minetest.serialize(table))
f:close()
end
mesecon.queue.actions = file2table(wpath.."/mesecon_actionqueue")
mesecon.queue.actions = mesecon.file2table("mesecon_actionqueue")
minetest.register_on_shutdown(function()
mesecon.queue.actions = table2file(wpath.."/mesecon_actionqueue", mesecon.queue.actions)
mesecon.table2file("mesecon_actionqueue", mesecon.queue.actions)
end)

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

@ -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
--
--
-- For developer documentation see the Developers' section on mesecons.TK
-- For basic development resources, see http://mesecons.net/developers.html
--
--
--
@ -30,7 +30,7 @@
-- action_change = function
-- rules = rules/get_rules
-- },
-- conductor =
-- conductor =
-- {
-- state = mesecon.state.on/off
-- offstate = opposite state (for state = on only)
@ -70,26 +70,20 @@ dofile(minetest.get_modpath("mesecons").."/internal.lua");
-- these are the only functions you need to remember
mesecon.queue:add_function("receptor_on", function (pos, rules)
mesecon.vm_begin()
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 = mesecon.addPosRule(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
local np = mesecon.addPosRule(pos, rule)
local np = vector.add(pos, rule)
local rulenames = mesecon.rules_link_rule_all(pos, rule)
for _, rulename in ipairs(rulenames) do
mesecon.turnon(np, rulename)
end
end
mesecon.vm_commit()
end)
function mesecon.receptor_on(pos, rules)
@ -99,23 +93,21 @@ end
mesecon.queue:add_function("receptor_off", function (pos, rules)
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 = mesecon.addPosRule(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
local np = mesecon.addPosRule(pos, rule)
local np = vector.add(pos, rule)
local rulenames = mesecon.rules_link_rule_all(pos, rule)
for _, rulename in ipairs(rulenames) do
if not mesecon.connected_to_receptor(np, mesecon.invertRule(rule)) then
mesecon.turnoff(np, rulename)
mesecon.vm_begin()
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
mesecon.changesignal(np, minetest.get_node(np), rulename, mesecon.state.off, 2)
mesecon.vm_abort()
end
end
end
@ -132,8 +124,5 @@ print("[OK] Mesecons")
-- To be removed in future releases
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
dofile(minetest.get_modpath("mesecons").."/services.lua");

@ -37,11 +37,6 @@
-- HIGH-LEVEL Internals
-- 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.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
-- RULES ROTATION helpers
@ -76,7 +71,9 @@ function mesecon.get_conductor(nodename)
end
end
function mesecon.get_any_outputrules (node)
function mesecon.get_any_outputrules(node)
if not node then return nil end
if mesecon.is_conductor(node.name) then
return mesecon.conductor_get_rules(node)
elseif mesecon.is_receptor(node.name) then
@ -84,7 +81,9 @@ function mesecon.get_any_outputrules (node)
end
end
function mesecon.get_any_inputrules (node)
function mesecon.get_any_inputrules(node)
if not node then return nil end
if mesecon.is_conductor(node.name) then
return mesecon.conductor_get_rules(node)
elseif mesecon.is_effector(node.name) then
@ -92,7 +91,7 @@ function mesecon.get_any_inputrules (node)
end
end
function mesecon.get_any_rules (node)
function mesecon.get_any_rules(node)
return mesecon.mergetable(mesecon.get_any_inputrules(node) or {},
mesecon.get_any_outputrules(node) or {})
end
@ -182,7 +181,9 @@ end
-- Activation:
mesecon.queue:add_function("activate", function (pos, rulename)
local node = minetest.get_node(pos)
local node = mesecon.get_node_force(pos)
if not node then return end
local effector = mesecon.get_effector(node.name)
if effector and effector.action_on then
@ -203,7 +204,9 @@ end
-- Deactivation
mesecon.queue:add_function("deactivate", function (pos, rulename)
local node = minetest.get_node(pos)
local node = mesecon.get_node_force(pos)
if not node then return end
local effector = mesecon.get_effector(node.name)
if effector and effector.action_off then
@ -224,7 +227,9 @@ end
-- Change
mesecon.queue:add_function("change", function (pos, rulename, changetype)
local node = minetest.get_node(pos)
local node = mesecon.get_node_force(pos)
if not node then return end
local effector = mesecon.get_effector(node.name)
if effector and effector.action_change then
@ -249,6 +254,8 @@ end
-- Conductors
function mesecon.is_conductor_on(node, rulename)
if not node then return false end
local conductor = mesecon.get_conductor(node.name)
if conductor then
if conductor.state then
@ -263,10 +270,13 @@ function mesecon.is_conductor_on(node, rulename)
return mesecon.get_bit(binstate, bit)
end
end
return false
end
function mesecon.is_conductor_off(node, rulename)
if not node then return false end
local conductor = mesecon.get_conductor(node.name)
if conductor then
if conductor.state then
@ -281,6 +291,7 @@ function mesecon.is_conductor_off(node, rulename)
return not mesecon.get_bit(binstate, bit)
end
end
return false
end
@ -340,53 +351,47 @@ end
-- some more general high-level stuff
function mesecon.is_power_on(pos, rulename)
local node = minetest.get_node(pos)
if mesecon.is_conductor_on(node, rulename) or mesecon.is_receptor_on(node.name) then
local node = mesecon.get_node_force(pos)
if node and (mesecon.is_conductor_on(node, rulename) or mesecon.is_receptor_on(node.name)) then
return true
end
return false
end
function mesecon.is_power_off(pos, rulename)
local node = minetest.get_node(pos)
if mesecon.is_conductor_off(node, rulename) or mesecon.is_receptor_off(node.name) then
local node = mesecon.get_node_force(pos)
if node and (mesecon.is_conductor_off(node, rulename) or mesecon.is_receptor_off(node.name)) then
return true
end
return false
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)
local frontiers = {{pos = pos, link = link}}
local depth = 1
while frontiers[depth] do
local f = frontiers[depth]
local node = minetest.get_node_or_nil(f.pos)
while frontiers[1] do
local f = table.remove(frontiers, 1)
local node = mesecon.get_node_force(f.pos)
-- area not loaded, postpone action
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
local rules = mesecon.conductor_get_rules(node)
minetest.swap_node(f.pos, {name = mesecon.get_conductor_on(node, f.link),
param2 = node.param2})
-- call turnon on neighbors: normal rules
-- Call turnon on neighbors
for _, r in ipairs(mesecon.rule2meta(f.link, rules)) do
local np = mesecon.addPosRule(f.pos, r)
-- area not loaded, postpone action
if not minetest.get_node_or_nil(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
local np = vector.add(f.pos, r)
for _, l in ipairs(mesecon.rules_link_rule_all(f.pos, r)) do
table.insert(frontiers, {pos = np, link = l})
end
end
mesecon.swap_node_force(f.pos, mesecon.get_conductor_on(node, f.link))
elseif mesecon.is_effector(node.name) then
mesecon.changesignal(f.pos, node, f.link, mesecon.state.on, depth)
if mesecon.is_effector_off(node.name) then
@ -397,176 +402,117 @@ function mesecon.turnon(pos, link)
end
end
mesecon.queue:add_function("turnon", function (pos, rulename, recdepth)
mesecon.turnon(pos, rulename, recdepth)
end)
-- Turn on 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, 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)
local frontiers = {{pos = pos, link = link}}
local signals = {}
local depth = 1
while frontiers[depth] do
local f = frontiers[depth]
local node = minetest.get_node_or_nil(f.pos)
while frontiers[1] do
local f = table.remove(frontiers, 1)
local node = mesecon.get_node_force(f.pos)
-- area not loaded, postpone action
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
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
local np = mesecon.addPosRule(f.pos, r)
local np = vector.add(f.pos, r)
-- area not loaded, postpone action
if not minetest.get_node_or_nil(np) then
mesecon.queue:add_action(np, "turnoff", {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})
-- Check if an onstate receptor is connected. If that is the case,
-- abort this turnoff process by returning false. `receptor_off` will
-- discard all the changes that we made in the voxelmanip:
for _, l in ipairs(mesecon.rules_link_rule_all_inverted(f.pos, r)) do
if mesecon.is_receptor_on(mesecon.get_node_force(np).name) then
return false
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
mesecon.swap_node_force(f.pos, mesecon.get_conductor_off(node, f.link))
elseif mesecon.is_effector(node.name) then
mesecon.changesignal(f.pos, node, f.link, mesecon.state.off, depth)
if mesecon.is_effector_on(node.name) and not mesecon.is_powered(f.pos) then
mesecon.deactivate(f.pos, node, f.link, depth)
end
table.insert(signals, {
pos = f.pos,
node = node,
link = f.link,
depth = depth
})
end
depth = depth + 1
end
end
mesecon.queue:add_function("turnoff", function (pos, rulename, recdepth)
mesecon.turnoff(pos, rulename, recdepth)
end)
function mesecon.connected_to_receptor(pos, link)
local node = minetest.get_node(pos)
-- 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 = mesecon.addPosRule(pos, l)
if mesecon.find_receptor_on(np, mesecon.invertRule(l)) then
return true
end
for _, sig in ipairs(signals) do
mesecon.changesignal(sig.pos, sig.node, sig.link, mesecon.state.off, sig.depth)
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)
end
end
return false
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 = minetest.get_node_or_nil(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 = mesecon.addPosRule(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 = minetest.get_node(output)
local inputnode = minetest.get_node(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 mesecon.cmpPos(mesecon.addPosRule(output, outputrule), input) then
for _, inputrule in ipairs(mesecon.flattenrules(inputrules)) do
-- Check if input accepts from output
if mesecon.cmpPos(mesecon.addPosRule(input, inputrule), output) then
return true, inputrule
end
end
end
end
return false
return true
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)
local input = mesecon.addPosRule(output, rule)
local inputnode = minetest.get_node(input)
local inputrules = mesecon.get_any_inputrules (inputnode)
local input = vector.add(output, rule)
local inputnode = mesecon.get_node_force(input)
local inputrules = mesecon.get_any_inputrules(inputnode)
if not inputrules then
return {}
end
local rules = {}
for _, inputrule in ipairs(mesecon.flattenrules(inputrules)) do
-- Check if input accepts from output
if mesecon.cmpPos(mesecon.addPosRule(input, inputrule), output) then
if vector.equals(vector.add(input, inputrule), output) then
table.insert(rules, inputrule)
end
end
return rules
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)
--local irule = mesecon.invertRule(rule)
local output = mesecon.addPosRule(input, rule)
local outputnode = minetest.get_node(output)
local outputrules = mesecon.get_any_outputrules (outputnode)
local output = vector.add(input, rule)
local outputnode = mesecon.get_node_force(output)
local outputrules = mesecon.get_any_outputrules(outputnode)
if not outputrules then
return {}
end
local rules = {}
for _, outputrule in ipairs(mesecon.flattenrules(outputrules)) do
if mesecon.cmpPos(mesecon.addPosRule(output, outputrule), input) then
if vector.equals(vector.add(output, outputrule), input) then
table.insert(rules, mesecon.invertRule(outputrule))
end
end
return rules
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)
local node = minetest.get_node(pos)
local node = mesecon.get_node_force(pos)
local rules = mesecon.get_any_inputrules(node)
if not rules then return false end
@ -577,10 +523,11 @@ function mesecon.is_powered(pos, rule)
for _, rule in ipairs(mesecon.flattenrules(rules)) do
local rulenames = mesecon.rules_link_rule_all_inverted(pos, rule)
for _, rname in ipairs(rulenames) do
local np = mesecon.addPosRule(pos, rname)
local nn = minetest.get_node(np)
if (mesecon.is_conductor_on (nn, mesecon.invertRule(rname))
or mesecon.is_receptor_on (nn.name)) then
local np = vector.add(pos, rname)
local nn = mesecon.get_node_force(np)
if (mesecon.is_conductor_on(nn, mesecon.invertRule(rname))
or mesecon.is_receptor_on(nn.name)) then
table.insert(sourcepos, np)
end
end
@ -588,8 +535,8 @@ function mesecon.is_powered(pos, rule)
else
local rulenames = mesecon.rules_link_rule_all_inverted(pos, rule)
for _, rname in ipairs(rulenames) do
local np = mesecon.addPosRule(pos, rname)
local nn = minetest.get_node(np)
local np = vector.add(pos, rname)
local nn = mesecon.get_node_force(np)
if (mesecon.is_conductor_on (nn, mesecon.invertRule(rname))
or mesecon.is_receptor_on (nn.name)) then
table.insert(sourcepos, np)
@ -607,8 +554,8 @@ function mesecon.rotate_rules_right(rules)
local nr = {}
for i, rule in ipairs(rules) do
table.insert(nr, {
x = -rule.z,
y = rule.y,
x = -rule.z,
y = rule.y,
z = rule.x,
name = rule.name})
end
@ -619,8 +566,8 @@ function mesecon.rotate_rules_left(rules)
local nr = {}
for i, rule in ipairs(rules) do
table.insert(nr, {
x = rule.z,
y = rule.y,
x = rule.z,
y = rule.y,
z = -rule.x,
name = rule.name})
end
@ -631,8 +578,8 @@ function mesecon.rotate_rules_down(rules)
local nr = {}
for i, rule in ipairs(rules) do
table.insert(nr, {
x = -rule.y,
y = rule.x,
x = -rule.y,
y = rule.x,
z = rule.z,
name = rule.name})
end
@ -643,8 +590,8 @@ function mesecon.rotate_rules_up(rules)
local nr = {}
for i, rule in ipairs(rules) do
table.insert(nr, {
x = rule.y,
y = -rule.x,
x = rule.y,
y = -rule.x,
z = rule.z,
name = rule.name})
end

@ -1,30 +1,97 @@
-- Ugly hack to prevent breaking compatibility with other mods
-- Just remove the following two functions to delete the hack, to be done when other mods have updated
function mesecon.receptor_on(self, pos, rules)
if (self.receptor_on) then
print("[Mesecons] Warning: A mod with mesecon support called mesecon:receptor_on.")
print("[Mesecons] If you are the programmer of this mod, please update it ")
print("[Mesecons] to use mesecon.receptor_on 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_on", {rules}, nil, rules)
-- Un-forceload any forceloaded mapblocks from older versions of Mesecons which
-- used forceloading instead of VoxelManipulators.
local BLOCKSIZE = 16
-- convert block hash --> node position
local function unhash_blockpos(hash)
return vector.multiply(minetest.get_position_from_hash(hash), BLOCKSIZE)
end
function mesecon.receptor_off(self, pos, rules)
if (self.receptor_off) then
print("[Mesecons] Warning: A mod with mesecon support called mesecon:receptor_off.")
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)
local old_forceloaded_blocks = mesecon.file2table("mesecon_forceloaded")
for hash, _ in pairs(old_forceloaded_blocks) do
minetest.forceload_free_block(unhash_blockpos(hash))
end
os.remove(minetest.get_worldpath()..DIR_DELIM.."mesecon_forceloaded")
-- LBMs to convert old pistons to use facedir instead of separate up/down nodes
minetest.register_lbm({
label = "Convert up pistons to use facedir",
name = ":mesecons_pistons:update_up_pistons",
nodenames = {"mesecons_pistons:piston_up_normal_on","mesecons_pistons:piston_up_normal_off",
"mesecons_pistons:piston_up_sticky_on","mesecons_pistons:piston_up_sticky_off"},
action = function(pos, node)
if string.find(node.name, "sticky") then
if string.sub(node.name, -3, -1) == "_on" then
node.name = "mesecons_pistons:piston_sticky_on"
else
node.name = "mesecons_pistons:piston_sticky_off"
end
else
if string.sub(node.name, -3, -1) == "_on" then
node.name = "mesecons_pistons:piston_normal_on"
else
node.name = "mesecons_pistons:piston_normal_off"
end
end
local dir = {x=0, y=-1, z=0}
node.param2 = minetest.dir_to_facedir(dir, true)
minetest.swap_node(pos, node)
end
})
minetest.register_lbm({
label = "Convert down pistons to use facedir",
name = ":mesecons_pistons:update_down_pistons",
nodenames = {"mesecons_pistons:piston_down_normal_on","mesecons_pistons:piston_down_normal_off",
"mesecons_pistons:piston_down_sticky_on","mesecons_pistons:piston_down_sticky_off"},
action = function(pos, node)
if string.find(node.name, "sticky") then
if string.sub(node.name, -3, -1) == "_on" then
node.name = "mesecons_pistons:piston_sticky_on"
else
node.name = "mesecons_pistons:piston_sticky_off"
end
else
if string.sub(node.name, -3, -1) == "_on" then
node.name = "mesecons_pistons:piston_normal_on"
else
node.name = "mesecons_pistons:piston_normal_off"
end
end
local dir = {x=0, y=1, z=0}
node.param2 = minetest.dir_to_facedir(dir, true)
minetest.swap_node(pos, node)
end
})
minetest.register_lbm({
label = "Convert up piston pushers to use facedir",
name = ":mesecons_pistons:update_up_pushers",
nodenames = {"mesecons_pistons:piston_up_pusher_normal", "mesecons_pistons:piston_up_pusher_sticky"},
action = function(pos, node)
if string.find(node.name, "sticky") then
node.name = "mesecons_pistons:piston_pusher_sticky"
else
node.name = "mesecons_pistons:piston_pusher_normal"
end
local dir = {x=0, y=-1, z=0}
node.param2 = minetest.dir_to_facedir(dir, true)
minetest.swap_node(pos, node)
end
})
minetest.register_lbm({
label = "Convert down piston pushers to use facedir",
name = ":mesecons_pistons:update_down_pushers",
nodenames = {"mesecons_pistons:piston_down_pusher_normal", "mesecons_pistons:piston_down_pusher_sticky"},
action = function(pos, node)
if string.find(node.name, "sticky") then
node.name = "mesecons_pistons:piston_pusher_sticky"
else
node.name = "mesecons_pistons:piston_pusher_normal"
end
local dir = {x=0, y=1, z=0}
node.param2 = minetest.dir_to_facedir(dir, true)
minetest.swap_node(pos, node)
end
})

@ -30,7 +30,7 @@ minetest.register_node("mesecons:mesecon_on", {
},
groups = {dig_immediate=3, not_in_creaive_inventory=1, mesecon=1},
drop = "mesecons:mesecon_off 1",
light_source = LIGHT_MAX-11,
light_source = default.LIGHT_MAX-11,
mesecons = {conductor={
state = mesecon.state.on,
offstate = "mesecons:mesecon_off"

@ -21,7 +21,7 @@ mesecon.rules.buttonlike =
{{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 = 1, y =-1, z =-1},
{x = 2, y = 0, z = 0}}
@ -30,15 +30,30 @@ mesecon.rules.flat =
{x =-1, y = 0, z = 0},
{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}}
mesecon.rules.buttonlike_get = function(node)
local rules = mesecon.rules.buttonlike
if node.param2 == 2 then
local dir = minetest.facedir_to_dir(node.param2)
if dir.x == 1 then
-- No action needed
elseif dir.z == -1 then
rules=mesecon.rotate_rules_left(rules)
elseif node.param2 == 3 then
elseif dir.x == -1 then
rules=mesecon.rotate_rules_right(mesecon.rotate_rules_right(rules))
elseif node.param2 == 0 then
elseif dir.z == 1 then
rules=mesecon.rotate_rules_right(rules)
elseif dir.y == -1 then
rules=mesecon.rotate_rules_up(rules)
elseif dir.y == 1 then
rules=mesecon.rotate_rules_down(rules)
end
return rules
end

@ -1,7 +1,7 @@
-- Dig and place services
mesecon.on_placenode = function (pos, node)
mesecon.update_autoconnect(pos, node)
mesecon.on_placenode = function(pos, node)
mesecon.execute_autoconnect_hooks_now(pos, node)
-- Receptors: Send on signal when active
if mesecon.is_receptor_on(node.name) then
@ -16,7 +16,7 @@ mesecon.on_placenode = function (pos, node)
-- also call receptor_on if itself is powered already, so that neighboring
-- conductors will be activated (when pushing an on-conductor with a piston)
for _, s in ipairs(sources) do
local rule = {x = pos.x - s.x, y = pos.y - s.y, z = pos.z - s.z}
local rule = vector.subtract(pos, s)
mesecon.turnon(pos, rule)
end
--mesecon.receptor_on (pos, mesecon.conductor_get_rules(node))
@ -28,11 +28,13 @@ mesecon.on_placenode = function (pos, node)
-- Effectors: Send changesignal and activate or deactivate
if mesecon.is_effector(node.name) then
local powered_rules = {}
local unpowered_rules = {}
-- for each input rule, check if powered
for _, r in ipairs(mesecon.effector_get_rules(node)) do
local powered = mesecon.is_powered(pos, r)
if powered then table.insert(powered_rules, r) end
if powered then table.insert(powered_rules, r)
else table.insert(unpowered_rules, r) end
local state = powered and mesecon.state.on or mesecon.state.off
mesecon.changesignal(pos, node, r, state, 1)
@ -42,20 +44,23 @@ mesecon.on_placenode = function (pos, node)
for _, r in ipairs(powered_rules) do
mesecon.activate(pos, node, r, 1)
end
else
for _, r in ipairs(unpowered_rules) do
mesecon.deactivate(pos, node, r, 1)
end
end
end
end
mesecon.on_dignode = function (pos, node)
mesecon.on_dignode = function(pos, node)
if mesecon.is_conductor_on(node) then
mesecon.receptor_off(pos, mesecon.conductor_get_rules(node))
elseif mesecon.is_receptor_on(node.name) then
mesecon.receptor_off(pos, mesecon.receptor_get_rules(node))
end
mesecon.queue:add_action(pos, "update_autoconnect", {node})
end
mesecon.queue:add_function("update_autoconnect", mesecon.update_autoconnect)
mesecon.execute_autoconnect_hooks_queue(pos, node)
end
minetest.register_on_placenode(mesecon.on_placenode)
minetest.register_on_dignode(mesecon.on_dignode)
@ -81,10 +86,6 @@ end
mesecon.queue:add_function("cooldown", function (pos)
if minetest.get_item_group(minetest.get_node(pos).name, "overheat") == 0 then
return -- node has been moved, this one does not use overheating - ignore
end
local meta = minetest.get_meta(pos)
local heat = meta:get_int("heat")
@ -92,3 +93,11 @@ mesecon.queue:add_function("cooldown", function (pos)
meta:set_int("heat", heat - 1)
end
end)
-- "Shim" for simple rotation, will result in the following item in nodedefs using it:
-- "on_rotate = screwdriver.rotate_simple" if screwdriver mod is installed
-- "on_rotate = nil" (essentially not present) if screwdriver mod is missing
if screwdriver then
mesecon.rotate_simple = screwdriver.rotate_simple
end

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

@ -2,7 +2,7 @@ function mesecon.move_node(pos, newpos)
local node = minetest.get_node(pos)
local meta = minetest.get_meta(pos):to_table()
minetest.remove_node(pos)
minetest.add_node(newpos, node)
minetest.set_node(newpos, node)
minetest.get_meta(pos):from_table(meta)
end
@ -50,7 +50,7 @@ function mesecon.rule2bit(findrule, allrules)
end
for m,metarule in ipairs( allrules) do
for _, rule in ipairs(metarule ) do
if mesecon.cmpPos(findrule, rule) then
if vector.equals(findrule, rule) then
return m
end
end
@ -69,7 +69,7 @@ function mesecon.rule2metaindex(findrule, allrules)
for m, metarule in ipairs( allrules) do
for _, rule in ipairs(metarule ) do
if mesecon.cmpPos(findrule, rule) then
if vector.equals(findrule, rule) then
return m
end
end
@ -129,19 +129,11 @@ function mesecon.set_bit(binary,bit,value)
end
end
return binary
end
function mesecon.invertRule(r)
return {x = -r.x, y = -r.y, z = -r.z}
end
function mesecon.addPosRule(p, r)
return {x = p.x + r.x, y = p.y + r.y, z = p.z + r.z}
end
function mesecon.cmpPos(p1, p2)
return (p1.x == p2.x and p1.y == p2.y and p1.z == p2.z)
return vector.multiply(r, -1)
end
function mesecon.tablecopy(table) -- deep table copy
@ -203,9 +195,196 @@ function mesecon.flipstate(pos, node)
local newstate
if (nodedef.__mesecon_state == "on") then newstate = "off" end
if (nodedef.__mesecon_state == "off") then newstate = "on" end
minetest.swap_node(pos, {name = nodedef.__mesecon_basename .. "_" .. newstate,
param2 = node.param2})
return newstate
end
-- File writing / reading utilities
local wpath = minetest.get_worldpath()
function mesecon.file2table(filename)
local f = io.open(wpath..DIR_DELIM..filename, "r")
if f == nil then return {} end
local t = f:read("*all")
f:close()
if t == "" or t == nil then return {} end
return minetest.deserialize(t)
end
function mesecon.table2file(filename, table)
local f = io.open(wpath..DIR_DELIM..filename, "w")
f:write(minetest.serialize(table))
f:close()
end
-- Block position "hashing" (convert to integer) functions for voxelmanip cache
local BLOCKSIZE = 16
-- convert node position --> block hash
local function hash_blockpos(pos)
return minetest.hash_node_position({
x = math.floor(pos.x/BLOCKSIZE),
y = math.floor(pos.y/BLOCKSIZE),
z = math.floor(pos.z/BLOCKSIZE)
})
end
-- Maps from a hashed mapblock position (as returned by hash_blockpos) to a
-- table.
--
-- 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
-- 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
-- Finishes a VoxelManipulator-based transaction, freeing the VMs and throwing
-- 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 tbl = vm_cache[hash]
if not tbl then
local vm = minetest.get_voxel_manip(pos, pos)
local min_pos, max_pos = vm:get_emerged_area()
local va = VoxelArea:new{MinEdge = min_pos, MaxEdge = max_pos}
tbl = {vm = vm, va = va, data = vm:get_data(), param1 = vm:get_light_data(), param2 = vm:get_param2_data(), dirty = false}
vm_cache[hash] = tbl
end
return tbl
end
-- Gets the node at a given position during a VoxelManipulator-based
-- transaction.
function mesecon.vm_get_node(pos)
local tbl = vm_get_or_create_entry(pos)
local index = tbl.va:indexp(pos)
local node_value = tbl.data[index]
if node_value == core.CONTENT_IGNORE then
return nil
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
-- Sets a nodes name during a VoxelManipulator-based transaction.
--
-- Existing param1, param2, and metadata are left alone.
function mesecon.vm_swap_node(pos, name)
local tbl = vm_get_or_create_entry(pos)
local index = tbl.va:indexp(pos)
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

@ -0,0 +1 @@
The blinky plants toggles between on and off state every three seconds. Can be used to make clocks. Also works after having restarted the game.

Binary file not shown.

After

(image error) Size: 65 KiB

Binary file not shown.

After

(image error) Size: 2.9 KiB

@ -0,0 +1 @@
This receptor can be attached to walls. It turns on for 1 second if it's punched.

Binary file not shown.

After

(image error) Size: 78 KiB

Binary file not shown.

After

(image error) Size: 7.8 KiB

@ -15,7 +15,7 @@ end
minetest.register_node("mesecons_button:button_off", {
drawtype = "nodebox",
tiles = {
"jeija_wall_button_sides.png",
"jeija_wall_button_sides.png",
"jeija_wall_button_sides.png",
"jeija_wall_button_sides.png",
"jeija_wall_button_sides.png",
@ -26,13 +26,14 @@ minetest.register_node("mesecons_button:button_off", {
paramtype2 = "facedir",
legacy_wallmounted = true,
walkable = false,
on_rotate = mesecon.buttonlike_onrotate,
sunlight_propagates = true,
selection_box = {
type = "fixed",
fixed = { -6/16, -6/16, 5/16, 6/16, 6/16, 8/16 }
},
node_box = {
type = "fixed",
type = "fixed",
fixed = {
{ -6/16, -6/16, 6/16, 6/16, 6/16, 8/16 }, -- the thin plate behind the button
{ -4/16, -2/16, 4/16, 4/16, 2/16, 6/16 } -- the button itself
@ -40,7 +41,7 @@ minetest.register_node("mesecons_button:button_off", {
},
groups = {dig_immediate=2, mesecon_needs_receiver = 1},
description = "Button",
on_punch = function (pos, node)
on_rightclick = function (pos, node)
minetest.swap_node(pos, {name = "mesecons_button:button_on", param2=node.param2})
mesecon.receptor_on(pos, mesecon.rules.buttonlike_get(node))
minetest.sound_play("mesecons_button_push", {pos=pos})
@ -67,7 +68,8 @@ minetest.register_node("mesecons_button:button_on", {
paramtype2 = "facedir",
legacy_wallmounted = true,
walkable = false,
light_source = LIGHT_MAX-7,
on_rotate = false,
light_source = default.LIGHT_MAX-7,
sunlight_propagates = true,
selection_box = {
type = "fixed",

@ -0,0 +1 @@
There is no crafting recipe as this should only be available for server admins. Quite similar to the Minecraft counterpart. Executes server commands.

Binary file not shown.

After

(image error) Size: 36 KiB

@ -1,195 +1,208 @@
minetest.register_chatcommand("say", {
params = "<text>",
description = "Say <text> as the server",
privs = {server=true},
func = function(name, param)
minetest.chat_send_all(name .. ": " .. param)
end
})
minetest.register_chatcommand("tell", {
params = "<name> <text>",
description = "Say <text> to <name> privately",
func = function(name, param)
local found, _, target, message = param:find("^([^%s]+)%s+(.*)$")
if found == nil then
minetest.chat_send_player(name, "Invalid usage: " .. param)
return
end
if not minetest.get_player_by_name(target) then
minetest.chat_send_player(name, "Invalid target: " .. target)
end
minetest.chat_send_player(target, name .. " whispers: " .. message, false)
end
})
minetest.register_chatcommand("hp", {
params = "<name> <value>",
description = "Set health of <name> to <value> hitpoints",
privs = {ban=true},
func = function(name, param)
local found, _, target, value = param:find("^([^%s]+)%s+(%d+)$")
if found == nil then
minetest.chat_send_player(name, "Invalid usage: " .. param)
return
end
local player = minetest.get_player_by_name(target)
if player then
player:set_hp(value)
else
minetest.chat_send_player(name, "Invalid target: " .. target)
end
end
})
local function initialize_data(meta)
local commands = meta:get_string("commands")
meta:set_string("formspec",
"invsize[9,5;]" ..
"textarea[0.5,0.5;8.5,4;commands;Commands;"..commands.."]" ..
"label[1,3.8;@nearest, @farthest, and @random are replaced by the respective player names]" ..
"button_exit[3.3,4.5;2,1;submit;Submit]")
local owner = meta:get_string("owner")
if owner == "" then
owner = "not owned"
else
owner = "owned by " .. owner
end
meta:set_string("infotext", "Command Block\n" ..
"(" .. owner .. ")\n" ..
"Commands: "..commands)
end
local function construct(pos)
local meta = minetest.get_meta(pos)
meta:set_string("commands", "tell @nearest Commandblock unconfigured")
meta:set_string("owner", "")
initialize_data(meta)
end
local function after_place(pos, placer)
if placer then
local meta = minetest.get_meta(pos)
meta:set_string("owner", placer:get_player_name())
initialize_data(meta)
end
end
local function receive_fields(pos, formname, fields, sender)
if not fields.submit then
return
end
local meta = minetest.get_meta(pos)
local owner = meta:get_string("owner")
if owner ~= "" and sender:get_player_name() ~= owner then
return
end
meta:set_string("commands", fields.commands)
initialize_data(meta)
end
local function resolve_commands(commands, pos)
local nearest, farthest = nil, nil
local min_distance, max_distance = math.huge, -1
local players = minetest.get_connected_players()
for index, player in pairs(players) do
local distance = vector.distance(pos, player:getpos())
if distance < min_distance then
min_distance = distance
nearest = player:get_player_name()
end
if distance > max_distance then
max_distance = distance
farthest = player:get_player_name()
end
end
local random = players[math.random(#players)]:get_player_name()
commands = commands:gsub("@nearest", nearest)
commands = commands:gsub("@farthest", farthest)
commands = commands:gsub("@random", random)
return commands
end
local function commandblock_action_on(pos, node)
if node.name ~= "mesecons_commandblock:commandblock_off" then
return
end
minetest.swap_node(pos, {name = "mesecons_commandblock:commandblock_on"})
local meta = minetest.get_meta(pos)
local owner = meta:get_string("owner")
if owner == "" then
return
end
local commands = resolve_commands(meta:get_string("commands"), pos)
for _, command in pairs(commands:split("\n")) do
local pos = command:find(" ")
local cmd, param = command, ""
if pos then
cmd = command:sub(1, pos - 1)
param = command:sub(pos + 1)
end
local cmddef = minetest.chatcommands[cmd]
if not cmddef then
minetest.chat_send_player(owner, "The command "..cmd.." does not exist")
return
end
local has_privs, missing_privs = minetest.check_player_privs(owner, cmddef.privs)
if not has_privs then
minetest.chat_send_player(owner, "You don't have permission "
.."to run "..cmd
.." (missing privileges: "
..table.concat(missing_privs, ", ")..")")
return
end
cmddef.func(owner, param)
end
end
local function commandblock_action_off(pos, node)
if node.name == "mesecons_commandblock:commandblock_on" then
minetest.swap_node(pos, {name = "mesecons_commandblock:commandblock_off"})
end
end
local function can_dig(pos, player)
local meta = minetest.get_meta(pos)
local owner = meta:get_string("owner")
return owner == "" or owner == player:get_player_name()
end
minetest.register_node("mesecons_commandblock:commandblock_off", {
description = "Command Block",
tiles = {"jeija_commandblock_off.png"},
inventory_image = minetest.inventorycube("jeija_commandblock_off.png"),
groups = {cracky=2, mesecon_effector_off=1},
on_construct = construct,
after_place_node = after_place,
on_receive_fields = receive_fields,
can_dig = can_dig,
sounds = default.node_sound_stone_defaults(),
mesecons = {effector = {
action_on = commandblock_action_on
}}
})
minetest.register_node("mesecons_commandblock:commandblock_on", {
tiles = {"jeija_commandblock_on.png"},
groups = {cracky=2, mesecon_effector_on=1, not_in_creative_inventory=1},
light_source = 10,
drop = "mesecons_commandblock:commandblock_off",
on_construct = construct,
after_place_node = after_place,
on_receive_fields = receive_fields,
can_dig = can_dig,
sounds = default.node_sound_stone_defaults(),
mesecons = {effector = {
action_off = commandblock_action_off
}}
})
minetest.register_chatcommand("say", {
params = "<text>",
description = "Say <text> as the server",
privs = {server=true},
func = function(name, param)
minetest.chat_send_all(name .. ": " .. param)
end
})
minetest.register_chatcommand("tell", {
params = "<name> <text>",
description = "Say <text> to <name> privately",
func = function(name, param)
local found, _, target, message = param:find("^([^%s]+)%s+(.*)$")
if found == nil then
minetest.chat_send_player(name, "Invalid usage: " .. param)
return
end
if not minetest.get_player_by_name(target) then
minetest.chat_send_player(name, "Invalid target: " .. target)
end
minetest.chat_send_player(target, name .. " whispers: " .. message, false)
end
})
minetest.register_chatcommand("hp", {
params = "<name> <value>",
description = "Set health of <name> to <value> hitpoints",
privs = {ban=true},
func = function(name, param)
local found, _, target, value = param:find("^([^%s]+)%s+(%d+)$")
if found == nil then
minetest.chat_send_player(name, "Invalid usage: " .. param)
return
end
local player = minetest.get_player_by_name(target)
if player then
player:set_hp(value)
else
minetest.chat_send_player(name, "Invalid target: " .. target)
end
end
})
local function initialize_data(meta)
local commands = minetest.formspec_escape(meta:get_string("commands"))
meta:set_string("formspec",
"invsize[9,5;]" ..
"textarea[0.5,0.5;8.5,4;commands;Commands;"..commands.."]" ..
"label[1,3.8;@nearest, @farthest, and @random are replaced by the respective player names]" ..
"button_exit[3.3,4.5;2,1;submit;Submit]")
local owner = meta:get_string("owner")
if owner == "" then
owner = "not owned"
else
owner = "owned by " .. owner
end
meta:set_string("infotext", "Command Block\n" ..
"(" .. owner .. ")\n" ..
"Commands: "..commands)
end
local function construct(pos)
local meta = minetest.get_meta(pos)
meta:set_string("commands", "tell @nearest Commandblock unconfigured")
meta:set_string("owner", "")
initialize_data(meta)
end
local function after_place(pos, placer)
if placer then
local meta = minetest.get_meta(pos)
meta:set_string("owner", placer:get_player_name())
initialize_data(meta)
end
end
local function receive_fields(pos, formname, fields, sender)
if not fields.submit then
return
end
local meta = minetest.get_meta(pos)
local owner = meta:get_string("owner")
if owner ~= "" and sender:get_player_name() ~= owner then
return
end
meta:set_string("commands", fields.commands)
initialize_data(meta)
end
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 min_distance, max_distance = math.huge, -1
for index, player in pairs(players) do
local distance = vector.distance(pos, player:getpos())
if distance < min_distance then
min_distance = distance
nearest = player:get_player_name()
end
if distance > max_distance then
max_distance = distance
farthest = player:get_player_name()
end
end
local random = players[math.random(#players)]:get_player_name()
commands = commands:gsub("@nearest", nearest)
commands = commands:gsub("@farthest", farthest)
commands = commands:gsub("@random", random)
return commands
end
local function commandblock_action_on(pos, node)
if node.name ~= "mesecons_commandblock:commandblock_off" then
return
end
minetest.swap_node(pos, {name = "mesecons_commandblock:commandblock_on"})
local meta = minetest.get_meta(pos)
local owner = meta:get_string("owner")
if owner == "" then
return
end
local commands = resolve_commands(meta:get_string("commands"), pos)
for _, command in pairs(commands:split("\n")) do
local pos = command:find(" ")
local cmd, param = command, ""
if pos then
cmd = command:sub(1, pos - 1)
param = command:sub(pos + 1)
end
local cmddef = minetest.chatcommands[cmd]
if not cmddef then
minetest.chat_send_player(owner, "The command "..cmd.." does not exist")
return
end
local has_privs, missing_privs = minetest.check_player_privs(owner, cmddef.privs)
if not has_privs then
minetest.chat_send_player(owner, "You don't have permission "
.."to run "..cmd
.." (missing privileges: "
..table.concat(missing_privs, ", ")..")")
return
end
cmddef.func(owner, param)
end
end
local function commandblock_action_off(pos, node)
if node.name == "mesecons_commandblock:commandblock_on" then
minetest.swap_node(pos, {name = "mesecons_commandblock:commandblock_off"})
end
end
local function can_dig(pos, player)
local meta = minetest.get_meta(pos)
local owner = meta:get_string("owner")
return owner == "" or owner == player:get_player_name()
end
minetest.register_node("mesecons_commandblock:commandblock_off", {
description = "Command Block",
tiles = {"jeija_commandblock_off.png"},
inventory_image = minetest.inventorycube("jeija_commandblock_off.png"),
groups = {cracky=2, mesecon_effector_off=1},
on_construct = construct,
after_place_node = after_place,
on_receive_fields = receive_fields,
can_dig = can_dig,
sounds = default.node_sound_stone_defaults(),
mesecons = {effector = {
action_on = commandblock_action_on
}}
})
minetest.register_node("mesecons_commandblock:commandblock_on", {
tiles = {"jeija_commandblock_on.png"},
groups = {cracky=2, mesecon_effector_on=1, not_in_creative_inventory=1},
light_source = 10,
drop = "mesecons_commandblock:commandblock_off",
on_construct = construct,
after_place_node = after_place,
on_receive_fields = receive_fields,
can_dig = can_dig,
sounds = default.node_sound_stone_defaults(),
mesecons = {effector = {
action_off = commandblock_action_off
}}
})

@ -0,0 +1 @@
The delayer delays the signal from the input for a determined time. The time can be set by punching the delayer. Possible delays are: 0.1 seconds, 0.3 seconds, 0.5 seconds and 1 second. You may try to use it for creating songs with the noteblock.

Binary file not shown.

After

(image error) Size: 61 KiB

Binary file not shown.

After

(image error) Size: 8.3 KiB

@ -35,7 +35,7 @@ end
for i = 1, 4 do
local groups = {}
if i == 1 then
if i == 1 then
groups = {bendy=2,snappy=1,dig_immediate=2}
else
groups = {bendy=2,snappy=1,dig_immediate=2, not_in_creative_inventory=1}
@ -47,7 +47,8 @@ elseif i == 2 then delaytime = 0.3
elseif i == 3 then delaytime = 0.5
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
{ -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
{ -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), {
description = "Delayer",

@ -0,0 +1,6 @@
The node detector is a receptor. It changes its state when either any node
or a specific node is detected. Right-click it to set a nodename to scan for.
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
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.

Binary file not shown.

After

(image error) Size: 48 KiB

Binary file not shown.

After

(image error) Size: 9.8 KiB

@ -0,0 +1,3 @@
The object detector is a receptor. It changes its state when a player approaches.
Right-click it to set a name to scan for.
It can also receive digiline signals which are the name to scan for on the specified channel in the right-click menu.

Binary file not shown.

After

(image error) Size: 84 KiB

Binary file not shown.

After

(image error) Size: 9.6 KiB

@ -4,16 +4,15 @@ local GET_COMMAND = "GET"
-- Detects players in a certain radius
-- The radius can be specified in mesecons/settings.lua
local object_detector_make_formspec = function (pos)
local meta = minetest.get_meta(pos)
meta:set_string("formspec", "size[9,2.5]" ..
local function object_detector_make_formspec(pos)
minetest.get_meta(pos):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,1.5;4,2;digiline_channel;Digiline Channel (optional):;${digiline_channel}]"..
"button_exit[7,0.75;2,3;;Save]")
end
local object_detector_on_receive_fields = function(pos, formname, fields)
if not fields.scanname or not fields.digiline_channel then return end;
local function object_detector_on_receive_fields(pos, _, fields)
if not fields.scanname or not fields.digiline_channel then return end
local meta = minetest.get_meta(pos)
meta:set_string("scanname", fields.scanname)
@ -22,25 +21,35 @@ local object_detector_on_receive_fields = function(pos, formname, fields)
end
-- returns true if player was found, false if not
local object_detector_scan = function (pos)
local function object_detector_scan(pos)
local objs = minetest.get_objects_inside_radius(pos, mesecon.setting("detector_radius", 6))
for k, obj in pairs(objs) do
local isname = obj:get_player_name() -- "" is returned if it is not a player; "" ~= nil!
local scanname = minetest.get_meta(pos):get_string("scanname")
if (isname == scanname and isname ~= "") or (isname ~= "" and scanname == "") then -- player with scanname found or not scanname specified
return true
-- abort if no scan results were found
if next(objs) == nil then return false end
local scanname = minetest.get_meta(pos):get_string("scanname")
local every_player = scanname == ""
for _, obj in pairs(objs) do
-- "" is returned if it is not a player; "" ~= nil; so only handle objects with foundname ~= ""
local foundname = obj:get_player_name()
if foundname ~= "" then
-- return true if scanning for any player or if specific playername was detected
if scanname == "" or foundname == scanname then
return true
end
end
end
return false
end
-- set player name when receiving a digiline signal on a specific channel
local object_detector_digiline = {
effector = {
action = function (pos, node, channel, msg)
action = function(pos, node, channel, msg)
local meta = minetest.get_meta(pos)
local active_channel = meta:get_string("digiline_channel")
if channel == active_channel then
if channel == meta:get_string("digiline_channel") then
meta:set_string("scanname", msg)
object_detector_make_formspec(pos)
end
@ -89,43 +98,44 @@ minetest.register_craft({
}
})
minetest.register_abm(
{nodenames = {"mesecons_detector:object_detector_off"},
interval = 1.0,
minetest.register_abm({
nodenames = {"mesecons_detector:object_detector_off"},
interval = 1,
chance = 1,
action = function(pos)
if object_detector_scan(pos) then
minetest.swap_node(pos, {name = "mesecons_detector:object_detector_on"})
mesecon.receptor_on(pos, mesecon.rules.pplate)
end
action = function(pos, node)
if not object_detector_scan(pos) then return end
node.name = "mesecons_detector:object_detector_on"
minetest.swap_node(pos, node)
mesecon.receptor_on(pos, mesecon.rules.pplate)
end,
})
minetest.register_abm(
{nodenames = {"mesecons_detector:object_detector_on"},
interval = 1.0,
minetest.register_abm({
nodenames = {"mesecons_detector:object_detector_on"},
interval = 1,
chance = 1,
action = function(pos)
if not object_detector_scan(pos) then
minetest.swap_node(pos, {name = "mesecons_detector:object_detector_off"})
mesecon.receptor_off(pos, mesecon.rules.pplate)
end
action = function(pos, node)
if object_detector_scan(pos) then return end
node.name = "mesecons_detector:object_detector_off"
minetest.swap_node(pos, node)
mesecon.receptor_off(pos, mesecon.rules.pplate)
end,
})
-- Node detector
-- Detects the node in front of it
local node_detector_make_formspec = function (pos)
local meta = minetest.get_meta(pos)
meta:set_string("formspec", "size[9,2.5]" ..
local function node_detector_make_formspec(pos)
minetest.get_meta(pos):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,1.5;4,2;digiline_channel;Digiline Channel (optional):;${digiline_channel}]"..
"button_exit[7,0.75;2,3;;Save]")
end
local node_detector_on_receive_fields = function(pos, formname, fields)
if not fields.scanname or not fields.digiline_channel then return end;
local function node_detector_on_receive_fields(pos, _, fields)
if not fields.scanname or not fields.digiline_channel then return end
local meta = minetest.get_meta(pos)
meta:set_string("scanname", fields.scanname)
@ -133,37 +143,59 @@ local node_detector_on_receive_fields = function(pos, formname, fields)
node_detector_make_formspec(pos)
end
-- returns true if player was found, false if not
local node_detector_scan = function (pos)
local node = minetest.get_node(pos)
local frontpos = vector.subtract(pos, minetest.facedir_to_dir(node.param2))
local frontnode = minetest.get_node(frontpos)
local meta = minetest.get_meta(pos)
return (frontnode.name == meta:get_string("scanname")) or
(frontnode.name ~= "air" and frontnode.name ~= "ignore" and meta:get_string("scanname") == "")
-- returns true if node was found, false if not
local function node_detector_scan(pos)
local node = minetest.get_node_or_nil(pos)
if not node then return end
local frontname = minetest.get_node(
vector.subtract(pos, minetest.facedir_to_dir(node.param2))
).name
local scanname = minetest.get_meta(pos):get_string("scanname")
return (frontname == scanname) or
(frontname ~= "air" and frontname ~= "ignore" and scanname == "")
end
-- set player name when receiving a digiline signal on a specific channel
local node_detector_digiline = {
effector = {
action = function (pos, node, channel, msg)
action = function(pos, node, channel, msg)
local meta = minetest.get_meta(pos)
local active_channel = meta:get_string("digiline_channel")
if channel == active_channel then
if msg == GET_COMMAND then
local frontpos = vector.subtract(pos, minetest.facedir_to_dir(node.param2))
local name = minetest.get_node(frontpos).name
digiline:receptor_send(pos, digiline.rules.default, channel, name)
else
meta:set_string("scanname", msg)
node_detector_make_formspec(pos)
end
if channel ~= meta:get_string("digiline_channel") then return end
if msg == GET_COMMAND then
local nodename = minetest.get_node(
vector.subtract(pos, minetest.facedir_to_dir(node.param2))
).name
digiline:receptor_send(pos, digiline.rules.default, channel, nodename)
else
meta:set_string("scanname", msg)
node_detector_make_formspec(pos)
end
end,
},
receptor = {}
}
local function after_place_node_detector(pos, placer)
local placer_pos = placer:getpos()
if not placer_pos then
return
end
--correct for the player's height
if placer:is_player() then
placer_pos.y = placer_pos.y + 1.625
end
--correct for 6d facedir
local node = minetest.get_node(pos)
node.param2 = minetest.dir_to_facedir(vector.subtract(pos, placer_pos), true)
minetest.set_node(pos, node)
end
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"},
paramtype = "light",
@ -176,25 +208,7 @@ minetest.register_node("mesecons_detector:node_detector_off", {
}},
on_construct = node_detector_make_formspec,
on_receive_fields = node_detector_on_receive_fields,
after_place_node = function (pos, placer)
local placer_pos = placer:getpos()
--correct for the player's height
if placer:is_player() then placer_pos.y = placer_pos.y + 1.5 end
--correct for 6d facedir
if placer_pos then
local dir = {
x = pos.x - placer_pos.x,
y = pos.y - placer_pos.y,
z = pos.z - placer_pos.z
}
local node = minetest.get_node(pos)
node.param2 = minetest.dir_to_facedir(dir, true)
minetest.set_node(pos, node)
minetest.log("action", "real (6d) facedir: " .. node.param2)
end
end,
after_place_node = after_place_node_detector,
sounds = default.node_sound_stone_defaults(),
digiline = node_detector_digiline
})
@ -211,25 +225,7 @@ minetest.register_node("mesecons_detector:node_detector_on", {
}},
on_construct = node_detector_make_formspec,
on_receive_fields = node_detector_on_receive_fields,
after_place_node = function (pos, placer)
local placer_pos = placer:getpos()
--correct for the player's height
if placer:is_player() then placer_pos.y = placer_pos.y + 1.5 end
--correct for 6d facedir
if placer_pos then
local dir = {
x = pos.x - placer_pos.x,
y = pos.y - placer_pos.y,
z = pos.z - placer_pos.z
}
local node = minetest.get_node(pos)
node.param2 = minetest.dir_to_facedir(dir, true)
minetest.set_node(pos, node)
minetest.log("action", "real (6d) facedir: " .. node.param2)
end
end,
after_place_node = after_place_node_detector,
sounds = default.node_sound_stone_defaults(),
digiline = node_detector_digiline
})
@ -243,26 +239,28 @@ minetest.register_craft({
}
})
minetest.register_abm(
{nodenames = {"mesecons_detector:node_detector_off"},
interval = 1.0,
minetest.register_abm({
nodenames = {"mesecons_detector:node_detector_off"},
interval = 1,
chance = 1,
action = function(pos, node)
if node_detector_scan(pos) then
minetest.swap_node(pos, {name = "mesecons_detector:node_detector_on", param2 = node.param2})
mesecon.receptor_on(pos)
end
if not node_detector_scan(pos) then return end
node.name = "mesecons_detector:node_detector_on"
minetest.swap_node(pos, node)
mesecon.receptor_on(pos)
end,
})
minetest.register_abm(
{nodenames = {"mesecons_detector:node_detector_on"},
interval = 1.0,
minetest.register_abm({
nodenames = {"mesecons_detector:node_detector_on"},
interval = 1,
chance = 1,
action = function(pos, node)
if not node_detector_scan(pos) then
minetest.swap_node(pos, {name = "mesecons_detector:node_detector_off", param2 = node.param2})
mesecon.receptor_off(pos)
end
if node_detector_scan(pos) then return end
node.name = "mesecons_detector:node_detector_off"
minetest.swap_node(pos, node)
mesecon.receptor_off(pos)
end,
})

@ -13,36 +13,60 @@ local function on_rightclick(pos, dir, check_name, replace, replace_dir, params)
minetest.swap_node(pos, {name = replace, param2 = p2})
if (minetest.get_meta(pos):get_int("right") ~= 0) == (params[1] ~= 3) then
minetest.sound_play("door_close", {pos = pos, gain = 0.3, max_hear_distance = 10})
minetest.sound_play("doors_door_close", {pos = pos, gain = 0.3, max_hear_distance = 10})
else
minetest.sound_play("door_open", {pos = pos, gain = 0.3, max_hear_distance = 10})
minetest.sound_play("doors_door_open", {pos = pos, gain = 0.3, max_hear_distance = 10})
end
end
local function meseconify_door(name)
local function toggle_state1 (pos, node)
on_rightclick(pos, 1, name.."_t_1", name.."_b_2", name.."_t_2", {1,2,3,0})
if minetest.registered_items[name .. "_b_1"] then
-- old style double-node doors
local function toggle_state1 (pos, node)
on_rightclick(pos, 1, name.."_t_1", name.."_b_2", name.."_t_2", {1,2,3,0})
end
local function toggle_state2 (pos, node)
on_rightclick(pos, 1, name.."_t_2", name.."_b_1", name.."_t_1", {3,0,1,2})
end
minetest.override_item(name.."_b_1", {
mesecons = {effector = {
action_on = toggle_state1,
action_off = toggle_state1,
rules = mesecon.rules.pplate
}}
})
minetest.override_item(name.."_b_2", {
mesecons = {effector = {
action_on = toggle_state2,
action_off = toggle_state2,
rules = mesecon.rules.pplate
}}
})
elseif minetest.registered_items[name .. "_a"] then
-- new style mesh node based doors
local override = {
mesecons = {effector = {
action_on = function(pos, node)
local door = doors.get(pos)
if door then
door:open()
end
end,
action_off = function(pos, node)
local door = doors.get(pos)
if door then
door:close()
end
end,
rules = mesecon.rules.pplate
}}
}
minetest.override_item(name .. "_a", override)
minetest.override_item(name .. "_b", override)
end
local function toggle_state2 (pos, node)
on_rightclick(pos, 1, name.."_t_2", name.."_b_1", name.."_t_1", {3,0,1,2})
end
minetest.override_item(name.."_b_1", {
mesecons = {effector = {
action_on = toggle_state1,
action_off = toggle_state1,
rules = mesecon.rules.pplate
}},
})
minetest.override_item(name.."_b_2", {
mesecons = {effector = {
action_on = toggle_state2,
action_off = toggle_state2,
rules = mesecon.rules.pplate
}},
})
end
meseconify_door("doors:door_wood")
@ -65,16 +89,41 @@ local function trapdoor_switch(pos, node)
minetest.get_meta(pos):set_int("state", state == 1 and 0 or 1)
end
minetest.override_item("doors:trapdoor", {
mesecons = {effector = {
action_on = trapdoor_switch,
action_off = trapdoor_switch
}},
})
if doors and doors.get then
local override = {
mesecons = {effector = {
action_on = function(pos, node)
local door = doors.get(pos)
if door then
door:open()
end
end,
action_off = function(pos, node)
local door = doors.get(pos)
if door then
door:close()
end
end,
}},
}
minetest.override_item("doors:trapdoor", override)
minetest.override_item("doors:trapdoor_open", override)
minetest.override_item("doors:trapdoor_steel", override)
minetest.override_item("doors:trapdoor_steel_open", override)
else
if minetest.registered_nodes["doors:trapdoor"] then
minetest.override_item("doors:trapdoor", {
mesecons = {effector = {
action_on = trapdoor_switch,
action_off = trapdoor_switch
}},
})
minetest.override_item("doors:trapdoor_open", {
mesecons = {effector = {
action_on = trapdoor_switch,
action_off = trapdoor_switch
}},
})
minetest.override_item("doors:trapdoor_open", {
mesecons = {effector = {
action_on = trapdoor_switch,
action_off = trapdoor_switch
}},
})
end
end

@ -10,7 +10,7 @@ local corner_selectionbox = {
}
local corner_get_rules = function (node)
local rules =
local rules =
{{x = 1, y = 0, z = 0},
{x = 0, y = 0, z = -1}}
@ -37,9 +37,10 @@ minetest.register_node("mesecons_extrawires:corner_on", {
sunlight_propagates = true,
selection_box = corner_selectionbox,
node_box = corner_nodebox,
on_rotate = mesecon.rotate_simple,
groups = {dig_immediate = 3, not_in_creative_inventory = 1},
drop = "mesecons_extrawires:corner_off",
mesecons = {conductor =
mesecons = {conductor =
{
state = mesecon.state.on,
rules = corner_get_rules,
@ -49,7 +50,7 @@ minetest.register_node("mesecons_extrawires:corner_on", {
minetest.register_node("mesecons_extrawires:corner_off", {
drawtype = "nodebox",
description = "Mesecon Corner",
description = "Insulated Mesecon Corner",
tiles = {
"jeija_insulated_wire_curved_tb_off.png",
"jeija_insulated_wire_curved_tb_off.png^[transformR270",
@ -64,8 +65,9 @@ minetest.register_node("mesecons_extrawires:corner_off", {
sunlight_propagates = true,
selection_box = corner_selectionbox,
node_box = corner_nodebox,
on_rotate = mesecon.rotate_simple,
groups = {dig_immediate = 3},
mesecons = {conductor =
mesecons = {conductor =
{
state = mesecon.state.off,
rules = corner_get_rules,

@ -1,4 +1,4 @@
function crossover_get_rules(node)
local function crossover_get_rules(node)
return {
{--first wire
{x=-1,y=0,z=0},
@ -19,29 +19,20 @@ local crossover_states = {
}
minetest.register_node("mesecons_extrawires:crossover_off", {
description = "Insulated Crossover",
drawtype = "nodebox",
description = "Insulated Mesecon Crossover",
drawtype = "mesh",
mesh = "mesecons_extrawires_crossover.b3d",
tiles = {
"jeija_insulated_wire_crossing_tb_off.png",
"jeija_insulated_wire_crossing_tb_off.png",
"jeija_insulated_wire_ends_off.png",
"jeija_insulated_wire_sides_off.png",
"jeija_insulated_wire_sides_off.png",
"jeija_insulated_wire_ends_off.png"
},
paramtype = "light",
walkable = false,
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}},
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, mesecon_conductor_craftable=1},
groups = {dig_immediate=3, mesecon=3},
mesecons = {
conductor = {
states = crossover_states,
@ -53,30 +44,18 @@ minetest.register_node("mesecons_extrawires:crossover_off", {
minetest.register_node("mesecons_extrawires:crossover_01", {
description = "You hacker you!",
drop = "mesecons_extrawires:crossover_off",
drawtype = "nodebox",
drawtype = "mesh",
mesh = "mesecons_extrawires_crossover.b3d",
tiles = {
"jeija_insulated_wire_crossing_tb_01.png",
"jeija_insulated_wire_crossing_tb_01.png",
"jeija_insulated_wire_ends_01x.png",
"jeija_insulated_wire_ends_01x.png",
"jeija_insulated_wire_ends_01z.png",
"jeija_insulated_wire_ends_01z.png"
"jeija_insulated_wire_ends_on.png",
"jeija_insulated_wire_sides_on.png",
"jeija_insulated_wire_sides_off.png",
"jeija_insulated_wire_ends_off.png"
},
paramtype = "light",
walkable = false,
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}},
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},
mesecons = {
conductor = {
@ -89,30 +68,18 @@ minetest.register_node("mesecons_extrawires:crossover_01", {
minetest.register_node("mesecons_extrawires:crossover_10", {
description = "You hacker you!",
drop = "mesecons_extrawires:crossover_off",
drawtype = "nodebox",
drawtype = "mesh",
mesh = "mesecons_extrawires_crossover.b3d",
tiles = {
"jeija_insulated_wire_crossing_tb_10.png",
"jeija_insulated_wire_crossing_tb_10.png",
"jeija_insulated_wire_ends_10x.png",
"jeija_insulated_wire_ends_10x.png",
"jeija_insulated_wire_ends_10z.png",
"jeija_insulated_wire_ends_10z.png"
"jeija_insulated_wire_ends_off.png",
"jeija_insulated_wire_sides_off.png",
"jeija_insulated_wire_sides_on.png",
"jeija_insulated_wire_ends_on.png"
},
paramtype = "light",
walkable = false,
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}},
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},
mesecons = {
conductor = {
@ -125,30 +92,18 @@ minetest.register_node("mesecons_extrawires:crossover_10", {
minetest.register_node("mesecons_extrawires:crossover_on", {
description = "You hacker you!",
drop = "mesecons_extrawires:crossover_off",
drawtype = "nodebox",
drawtype = "mesh",
mesh = "mesecons_extrawires_crossover.b3d",
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_sides_on.png",
"jeija_insulated_wire_sides_on.png",
"jeija_insulated_wire_ends_on.png"
},
paramtype = "light",
walkable = false,
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}},
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},
mesecons = {
conductor = {

@ -0,0 +1 @@
Insulated corners are conductors that only conduct between the inputs (also not up or down). When placing they always point to the left in direction of your vision.

Binary file not shown.

After

(image error) Size: 41 KiB

Binary file not shown.

After

(image error) Size: 3.8 KiB

@ -0,0 +1 @@
Insulated crossing are conductors that conduct two signals between the opposing sides, the signals are insulated to each other.

Binary file not shown.

After

(image error) Size: 61 KiB

Binary file not shown.

After

(image error) Size: 3.7 KiB

@ -0,0 +1 @@
The basic prerequesite for mesecons, can be crafted into wires and other stuff. Have a look at the <a href="http://wiki.minetest.net/Mese">Minetest Wiki</a> for more information. Mese is a conductor. It conducts in all six directions: Up/Down/Left/Right/Forward/Backward

Binary file not shown.

After

(image error) Size: 30 KiB

Binary file not shown.

After

(image error) Size: 6.1 KiB

@ -0,0 +1 @@
Insulated T-Junctions are conductors that only conduct between the inputs (also not up or down).

Binary file not shown.

After

(image error) Size: 54 KiB

Binary file not shown.

After

(image error) Size: 3.9 KiB

@ -0,0 +1 @@
Vertical Mesecons only conduct up and down. Plates appear at the ends, at that place they also conduct to the side.

Binary file not shown.

After

(image error) Size: 14 KiB

Binary file not shown.

After

(image error) Size: 3.0 KiB

@ -16,15 +16,21 @@ minetest.override_item("default:mese", {
}}
})
minetest.register_node("mesecons_extrawires:mese_powered", {
tiles = {minetest.registered_nodes["default:mese"].tiles[1].."^[brighten"},
is_ground_content = true,
groups = {cracky=1, not_in_creative_inventory = 1},
sounds = default.node_sound_stone_defaults(),
-- Copy node definition of powered mese from normal mese
-- and brighten texture tiles to indicate mese is powered
local powered_def = mesecon.mergetable(minetest.registered_nodes["default:mese"], {
drop = "default:mese",
light_source = 5,
mesecons = {conductor = {
state = mesecon.state.on,
offstate = "default:mese",
rules = mesewire_rules
}},
drop = "default:mese"
groups = {cracky = 1, not_in_creative_inventory = 1}
})
for i, v in pairs(powered_def.tiles) do
powered_def.tiles[i] = v .. "^[brighten"
end
minetest.register_node("mesecons_extrawires:mese_powered", powered_def)

Binary file not shown.

Binary file not shown.

@ -10,7 +10,7 @@ local tjunction_selectionbox = {
}
local tjunction_get_rules = function (node)
local rules =
local rules =
{{x = 0, y = 0, z = 1},
{x = 1, y = 0, z = 0},
{x = 0, y = 0, z = -1}}
@ -38,9 +38,10 @@ minetest.register_node("mesecons_extrawires:tjunction_on", {
sunlight_propagates = true,
selection_box = tjunction_selectionbox,
node_box = tjunction_nodebox,
on_rotate = mesecon.rotate_simple,
groups = {dig_immediate = 3, not_in_creative_inventory = 1},
drop = "mesecons_extrawires:tjunction_off",
mesecons = {conductor =
mesecons = {conductor =
{
state = mesecon.state.on,
rules = tjunction_get_rules,
@ -50,7 +51,7 @@ minetest.register_node("mesecons_extrawires:tjunction_on", {
minetest.register_node("mesecons_extrawires:tjunction_off", {
drawtype = "nodebox",
description = "T-junction",
description = "Insulated Mesecon T-junction",
tiles = {
"jeija_insulated_wire_tjunction_tb_off.png",
"jeija_insulated_wire_tjunction_tb_off.png^[transformR180",
@ -65,8 +66,9 @@ minetest.register_node("mesecons_extrawires:tjunction_off", {
sunlight_propagates = true,
selection_box = tjunction_selectionbox,
node_box = tjunction_nodebox,
groups = {dig_immediate = 3, mesecon_conductor_craftable=1},
mesecons = {conductor =
on_rotate = mesecon.rotate_simple,
groups = {dig_immediate = 3},
mesecons = {conductor =
{
state = mesecon.state.off,
rules = tjunction_get_rules,

@ -42,33 +42,37 @@ local vertical_updatepos = function (pos)
local node = minetest.get_node(pos)
if minetest.registered_nodes[node.name]
and minetest.registered_nodes[node.name].is_vertical_conductor then
local node_above = minetest.get_node(mesecon.addPosRule(pos, vertical_rules[1]))
local node_below = minetest.get_node(mesecon.addPosRule(pos, vertical_rules[2]))
local namestate = minetest.registered_nodes[node.name].vertical_conductor_state
local node_above = minetest.get_node(vector.add(pos, vertical_rules[1]))
local node_below = minetest.get_node(vector.add(pos, vertical_rules[2]))
local above = minetest.registered_nodes[node_above.name]
and minetest.registered_nodes[node_above.name].is_vertical_conductor
local below = minetest.registered_nodes[node_below.name]
and minetest.registered_nodes[node_below.name].is_vertical_conductor
local basename = "mesecons_extrawires:vertical_"
mesecon.on_dignode(pos, node)
-- Always place offstate conductor and let mesecon.on_placenode take care
local newname = "mesecons_extrawires:vertical_"
if above and below then -- above and below: vertical mesecon
minetest.add_node(pos, {name = basename .. namestate})
newname = newname .. "off"
elseif above and not below then -- above only: bottom
minetest.add_node(pos, {name = basename .. "bottom_" .. namestate})
newname = newname .. "bottom_off"
elseif not above and below then -- below only: top
minetest.add_node(pos, {name = basename .. "top_" .. namestate})
newname = newname .. "top_off"
else -- no vertical wire above, no vertical wire below: use bottom
minetest.add_node(pos, {name = basename .. "bottom_" .. namestate})
newname = newname .. "bottom_off"
end
mesecon.update_autoconnect(pos)
minetest.set_node(pos, {name = newname})
mesecon.on_placenode(pos, {name = newname})
end
end
local vertical_update = function (pos, node)
vertical_updatepos(pos) -- this one
vertical_updatepos(mesecon.addPosRule(pos, vertical_rules[1])) -- above
vertical_updatepos(mesecon.addPosRule(pos, vertical_rules[2])) -- below
vertical_updatepos(vector.add(pos, vertical_rules[1])) -- above
vertical_updatepos(vector.add(pos, vertical_rules[2])) -- below
end
-- Vertical wire
@ -80,6 +84,7 @@ mesecon.register_node("mesecons_extrawires:vertical", {
sunlight_propagates = true,
selection_box = vertical_box,
node_box = vertical_box,
on_rotate = false,
is_vertical_conductor = true,
drop = "mesecons_extrawires:vertical_off",
after_place_node = vertical_update,
@ -87,7 +92,6 @@ mesecon.register_node("mesecons_extrawires:vertical", {
},{
tiles = {"mesecons_wire_off.png"},
groups = {dig_immediate=3},
vertical_conductor_state = "off",
mesecons = {conductor = {
state = mesecon.state.off,
onstate = "mesecons_extrawires:vertical_on",
@ -96,7 +100,6 @@ mesecon.register_node("mesecons_extrawires:vertical", {
},{
tiles = {"mesecons_wire_on.png"},
groups = {dig_immediate=3, not_in_creative_inventory=1},
vertical_conductor_state = "on",
mesecons = {conductor = {
state = mesecon.state.on,
offstate = "mesecons_extrawires:vertical_off",
@ -114,13 +117,13 @@ mesecon.register_node("mesecons_extrawires:vertical_top", {
groups = {dig_immediate=3, not_in_creative_inventory=1},
selection_box = top_box,
node_box = top_box,
on_rotate = false,
is_vertical_conductor = true,
drop = "mesecons_extrawires:vertical_off",
after_place_node = vertical_update,
after_dig_node = vertical_update
},{
tiles = {"mesecons_wire_off.png"},
vertical_conductor_state = "off",
mesecons = {conductor = {
state = mesecon.state.off,
onstate = "mesecons_extrawires:vertical_top_on",
@ -128,7 +131,6 @@ mesecon.register_node("mesecons_extrawires:vertical_top", {
}}
},{
tiles = {"mesecons_wire_on.png"},
vertical_conductor_state = "on",
mesecons = {conductor = {
state = mesecon.state.on,
offstate = "mesecons_extrawires:vertical_top_off",
@ -146,13 +148,13 @@ mesecon.register_node("mesecons_extrawires:vertical_bottom", {
groups = {dig_immediate = 3, not_in_creative_inventory = 1},
selection_box = bottom_box,
node_box = bottom_box,
on_rotate = false,
is_vertical_conductor = true,
drop = "mesecons_extrawires:vertical_off",
after_place_node = vertical_update,
after_dig_node = vertical_update
},{
tiles = {"mesecons_wire_off.png"},
vertical_conductor_state = "off",
mesecons = {conductor = {
state = mesecon.state.off,
onstate = "mesecons_extrawires:vertical_bottom_on",
@ -160,7 +162,6 @@ mesecon.register_node("mesecons_extrawires:vertical_bottom", {
}}
},{
tiles = {"mesecons_wire_on.png"},
vertical_conductor_state = "on",
mesecons = {conductor = {
state = mesecon.state.on,
offstate = "mesecons_extrawires:vertical_bottom_off",

@ -0,0 +1 @@
mesecons

@ -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

(image error) Size: 21 KiB

Binary file not shown.

After

(image error) Size: 3.1 KiB

@ -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

(image error) Size: 598 B

Binary file not shown.

After

(image error) Size: 1.9 KiB

375
mesecons_fpga/init.lua Normal file

@ -0,0 +1,375 @@
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
sunlight_propagates = true,
paramtype = "light",
walkable = true,
groups = {dig_immediate = 2, mesecon = 3},
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,
})
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
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

@ -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

(image error) Size: 311 B

Binary file not shown.

After

(image error) Size: 536 B

Binary file not shown.

After

(image error) Size: 816 B

62
mesecons_fpga/tool.lua Normal 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

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

Binary file not shown.

After

(image error) Size: 68 KiB

Binary file not shown.

After

(image error) Size: 2.7 KiB

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

Binary file not shown.

After

(image error) Size: 71 KiB

Binary file not shown.

After

(image error) Size: 2.0 KiB

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

Binary file not shown.

After

(image error) Size: 62 KiB

Binary file not shown.

After

(image error) Size: 2.7 KiB

@ -0,0 +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.

Binary file not shown.

After

(image error) Size: 26 KiB

Binary file not shown.

After

(image error) Size: 2.4 KiB

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

Binary file not shown.

After

(image error) Size: 69 KiB

Binary file not shown.

After

(image error) Size: 2.0 KiB

@ -0,0 +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.

Binary file not shown.

After

(image error) Size: 26 KiB

Binary file not shown.

After

(image error) Size: 2.4 KiB

@ -0,0 +1 @@
XOR gates power their output if only one input is powered, they're off if either both or none of the inputs is powered.

Binary file not shown.

After

(image error) Size: 69 KiB

Binary file not shown.

After

(image error) Size: 2.6 KiB

@ -54,7 +54,7 @@ local function update_gate(pos, node, link, newstate)
end
end
function register_gate(name, inputnumber, assess, recipe)
local function register_gate(name, inputnumber, assess, recipe)
local get_inputrules = inputnumber == 2 and gate_get_input_rules_twoinputs or
gate_get_input_rules_oneinput
local description = "Mesecons Logic Gate: "..name
@ -122,3 +122,13 @@ register_gate("xor", 2, function (val1, val2) return (val1 or val2) and not (val
{{"mesecons:mesecon", "", ""},
{"", "mesecons_materials:silicon", "mesecons_materials:silicon"},
{"mesecons:mesecon", "", ""}})
register_gate("nor", 2, function (val1, val2) return not (val1 or val2) end,
{{"mesecons:mesecon", "", ""},
{"", "mesecons:mesecon", "mesecons_torch:mesecon_torch_on"},
{"mesecons:mesecon", "", ""}})
register_gate("or", 2, function (val1, val2) return (val1 or val2) end,
{{"mesecons:mesecon", "", ""},
{"", "mesecons:mesecon", "mesecons:mesecon"},
{"mesecons:mesecon", "", ""}})

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