diff --git a/Bucket_Game-base/remove_io_and_os-vs-bg220909/mods/LICENSE b/Bucket_Game-base/remove_io_and_os-vs-bg220909/mods/LICENSE new file mode 100644 index 0000000..4ebf695 --- /dev/null +++ b/Bucket_Game-base/remove_io_and_os-vs-bg220909/mods/LICENSE @@ -0,0 +1,12 @@ +For license information, see the following files, where they exist, in +each modpack or mod: + + oldcoder.txt + LICENSE + LICENSE.txt + license.txt + README.md + README.txt + readme.txt + +and/or files with similar names. diff --git a/Bucket_Game-base/remove_io_and_os-vs-bg220909/mods/codercore/coderskins/LICENSE b/Bucket_Game-base/remove_io_and_os-vs-bg220909/mods/codercore/coderskins/LICENSE new file mode 100644 index 0000000..d591b92 --- /dev/null +++ b/Bucket_Game-base/remove_io_and_os-vs-bg220909/mods/codercore/coderskins/LICENSE @@ -0,0 +1,42 @@ +Name: coderskins +Source: Original mod + +License: (c) 2019 and CC BY-NC-SA 4.0 International: OldCoder (Robert +Kiraly). + +---------------------------------------------------------------------- + +"coderskins" is a Minetest "skins" mod that is designed to work with +the Bucket World "_game" or derived "_games". It won't work in other +contexts. + +This mod is inspired by older Minetest "skins" mods, but is suffi- +ciently different that it should be viewed as a new mod. + +---------------------------------------------------------------------- + +The mod supports 64x64 skins and, additionally, sets random default +skins for new players. + +To install a specific skin for a specific player, name the PNG file +to be used as follows: + + player_NAME.png + +where NAME is the player's in-game nick. Then copy the PNG file into +the mod's "textures" directory. + +The PNG file should be a standard Minetest 64x32 or Minecraft 64x64 +"skin" file. + +Or, if you prefer, create a text file, in the mod's "textures" direc- +tory with a similar filename: + + player_NAME.skin + +In the text file, put the filename of the PNG file to be used for the +associated player's skin. The PNG file should be stored in the same +directory. + +If a "player_NAME.png" file and a "player_NAME.skin" file are both +present for a particular player, the PNG file takes precedence. diff --git a/Bucket_Game-base/remove_io_and_os-vs-bg220909/mods/codercore/coderskins/oldcoder.txt b/Bucket_Game-base/remove_io_and_os-vs-bg220909/mods/codercore/coderskins/oldcoder.txt new file mode 100644 index 0000000..57a8d47 --- /dev/null +++ b/Bucket_Game-base/remove_io_and_os-vs-bg220909/mods/codercore/coderskins/oldcoder.txt @@ -0,0 +1,207 @@ +Name: coderskins +Source: Largely original mod +License: See notes in "oldcoder.txt" + +---------------------------------------------------------------------- + +1. Overview. + +"CoderSkins" is a Minetest "skins" mod that is designed to work with +the Bucket World "_game" or derived "_games". It won't work in other +contexts. + +The mod is largely original, but includes Unified Inventory support +code from other mods. + +The Unified Inventory support code is based on GPL3 code that is (c) +2012 CoRNeRNoTe and Dean Montgomery. + +As this module incorporates GPL3 code, the code as a whole is GPL3. +However, the rest of the code is (c) 2017-2020 OldCoder (Robert Kira- +ly). + +If individual media files, i.e., skin textures, included with the mod +are discovered to be incompatible with GPL3, the files in question +should be removed. + +---------------------------------------------------------------------- + +2. CoderSkins features. + +2.1. CoderSkins supports both 64x64 Minecraft (tm) skins and 64x32 +Minetest skins. + +It's compatible, despite the use of 64x64, with the Bucket Game ver- +sion of 3D Armor. + +As of 2020, old MT skin systems only support 64x32. CoderSkins is be- +lieved to be the only one that supports 64x64 (and that works with +a patched 3D Armor as well). + +2.2. The world owner can install skins for individual players manual- +ly. Or builders can choose their own skins using U.I. GUI screens. Or +both. + +2.3. The world owner can set the order of skins displayed in the GUI. + +2.4. By default, the main CoderSkins U.I. page displays a short 1-line +description of the player's current skin based on the associated PNG- +file name. + +The world owner can specify a 2nd line. Additionally, he/she can over- +ride the default for the 1st line. + +2.5. New players get random gender-neutral skins by default. + +2.6. CoderSkins adds extra navigation buttons to the GUI. + +The extra buttons include first page, last page, and -- if there are +6 or more pages -- 2 more buttons that jump to 1/3 and 2/3 of the way +through the page list. + +2.7. CoderSkins fixes a bug in the old U.I. code related to the +"Change" button. + +Specifically, the "Change" button now takes you to the last "skins" +screen that you visited in the current session. The old version al- +ways took you to the first page. + +2.8. Minor feature: The U.I. GUI includes a tooltip. "u_skins" and/or +other old skin mods seem to be missing this feature. + +2.9. CoderSkins supports its own spacesuits, NC virus masks, and 3D +armor. + +The spacesuits and NC virus masks are functional. 3D armor is still +under development. + +Documentation for these features will be added here. + +---------------------------------------------------------------------- + +3. CoderSkins limitations. + +3.1. CoderSkins requires Bucket Game. + +3.2. While 3D Armor, the old mod as opposed to the new CoderSkins fea- +ture, is being worn, 64x64 skins will drop the level of detail dis- +played down to the 64x32 level. + +3.3. 2D sprite skins aren't supported. + +---------------------------------------------------------------------- + +4. Adding new skins. + +Players will usually select their skins from the set that comes with +the mod. + +To do this, they'll use Unified Inventory. There's a button for the +purpose in the U.I. "buttons" row. + +The in-game command "/skin" can also be used to change skins. + +If you're a world host, the mod allows you to add skins and/or change +them for players in multiple ways: + +4.1. You can add a new PNG file just for one player. + +This procedure, 4.1, is discussed in Appendix A. Most experienced +world hosts should be able to do it. + +4.2. You can use the in-game command "/pskin" to set the skin for a +player who is too inexperienced to set his or her own skin. + +4.3. You can add new skins to the CoderSkins GUI. This procedure, 4.3, +is discussed in Appendix B. + +---------------------------------------------------------------------- + +5. Changing skin display order. + +CoderSkins includes a Lua file named "skinlist.lua". The file defines +a table named "coderskins.list". + +The CoderSkins GUI displays predefined skins in the order that the ta- +ble lists them. + +To change the order in which the GUI displays skins, edit "skinlist. +lua" and change the order of the entries in the table. + +---------------------------------------------------------------------- + +Appendix A. Adding a PNG file just for one player. + +The world owner can add a specific skin just for a specific player. +If this is done, the new skin won't appear in the list of skin options +for other players. + +This procedure bypasses the "skins" GUI in Unified Inventory. + +To do this, proceed as follows: + +A.1. Start with a PNG file that contains a valid MC or MT skin. It can +be either 64x64 or 64x32. + +A.2. Rename the PNG file to a filename of the following form: + + player_NAME.png + +NAME should be the player's in-game nickname. For example, if the +player uses the nickname "Salad", the name of the PNG file should +be: + player_Salad.png + +Limitation: If the player's nickname contains unusual characters, you +may not be able to do this. + +A.3. Copy the renamed PNG file into the mod's "textures" directory. + +A.4. Restart the world. + +---------------------------------------------------------------------- + +Appendix B. Adding new public skins. + +A world host can add local skins. + +B.1. A local skin is a PNG file with a name of the form "skin_MeowCat. +png" or "skin_PizzaWolf.png". + +CoderSkins supports both standard 64x64 and 64x32 Minecraft (tm) skin +formats. + +B.2. To add a local skin, drop appropriate PNG files, with names of +the form "skin_*.png", into the "textures" directory. + +If this is done, the GUI will display local skins first. The local +skins will be displayed in alpha betical order based on filename. + +B.3. To disable support for local skins, add the following setting +to "world.conf": + + local_skins = false + +B.4. The CoderSkins GUI displays a front and back preview image for +each skin. For this to work, two additional PNG files must be present +in addition to a given skin PNG file. + +The two preview PNG files should have filenames of the form: + + skin_PizzaWolf_preview.png + skin_PizzaWolf_preview_back.png + +In other words, for the front preview, take the original skin-file +name and insert "_preview" right before ".png". For the back preview, +insert "_preview_back" instead. + +The preview image files should be 16x32 images that display the assoc- +iated skin as it looks from the front and the back, respectively. + +CoderSkins doesn't presently provide a tool to generate previews. A +tool of this type may be added in the future. + +If skin preview files are omitted, "not available" images will be dis- +played instead. + +(end of document) diff --git a/Bucket_Game-base/remove_io_and_os-vs-bg220909/mods/codercore/coderskins/skinlist.lua b/Bucket_Game-base/remove_io_and_os-vs-bg220909/mods/codercore/coderskins/skinlist.lua new file mode 100644 index 0000000..f073064 --- /dev/null +++ b/Bucket_Game-base/remove_io_and_os-vs-bg220909/mods/codercore/coderskins/skinlist.lua @@ -0,0 +1,332 @@ +coderskins.desc1 = {} +coderskins.desc2 = {} + +-- =================================================================== + +coderskins.desc2 ["skin_Actual_Cat" ] = "How Now Meow Wow" +coderskins.desc2 ["skin_Apple_Tree" ] = "Apple a Day Hooray" +coderskins.desc2 ["skin_Patience" ] = "Patience leads to focus" + +-- =================================================================== + +coderskins.list = { + + "skin_Chinese_Off_White" , + "skin_Corona" , + "skin_Mumbo_Jumbo" , + "skin_RedMinionToby" , + "skin_SAF_Army1" , + "skin_SAF_Army3G" , + "skin_Hope" , + "skin_Jessa_PJs" , + + "skin_09SharkBoy" , + "skin_Unspeakable" , + "skin_LDShadow_Lady" , + "skin_Steve_Watch" , + "skin_Business_Kermit" , + "skin_Stampy_Boots" , + "skin_iBallistic_Squid" , + "skin_MooseCraft" , + "sscharacter_120" , + + "skin_Actual_Cat" , + "skin_Apple_Tree" , + "skin_Black_Panther" , + "skin_Farmer_Green" , + "skin_Patience" , + "skin_Bear" , + "skin_Hotdog" , + "skin_Robocop" , + "skin_Capt_America" , + "skin_Queen_Elsa" , + "skin_Cola" , + "skin_Santa" , + "skin_Tiger" , + "skin_Cool_Panda" , + + "skin_Athena" , + "skin_Brianna_Playz" , + "skin_Chad_Wild_Clay" , + "skin_Chara" , + "skin_Duck" , + "skin_Kata_Red_Hair" , + "skin_Potion_Master" , + "skin_Preston_Playz" , + + "skin_Batman" , + "skin_Battery" , + "skin_Bear_Overalls" , + "skin_Bearded_Wizard" , + "skin_Alejo_Facheraso" , + "skin_Bee" , + "skin_Capt_Blue_Sparrow" , + "skin_Doraemon" , + "skin_Green_Boy" , + + "skin_Grey_Dog" , + "skin_Hispanic_Napoleon" , + "skin_King_Turtle" , + "skin_Krypto" , + "skin_Pink_Tiger" , + "skin_Recon_Expert" , + "skin_Big_Bird" , + "skin_Gold_Cylon" , + "skin_Gold_Knight" , + "skin_Leo" , + "skin_Wonder_Woman" , + "skin_Mr_Spock" , + "skin_Regular_Cylon" , + "skin_Rosalyn_Potion_Master" , + "skin_Red_Wolf_Boy" , + "skin_Rosa" , + "skin_Shovel_Knight" , + "skin_Wonder_Boy" , + "skin_Boy_Red_Hoodie" , + "skin_Boy_Water_Jacket" , + "skin_Fire_Enderman" , + "skin_Fox" , + "skin_Gamer_Guy" , + "skin_Girl_Casual" , + "skin_Good_Witch" , + "skin_Green_Claus_Wizard" , + "skin_Heather_Elf" , + "skin_Hobbit" , + "skin_Jane_Foster" , + "skin_Kyle_Rayner" , + "skin_Lego_Person" , + "skin_Lego_Spaceman" , + "skin_Link" , + "skin_Luigi" , + "skin_Mario" , + "skin_Marley_Xia" , + "skin_Mutant_Fox" , + "skin_Owl" , + "skin_Pachilo155" , + "skin_Pie" , + "skin_Pizza_Girl" , + "skin_Polar_Bear" , + "skin_Purple_Outfit" , + "skin_Purple_Princess" , + "skin_Quackin_Hood" , + "skin_Rabbit" , + "skin_Rabbit_Coco" , + "skin_Rainboots" , + "skin_Squirrel" , + "skin_Stampy" , + "skin_Steampunk" , + "skin_Super_Jack" , + "skin_Supercow" , + "skin_Superpollo" , + "skin_Thanatos" , + "skin_Trainer_Red" , + "skin_Wafleman" , + "skin_White_Bear" , + "skin_White_Dress" , + "skin_Puppy" , + "skin_Bakugo" , + + "sdskin_Blue_Girl" , + "sdskin_Calinou" , + "sdskin_Son_Goku" , + "sdskin_StormChaser_30000" , + "sdskin_oOChainLynxOo" , + "sdskin_sdzen" , + + "sscharacter_1" , + "sscharacter_100" , + "sscharacter_101" , + "sscharacter_102" , + "sscharacter_103" , + "sscharacter_106" , + "sscharacter_107" , + "sscharacter_108" , + "sscharacter_109" , + "sscharacter_110" , + "sscharacter_111" , + "sscharacter_113" , + "sscharacter_114" , + "sscharacter_116" , + "sscharacter_118" , + "sscharacter_119" , + "sscharacter_121" , + "sscharacter_122" , + "sscharacter_123" , + "sscharacter_126" , + "sscharacter_129" , + "sscharacter_13" , + "sscharacter_132" , + "sscharacter_133" , + "sscharacter_134" , + "sscharacter_135" , + "sscharacter_136" , + "sscharacter_14" , + "sscharacter_140" , + "sscharacter_141" , + "sscharacter_142" , + "sscharacter_143" , + "sscharacter_146" , + "sscharacter_148" , + "sscharacter_149" , + "sscharacter_15" , + "sscharacter_150" , + "sscharacter_151" , + "sscharacter_152" , + "sscharacter_16" , + "sscharacter_2" , + "sscharacter_20" , + "sscharacter_21" , + "sscharacter_22" , + "sscharacter_23" , + "sscharacter_24" , + "sscharacter_25" , + "sscharacter_26" , + "sscharacter_28" , + "sscharacter_30" , + "sscharacter_32" , + "sscharacter_33" , + "sscharacter_47" , + "sscharacter_51" , + "sscharacter_56" , + "sscharacter_57" , + "sscharacter_59" , + "sscharacter_6" , + "sscharacter_64" , + "sscharacter_66" , + "sscharacter_70" , + "sscharacter_71" , + "sscharacter_73" , + "sscharacter_75" , + "sscharacter_78" , + "sscharacter_80" , + "sscharacter_81" , + "sscharacter_83" , + "sscharacter_84" , + "sscharacter_85" , + "sscharacter_90" , + "sscharacter_99" , + "uskins_1" , + "uskins_10" , + "uskins_11" , + "uskins_12" , + "uskins_13" , + "uskins_14" , + "uskins_16" , + "uskins_17" , + "uskins_18" , + "uskins_19" , + "uskins_2" , + "uskins_20" , + "uskins_21" , + "uskins_22" , + "uskins_23" , + "uskins_25" , + "uskins_26" , + "uskins_27" , + "uskins_28" , + "uskins_29" , + "uskins_3" , + "uskins_30" , + "uskins_31" , + "uskins_32" , + "uskins_33" , + "uskins_34" , + "uskins_35" , + "uskins_36" , + "uskins_37" , + "uskins_38" , + "uskins_39" , + "uskins_4" , + "uskins_40" , + "uskins_41" , + "uskins_45" , + "uskins_46" , + "uskins_47" , + "uskins_48" , + "uskins_5" , + "uskins_50" , + "uskins_51" , + "uskins_52" , + "uskins_53" , + "uskins_54" , + "uskins_55" , + "uskins_56" , + "uskins_58" , + "uskins_59" , + "uskins_6" , + "uskins_60" , + "uskins_61" , + "uskins_62" , + "uskins_63" , + "uskins_64" , + "uskins_65" , + "uskins_66" , + "uskins_68" , + "uskins_69" , + "uskins_70" , + "uskins_71" , + "uskins_72" , + "uskins_73" , + "uskins_74" , + "uskins_75" , + "uskins_77" , + "uskins_79" , + "uskins_8" , + "uskins_80" , + "uskins_81" , + "uskins_82" , + "uskins_83" , + "uskins_84" , + "uskins_85" , + "uskins_86" , + "uskins_87" , + "uskins_88" , + "uskins_89" , + "uskins_9" , + "uskins_90" , + "uskins_91" , + "uskins_92" , + "uskins_93" , + "uskins_94" , + "uskins_95" , + "uskins_96" , + "uskins_97" , + "uskins_98" , + "uskins_99" , + "uskins_103" , +} + +-- =================================================================== +-- Add local skins. + +if ocutil.bool_setting ("local_skins", true) then + + local ktable = ocutil.vtable_to_ktable (coderskins.list) + local dir = coderskins.textdir + local popen = io.popen + local newlist = {} + local ofname, dfname + + for ofname in popen ('ls "' .. dir .. '"skin_*.png'):lines() + do + ofname = ofname:gsub (".*/" , "") + ofname = ofname:gsub ("%.png$" , "") + dfname = ofname:gsub ("_preview.*$" , "") + + if dfname == ofname and ktable [dfname] == nil then + ktable [dfname] = true + table.insert (newlist, dfname) + end + end + + for _, dfname in ipairs (coderskins.list) do + table.insert (newlist, dfname) + end + + coderskins.list = newlist + ktable = {} + newlist = {} +end + +-- =================================================================== +-- End of file. diff --git a/Bucket_Game-base/remove_io_and_os-vs-bg220909/mods/coderedit/LICENSE.txt b/Bucket_Game-base/remove_io_and_os-vs-bg220909/mods/coderedit/LICENSE.txt new file mode 100644 index 0000000..dba13ed --- /dev/null +++ b/Bucket_Game-base/remove_io_and_os-vs-bg220909/mods/coderedit/LICENSE.txt @@ -0,0 +1,661 @@ + GNU AFFERO GENERAL PUBLIC LICENSE + Version 3, 19 November 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU Affero General Public License is a free, copyleft license for +software and other kinds of works, specifically designed to ensure +cooperation with the community in the case of network server software. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +our General Public Licenses are intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + Developers that use our General Public Licenses protect your rights +with two steps: (1) assert copyright on the software, and (2) offer +you this License which gives you legal permission to copy, distribute +and/or modify the software. + + A secondary benefit of defending all users' freedom is that +improvements made in alternate versions of the program, if they +receive widespread use, become available for other developers to +incorporate. Many developers of free software are heartened and +encouraged by the resulting cooperation. However, in the case of +software used on network servers, this result may fail to come about. +The GNU General Public License permits making a modified version and +letting the public access it on a server without ever releasing its +source code to the public. + + The GNU Affero General Public License is designed specifically to +ensure that, in such cases, the modified source code becomes available +to the community. It requires the operator of a network server to +provide the source code of the modified version running there to the +users of that server. Therefore, public use of a modified version, on +a publicly accessible server, gives the public access to the source +code of the modified version. + + An older license, called the Affero General Public License and +published by Affero, was designed to accomplish similar goals. This is +a different license, not a version of the Affero GPL, but Affero has +released a new version of the Affero GPL which permits relicensing under +this license. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU Affero General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Remote Network Interaction; Use with the GNU General Public License. + + Notwithstanding any other provision of this License, if you modify the +Program, your modified version must prominently offer all users +interacting with it remotely through a computer network (if your version +supports such interaction) an opportunity to receive the Corresponding +Source of your version by providing access to the Corresponding Source +from a network server at no charge, through some standard or customary +means of facilitating copying of software. This Corresponding Source +shall include the Corresponding Source for any work covered by version 3 +of the GNU General Public License that is incorporated pursuant to the +following paragraph. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the work with which it is combined will remain governed by version +3 of the GNU General Public License. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU Affero General Public License from time to time. Such new versions +will be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU Affero General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU Affero General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU Affero General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program 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 Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If your software can interact with users remotely through a computer +network, you should also make sure that it provides a way for users to +get its source. For example, if your program is a web application, its +interface could display a "Source" link that leads users to an archive +of the code. There are many ways you could offer source, and different +solutions will be better for different programs; see section 13 for the +specific requirements. + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU AGPL, see +. diff --git a/Bucket_Game-base/remove_io_and_os-vs-bg220909/mods/coderedit/oldcoder.txt b/Bucket_Game-base/remove_io_and_os-vs-bg220909/mods/coderedit/oldcoder.txt new file mode 100644 index 0000000..dce32f5 --- /dev/null +++ b/Bucket_Game-base/remove_io_and_os-vs-bg220909/mods/coderedit/oldcoder.txt @@ -0,0 +1,16 @@ +Name: worldedit +Source: Fork of upstream modpack (do not replace) +License: See "LICENSE.txt" + +---------------------------------------------------------------------- + +This is a fork of the Minetest "worldedit" modpack that includes sig- +nificant changes. + +This modpack should not be replaced or updated except to future re- +leases of the Bucket World "_game" series. + +The "brush" component has been removed, at least temporarily, for the +sake of backwards compatibility. + +To be added: Descriptions of new commands and/or features. diff --git a/Bucket_Game-base/remove_io_and_os-vs-bg220909/mods/coderedit/worldedit/manipulations.lua b/Bucket_Game-base/remove_io_and_os-vs-bg220909/mods/coderedit/worldedit/manipulations.lua new file mode 100644 index 0000000..04ce7ee --- /dev/null +++ b/Bucket_Game-base/remove_io_and_os-vs-bg220909/mods/coderedit/worldedit/manipulations.lua @@ -0,0 +1,1468 @@ +-- Generic node manipulations +-- @module worldedit.manipulations + +require "os" + +-- =================================================================== + +local coderedit_debug = + minetest.setting_get ("coderedit_debug" ) + +local coderedit_disable_verbose = + minetest.setting_get ("coderedit_disable_verbose" ) or + minetest.setting_get ("disable_coderedit_verbose" ) + +local coderedit_noqueue = + minetest.setting_get ("coderedit_noqueue" ) + +-- =================================================================== + +local mh = worldedit.manip_helpers + +-- Sets a region to `node_names` +-- @param pos1 +-- @param pos2 +-- @param node_names Node name or list of node names. +-- @return The number of nodes set. + +-- =================================================================== + +worldedit.cmd_queue = {} +worldedit.emerge_busy = 0 +worldedit.use_queue = 1 + +if coderedit_noqueue then worldedit.use_queue = 0 end + +-- =================================================================== + +local function idiv (a, b) + return (a - (a % b)) / b +end + +-- =================================================================== + +local function sort2num (a, b) + if a > b then return b, a end + return a, b +end + +-- =================================================================== + +local function deblog (str) + if coderedit_debug then + ocutil.log ("[we] " .. str) + end +end + +-- =================================================================== + +function worldedit.toggle_queue() + if worldedit.use_queue == 0 then + worldedit.use_queue = 1 + minetest.chat_send_all ("CoderEdit commands are queued" ) + else + worldedit.use_queue = 0 + minetest.chat_send_all ("CoderEdit commands are not queued" ) + end +end + +-- =================================================================== + +local function end_of_start_emerge (pos1, pos2, mode) + + if collectgarbage ("count") > 307200 then collectgarbage() end + deblog ("emerge started") + + if not coderedit_disable_verbose then + minetest.chat_send_all ("Volume may print immediately," .. + " but we're not done") + minetest.chat_send_all ("Wait for DONE message") + minetest.chat_send_all ("This may take 5 to 45 minutes" .. + " for large schems") + end + + return worldedit.volume (pos1, pos2) +end + +-- =================================================================== + +local function end_of_emerge (mode) + + if collectgarbage ("count") > 307200 then collectgarbage() end + minetest.chat_send_all ("*** " .. mode .." DONE ***") + deblog ("emerge done") + + worldedit.emerge_busy = 0 + worldedit.place_base = nil + worldedit.place_both = nil + worldedit.place_name = nil + worldedit.place_path = nil + worldedit.place_pos = nil +end + +-- =================================================================== + +local function emerge_callback_copy (blockpos, action, numleft, param) + + if collectgarbage ("count") > 307200 then collectgarbage() end + if numleft ~= 0 then return end + + local pos1 = param.pos1 + local pos2 = param.pos2 + local axis = param.axis + local amount = param.amount + local overlap = param.overlap + + local newpos1 = { x=pos1.x, y=pos1.y, z=pos1.z } + local newpos2 = { x=pos2.x, y=pos2.y, z=pos2.z } + + newpos1 [axis] = newpos1 [axis] + amount + newpos2 [axis] = newpos2 [axis] + amount + + if overlap then + if not coderedit_disable_verbose then + minetest.chat_send_all ("Emerge done, skipping" .. + " set air due to overlap") + minetest.chat_send_all ("Dark areas may result." .. + " Starting actual copy.") + end + else + if not coderedit_disable_verbose then + minetest.chat_send_all ("Emerge done, starting set air") + end + + deblog ("copy callback: set to air start" ) + worldedit.old_set (newpos1, newpos2, "air") + deblog ("copy callback: set to air done" ) + + if not coderedit_disable_verbose then + minetest.chat_send_all ("Set air done, starting" .. + " actual copy") + end + end + + deblog ("copy callback: actual copy start" ) + worldedit.old_copy (pos1, pos2, axis, amount) + deblog ("copy callback: actual copy done" ) + + end_of_emerge ("COPY") +end + +-- =================================================================== + +local function emerge_callback_move (blockpos, action, numleft, param) + + if collectgarbage ("count") > 307200 then collectgarbage() end + if numleft ~= 0 then return end + + local pos1 = param.pos1 + local pos2 = param.pos2 + local axis = param.axis + local amount = param.amount + local overlap = param.overlap + + local newpos1 = { x=pos1.x, y=pos1.y, z=pos1.z } + local newpos2 = { x=pos2.x, y=pos2.y, z=pos2.z } + + newpos1 [axis] = newpos1 [axis] + amount + newpos2 [axis] = newpos2 [axis] + amount + + if overlap then + if not coderedit_disable_verbose then + minetest.chat_send_all ("Emerge done, skipping" .. + " set air due to overlap") + minetest.chat_send_all ("Dark areas may result." .. + " Starting actual move.") + end + else + if not coderedit_disable_verbose then + minetest.chat_send_all ("Emerge done, starting set air") + end + + deblog ("move callback: set to air start" ) + worldedit.old_set (newpos1, newpos2, "air") + deblog ("move callback: set to air done" ) + + if not coderedit_disable_verbose then + minetest.chat_send_all ("Set air done, starting" .. + " actual move") + end + end + + deblog ("move callback: actual move start" ) + worldedit.old_move (pos1, pos2, axis, amount) + deblog ("move callback: actual move done" ) + + end_of_emerge ("MOVE") +end + +-- =================================================================== + +local function emerge_callback_emerge (blockpos, action, + numleft, param) + + if collectgarbage ("count") > 307200 then collectgarbage() end + if numleft ~= 0 then return end + end_of_emerge ("EMERGE") +end + +-- =================================================================== + +local function emerge_callback_set (blockpos, action, numleft, param) + + if false and (numleft % 8192) == 0 then + ocutil.log ("emerge left: " .. numleft) + end + if numleft ~= 0 then return end + + if not coderedit_disable_verbose then + minetest.chat_send_all ("Emerge done, starting actual set") + end + + if type (param.node_names) ~= "string" or + param.node_names ~= "default:emerge" then + worldedit.old_set (param.pos1, + param.pos2, param.node_names) + end + + local pbase = worldedit.place_base + local pboth = worldedit.place_both + local pname = worldedit.place_name + local ppos = worldedit.place_pos + local ppath = worldedit.place_path + + if (ppos ~= nil) and (ppath ~= nil) then + if not coderedit_disable_verbose then + minetest.chat_send_all ("Set done, starting actual place") + end + + if minetest.place_schematic (ppos, ppath) == nil then + minetest.chat_send_all ("Failed to place MTS", false) + else + local ps = minetest.pos_to_string (ppos) + minetest.chat_send_all ("Placed MTS at " .. ps, false) + + if (pname ~= nil) and (pbase ~= nil) and + (pboth ~= nil) and pboth then + worldedit.loadwe (pname, pbase) + minetest.chat_send_all ("Placed WE at " .. ps, false) + end + end + end + + end_of_emerge ("SET or PLACE") +end + +-- =================================================================== + +-- Copies a region along `axis` by `amount` nodes. +-- @param pos1 +-- @param pos2 +-- @param axis Axis ("x", "y", or "z") +-- @param amount +-- @return The number of nodes copied. + +function worldedit.old_copy (xpos1, xpos2, axis, amount) + + local pos1, pos2 = worldedit.sort_pos (xpos1, xpos2) + worldedit.keep_loaded (pos1, pos2) + + local get_node, get_meta, set_node = minetest.get_node, + minetest.get_meta, minetest.set_node + -- Copy things backwards when negative to avoid corruption. + -- FIXME: Lots of code duplication here. + + if amount < 0 then + local pos = {} + pos.x = pos1.x + + while pos.x <= pos2.x do + pos.y = pos1.y + + while pos.y <= pos2.y do + pos.z = pos1.z + + while pos.z <= pos2.z do + + -- Obtain current node + local node = get_node (pos) + + -- Get meta of current node + local meta = get_meta (pos):to_table() + + -- Store current position + local value = pos [axis] + + -- Move along axis + pos[axis] = value + amount + + -- Copy node to new position + set_node (pos, node) + + -- Set metadata of new node + get_meta (pos):from_table (meta) + + -- Restore old position + pos [axis] = value + + pos.z = pos.z + 1 + end + + pos.y = pos.y + 1 + end + + pos.x = pos.x + 1 + end + else + local pos = {} + pos.x = pos2.x + + while pos.x >= pos1.x do + pos.y = pos2.y + + while pos.y >= pos1.y do + pos.z = pos2.z + + while pos.z >= pos1.z do + + -- Obtain current node + local node = get_node (pos) + + -- Get meta of current node + local meta = get_meta (pos):to_table() + + -- Store current position + local value = pos [axis] + + -- Move along axis + pos[axis] = value + amount + + -- Copy node to new position + set_node (pos, node) + + -- Set metadata of new node + get_meta (pos):from_table (meta) + + -- Restore old position + pos [axis] = value + + pos.z = pos.z - 1 + end + + pos.y = pos.y - 1 + end + + pos.x = pos.x - 1 + end + end + + return worldedit.volume (pos1, pos2) +end + +-- =================================================================== + +function worldedit.wait_copy (p) + worldedit.copy (p.xpos1, p.xpos2, p.axis, p.amount) + return 0 +end + +function worldedit.wait_emerge_area (p) + worldedit.emerge_area (p.xpos1, p.xpos2) + return 0 +end + +function worldedit.wait_move (p) + worldedit.move (p.xpos1, p.xpos2, p.axis, p.amount) + return 0 +end + +function worldedit.wait_set (p) + worldedit.set (p.xpos1, p.xpos2, p.node_names) + return 0 +end + +-- =================================================================== + +function worldedit.pop_queue() + if #worldedit.cmd_queue == 0 then return 0 end + if worldedit.emerge_busy == 1 then + deblog ("pop_queue: WE is busy, waiting 1 second") + minetest.after (1, worldedit.pop_queue) + return 0 + end + + deblog ("pop_queue: WE is free, running next command") + local qe = table.remove (worldedit.cmd_queue, 1) + qe.func (qe.param) + return 0 +end + +-- =================================================================== + +function worldedit.copy (xpos1, xpos2, axis, amount) + if worldedit.emerge_busy == 1 then + deblog ("worldedit.copy called but WE is busy") + else + deblog ("worldedit.copy called and WE is free") + end + + local pos1, pos2 = worldedit.sort_pos (xpos1, xpos2) + + if worldedit.volume (pos1, pos2) > 1500000 then + minetest.chat_send_all ("//copy is limited to 1.5M nodes", + false) + return 0 + end + + if worldedit.emerge_busy == 1 then + if worldedit.use_queue == 0 then + minetest.chat_send_all ("A previous //operation is busy") + else + local qe = { + func = worldedit.wait_copy , + param = { + xpos1=xpos1, xpos2=xpos2, axis=axis, amount=amount + } + } + + deblog ("queuing for later: copy " .. + ocutil.pos_to_str (xpos1) .. " " .. + ocutil.pos_to_str (xpos2) .. " " .. + axis .. " " .. amount) + + qe = ocutil.clone_table (qe) + table.insert (worldedit.cmd_queue, qe) + minetest.after (1, worldedit.pop_queue) + end + return 0 + else + deblog ("WE is free, proceeding: copy " .. + ocutil.pos_to_str (xpos1) .. " " .. + ocutil.pos_to_str (xpos2) .. " " .. + axis .. " " .. amount) + end + +-- =================================================================== + + local newpos1 = { x=pos1.x, y=pos1.y, z=pos1.z } + local newpos2 = { x=pos2.x, y=pos2.y, z=pos2.z } + + newpos1 [axis] = newpos1 [axis] + amount + newpos2 [axis] = newpos2 [axis] + amount + +-- =================================================================== + + local os1 = minetest.pos_to_string (pos1) + local os2 = minetest.pos_to_string (pos2) + + local ps1 = minetest.pos_to_string (newpos1) + local ps2 = minetest.pos_to_string (newpos2) + +-- =================================================================== + + if not coderedit_disable_verbose then + minetest.chat_send_all ("//copy " .. + "Source: " .. os1 .. " " .. os2 .. " " .. + "Axis: " .. axis .. " " .. + "Amount: " .. amount) + minetest.chat_send_all ("//copy Destin:" .. + ps1 .. " " .. ps2) + end + + deblog ("//copy " .. + "Source: " .. os1 .. " " .. os2 .. " " .. + "Axis: " .. axis .. " " .. + "Amount: " .. amount) + deblog ("//copy Destin: " .. ps1 .. " " .. ps2) + +-- =================================================================== + + local x1min, x1max = sort2num (pos1.x, pos2.x) + local y1min, y1max = sort2num (pos1.y, pos2.y) + local z1min, z1max = sort2num (pos1.z, pos2.z) + + local x2min, x2max = sort2num (newpos1.x, newpos2.x) + local y2min, y2max = sort2num (newpos1.y, newpos2.y) + local z2min, z2max = sort2num (newpos1.z, newpos2.z) + + local overlap = true + if x1max < x2min or x2max < x1min or + y1max < y2min or y2max < y1min or + z1max < z2min or z2max < z1min then + overlap = false + end + + if overlap then + minetest.chat_send_all ("Source and dest regions" .. + " overlap, there may be dark areas") + end + +-- =================================================================== + + worldedit.emerge_busy = 1 + if collectgarbage ("count") > 307200 then collectgarbage() end + + local param = { + pos1=pos1 , pos2=pos2 , axis=axis , amount=amount , + overlap=overlap , + } + + minetest.emerge_area (newpos1, newpos2, + emerge_callback_copy, param) + + return end_of_start_emerge (pos1, pos2, "COPY") +end + +-- =================================================================== + +function worldedit.emerge_area (xpos1, xpos2) + + if worldedit.emerge_busy == 1 then + if worldedit.use_queue == 0 then + minetest.chat_send_all ("A previous //operation is busy") + else + local qe = { + func = worldedit.wait_emerge_area , + param = { xpos1=xpos1, xpos2=xpos2 } , + } + + qe = ocutil.clone_table (qe) + table.insert (worldedit.cmd_queue, qe) + minetest.after (1, worldedit.pop_queue) + end + return 0 + end + + worldedit.emerge_busy = 1 + local pos1, pos2 = worldedit.sort_pos (xpos1, xpos2) + if collectgarbage ("count") > 307200 then collectgarbage() end + local param = { pos1=pos1, pos2=pos2 } + + minetest.emerge_area (pos1, pos2, emerge_callback_emerge, param) + return end_of_start_emerge (pos1, pos2, "EMERGE") +end + +-- =================================================================== + +-- Replaces all instances of "search_node" with "replace_node" in a +-- region. When "inverse" is "true", replaces all instances that are +-- NOT "search_node". +-- @return The number of nodes replaced. + +function worldedit.replace (pos1, pos2, search_node, + replace_node, inverse) + + pos1, pos2 = worldedit.sort_pos (pos1, pos2) + local manip, area = mh.init (pos1, pos2) + local data = manip:get_data() + + local search_id = ocutil.get_content_id (search_node ) + if search_id == nil then + minetest.chat_send_all ("Error: Unknown node " .. search_node ) + return + end + + local replace_id = ocutil.get_content_id (replace_node) + if replace_id == nil then + minetest.chat_send_all ("Error: Unknown node " .. replace_node ) + return + end + + local count = 0 + + --- TODO: This could be shortened by checking `inverse` in the loop, + -- but that would have a speed penalty. Is the penalty big enough + -- to matter? + + if not inverse then + for i in area:iterp (pos1, pos2) do + if data [i] == search_id then + data [i] = replace_id + count = count + 1 + end + end + else + for i in area:iterp (pos1, pos2) do + if data [i] ~= search_id then + data [i] = replace_id + count = count + 1 + end + end + end + + mh.finish (manip, data) + return count +end + +-- =================================================================== + +-- Sets a region to node_names. +-- @param pos1 +-- @param pos2 +-- @param node_names Node name or list of node names. +-- @return The number of nodes set. + +function worldedit.old_set (xpos1, xpos2, node_names) + + local pos1, pos2 + pos1, pos2 = worldedit.sort_pos (xpos1, xpos2) + + local xdelta = pos2.x - pos1.x + local ydelta = pos2.y - pos1.y + local zdelta = pos2.z - pos1.z + + if xdelta >= 30 or xdelta <= -30 then + local m1 = idiv (xdelta, 2) + local m2 = xdelta - m1 + local posa = { x=pos1.x+m1, y=pos2.y, z=pos2.z } + local posb = { x=pos1.x+m2, y=pos1.y, z=pos1.z } + worldedit.old_set (pos1, posa, node_names) + worldedit.old_set (posb, pos2, node_names) + return worldedit.volume (pos1, pos2) + end + + if ydelta >= 30 or ydelta <= -30 then + local m1 = idiv (ydelta, 2) + local m2 = ydelta - m1 + local posa = { x=pos2.x, y=pos1.y+m1, z=pos2.z } + local posb = { x=pos1.x, y=pos1.y+m2, z=pos1.z } + worldedit.old_set (pos1, posa, node_names) + worldedit.old_set (posb, pos2, node_names) + return worldedit.volume (pos1, pos2) + end + + if zdelta >= 30 or zdelta <= -30 then + local m1 = idiv (zdelta, 2) + local m2 = zdelta - m1 + local posa = { x=pos2.x, y=pos2.y, z=pos1.z+m1 } + local posb = { x=pos1.x, y=pos1.y, z=pos1.z+m2 } + worldedit.old_set (pos1, posa, node_names) + worldedit.old_set (posb, pos2, node_names) + return worldedit.volume (pos1, pos2) + end + + local manip, area = mh.init (pos1, pos2) + manip:update_map() + + local data = mh.get_empty_data (area) + if collectgarbage ("count") > 307200 then collectgarbage() end + + if type (node_names) == "string" then -- Only one type of node + if node_names ~= "default:emerge" then + local id = ocutil.get_content_id (node_names) + if id == nil then + minetest.chat_send_all ("Error: Unknown node " .. node_names) + return + end + + -- Fill area with node + for i in area:iterp (pos1, pos2) do + data [i] = id + end + end + else -- Several types of nodes specified + local node_ids = {} + for i, v in ipairs (node_names) do + node_ids [i] = ocutil.get_content_id (v) + if node_ids [i] == nil then + minetest.chat_send_all ("Error: Unknown node " .. v) + return + end + end + -- Fill area randomly with nodes + local id_count, rand = #node_ids, math.random + for i in area:iterp (pos1, pos2) do + data [i] = node_ids [rand (id_count)] + end + end + + if collectgarbage ("count") > 307200 then collectgarbage() end + manip:set_data (data) + data = {} + manip:update_liquids() + manip:write_to_map() + manip:update_map() + + if collectgarbage ("count") > 307200 then collectgarbage() end + return worldedit.volume (pos1, pos2) +end + +-- =================================================================== + +function worldedit.set (xpos1, xpos2, node_names) + + if worldedit.emerge_busy == 1 then + if worldedit.use_queue == 0 then + minetest.chat_send_all ("A previous //operation is busy") + else + local qe = { + func = worldedit.wait_set , + param = { + xpos1=xpos1, xpos2=xpos2, node_names=node_names + } + } + + qe = ocutil.clone_table (qe) + table.insert (worldedit.cmd_queue, qe) + minetest.after (1, worldedit.pop_queue) + end + return 0 + end + + worldedit.emerge_busy = 1 + local pos1, pos2 = worldedit.sort_pos (xpos1, xpos2) + if collectgarbage ("count") > 307200 then collectgarbage() end + local vol = worldedit.volume (pos1, pos2) + + if type (node_names) ~= "string" or + node_names ~= "default:emerge" then + if (vol > 190000000) then + worldedit.emerge_busy = 0 + minetest.chat_send_all ("//set is limited to 190M nodes") + return 0 + end + end + + if not coderedit_disable_verbose then + minetest.chat_send_all ("Starting set of " .. vol .. + " node(s)") + end + + local param = { pos1=pos1, pos2=pos2, node_names=node_names } + minetest.emerge_area (pos1, pos2, emerge_callback_set, param) + return end_of_start_emerge (pos1, pos2, "SET") +end + +-- =================================================================== + +--- Sets param2 of a region. +-- @param pos1 +-- @param pos2 +-- @param param2 Value of param2 to set +-- @return The number of nodes set. + +function worldedit.set_param2 (pos1, pos2, param2) + + pos1, pos2 = worldedit.sort_pos (pos1, pos2) + + local manip, area = mh.init (pos1, pos2) + local param2_data = manip:get_param2_data() + + -- Set param2 for every node + for i in area:iterp (pos1, pos2) do + param2_data [i] = param2 + end + + -- Update map + manip:set_param2_data (param2_data) + manip:write_to_map() + manip:update_map() + + return worldedit.volume (pos1, pos2) +end + +-- =================================================================== + +--- Duplicates a region `amount` times with offset vector `direction`. +-- Stacking is spread across server steps, one copy per step. +-- @return The number of nodes stacked. + +function worldedit.stack2 (pos1, pos2, direction, amount, finished) + + local i = 0 + local translated = {x=0, y=0, z=0} + local function next_one() + if i < amount then + i = i + 1 + translated.x = translated.x + direction.x + translated.y = translated.y + direction.y + translated.z = translated.z + direction.z + + worldedit.copy2 (pos1, pos2, translated) + minetest.after (0, next_one) + else + if finished then + finished() + end + end + end + + next_one() + return worldedit.volume (pos1, pos2) * amount +end + +-- =================================================================== + +--- Copies a region by offset vector `off`. +-- @param pos1 +-- @param pos2 +-- @param off +-- @return The number of nodes copied. + +function worldedit.copy2 (pos1, pos2, off) + + local pos1, pos2 = worldedit.sort_pos (pos1, pos2) + worldedit.keep_loaded (pos1, pos2) + + local get_node, get_meta, set_node = minetest.get_node, + minetest.get_meta, minetest.set_node + + local pos = {} + pos.x = pos2.x + while pos.x >= pos1.x do + pos.y = pos2.y + while pos.y >= pos1.y do + pos.z = pos2.z + while pos.z >= pos1.z do + local node = get_node(pos) -- Obtain current node + local meta = get_meta(pos):to_table() -- Get meta of current node + local newpos = vector.add(pos, off) -- Calculate new position + set_node(newpos, node) -- Copy node to new position + get_meta(newpos):from_table(meta) -- Set metadata of new node + + pos.z = pos.z - 1 + end + + pos.y = pos.y - 1 + end + + pos.x = pos.x - 1 + end + + return worldedit.volume (pos1, pos2) +end + +-- =================================================================== + +-- Moves a region along `axis` by `amount` nodes. +-- @return The number of nodes moved. + +function worldedit.old_move (pos1, pos2, axis, amount) + + local pos1, pos2 = worldedit.sort_pos (pos1, pos2) + worldedit.keep_loaded (pos1, pos2) + + --- TODO: Move slice by slice using schematic method in the move axis + -- and transfer metadata in separate loop (and if the amount is + -- greater than the length in the axis, copy whole thing at a time and + -- erase original after, using schematic method). + + local get_node, get_meta, set_node, remove_node = minetest.get_node, + minetest.get_meta, minetest.set_node, minetest.remove_node + -- Copy things backwards when negative to avoid corruption. + --- FIXME: Lots of code duplication here. + + if amount < 0 then + local pos = {} + pos.x = pos1.x + + while pos.x <= pos2.x do + pos.y = pos1.y + + while pos.y <= pos2.y do + pos.z = pos1.z + + while pos.z <= pos2.z do + + -- Obtain current node + local node = get_node (pos) + + -- Get metadata of current node + local meta = get_meta (pos):to_table() + + -- Remove current node + remove_node (pos) + + -- Store current position + local value = pos [axis] + + -- Move along axis + pos[axis] = value + amount + + -- Move node to new position + set_node (pos, node) + + -- Set metadata of new node + get_meta (pos):from_table (meta) + + -- Restore old position + pos [axis] = value + + pos.z = pos.z + 1 + end + + pos.y = pos.y + 1 + end + + pos.x = pos.x + 1 + end + else + local pos = {} + pos.x = pos2.x + + while pos.x >= pos1.x do + pos.y = pos2.y + + while pos.y >= pos1.y do + pos.z = pos2.z + + while pos.z >= pos1.z do + + -- Obtain current node + local node = get_node (pos) + + -- Get metadata of current node + local meta = get_meta (pos):to_table() + + -- Remove current node + remove_node (pos) + + -- Store current position + local value = pos [axis] + + -- Move along axis + pos[axis] = value + amount + + -- Move node to new position + set_node (pos, node) + + -- Set metadata of new node + get_meta (pos):from_table (meta) + + -- Restore old position + pos [axis] = value + + pos.z = pos.z - 1 + end + + pos.y = pos.y - 1 + end + + pos.x = pos.x - 1 + end + end + + return worldedit.volume (pos1, pos2) +end + +-- =================================================================== + +function worldedit.move (xpos1, xpos2, axis, amount) + + if worldedit.emerge_busy == 1 then + deblog ("worldedit.move called but WE is busy") + else + deblog ("worldedit.move called and WE is free") + end + local pos1, pos2 = worldedit.sort_pos (xpos1, xpos2) + + if worldedit.volume (pos1, pos2) > 1500000 then + minetest.chat_send_all ("//move is limited to 1.5M nodes", + false) + return 0 + end + + if worldedit.emerge_busy == 1 then + if worldedit.use_queue == 0 then + minetest.chat_send_all ("A previous //operation is busy") + else + local qe = { + func = worldedit.wait_move , + param = { + xpos1=xpos1, xpos2=xpos2, axis=axis, amount=amount + } + } + + deblog ("queuing for later: move " .. + ocutil.pos_to_str (xpos1) .. " " .. + ocutil.pos_to_str (xpos2) .. " " .. + axis .. " " .. amount) + + qe = ocutil.clone_table (qe) + table.insert (worldedit.cmd_queue, qe) + minetest.after (1, worldedit.pop_queue) + end + return 0 + else + deblog ("WE is free, proceeding: move " .. + ocutil.pos_to_str (xpos1) .. " " .. + ocutil.pos_to_str (xpos2) .. " " .. + axis .. " " .. + amount) + end + +-- =================================================================== + + local newpos1 = { x=pos1.x, y=pos1.y, z=pos1.z } + local newpos2 = { x=pos2.x, y=pos2.y, z=pos2.z } + + newpos1 [axis] = newpos1 [axis] + amount + newpos2 [axis] = newpos2 [axis] + amount + +-- =================================================================== + + local os1 = minetest.pos_to_string (pos1) + local os2 = minetest.pos_to_string (pos2) + + local ps1 = minetest.pos_to_string (newpos1) + local ps2 = minetest.pos_to_string (newpos2) + +-- =================================================================== + + if not coderedit_disable_verbose then + minetest.chat_send_all ("//move " .. + "Source: " .. os1 .. " " .. os2 .. " " .. + "Axis: " .. axis .. " " .. + "Amount: " .. amount) + minetest.chat_send_all ("//move Destin:" .. + ps1 .. " " .. ps2) + end + + deblog ("//move " .. + "Source: " .. os1 .. " " .. os2 .. " " .. + "Axis: " .. axis .. " " .. + "Amount: " .. amount) + deblog ("//move Destin: " .. ps1 .. " " .. ps2) + +-- =================================================================== + + local x1min, x1max = sort2num (pos1.x, pos2.x) + local y1min, y1max = sort2num (pos1.y, pos2.y) + local z1min, z1max = sort2num (pos1.z, pos2.z) + + local x2min, x2max = sort2num (newpos1.x, newpos2.x) + local y2min, y2max = sort2num (newpos1.y, newpos2.y) + local z2min, z2max = sort2num (newpos1.z, newpos2.z) + + local overlap = true + if x1max < x2min or x2max < x1min or + y1max < y2min or y2max < y1min or + z1max < z2min or z2max < z1min then + overlap = false + end + + if overlap then + minetest.chat_send_all ("Source and dest regions" .. + " overlap, there may be dark areas") + end + +-- =================================================================== + + worldedit.emerge_busy = 1 + if collectgarbage ("count") > 307200 then collectgarbage() end + + local param = { + pos1=pos1 , pos2=pos2 , axis=axis , amount=amount , + overlap=overlap , + } + + minetest.emerge_area (newpos1, newpos2, + emerge_callback_move, param) + + return end_of_start_emerge (pos1, pos2, "MOVE") +end + +-- =================================================================== + +-- Duplicates a region along `axis` `amount` times. +-- Stacking is spread across server steps, one copy per step. +-- @param pos1 +-- @param pos2 +-- @param axis Axis direction, "x", "y", or "z". +-- @param count +-- @return The number of nodes stacked. + +function worldedit.stack (pos1, pos2, axis, count) + + local pos1, pos2 = worldedit.sort_pos(pos1, pos2) + local length = pos2[axis] - pos1[axis] + 1 + if count < 0 then + count = -count + length = -length + end + local amount = 0 + local copy = worldedit.copy + local i = 1 + local function next_one() + if i <= count then + i = i + 1 + amount = amount + length + copy(pos1, pos2, axis, amount) + minetest.after(0, next_one) + end + end + next_one() + return worldedit.volume(pos1, pos2) * count +end + +-- =================================================================== + +--- Stretches a region by a factor of positive integers along the X, Y, and Z +-- axes, respectively, with `pos1` as the origin. +-- @param pos1 +-- @param pos2 +-- @param stretch_x Amount to stretch along X axis. +-- @param stretch_y Amount to stretch along Y axis. +-- @param stretch_z Amount to stretch along Z axis. +-- @return The number of nodes scaled. +-- @return The new scaled position 1. +-- @return The new scaled position 2. + +function worldedit.stretch (pos1, pos2, stretch_x, stretch_y, stretch_z) + + local pos1, pos2 = worldedit.sort_pos(pos1, pos2) + + -- Prepare schematic of large node + local get_node, get_meta, place_schematic = minetest.get_node, + minetest.get_meta, minetest.place_schematic + local placeholder_node = {name="", param1=255, param2=0} + local nodes = {} + for i = 1, stretch_x * stretch_y * stretch_z do + nodes[i] = placeholder_node + end + + local schematic = {size={x=stretch_x, y=stretch_y, z=stretch_z}, + data=nodes} + + local size_x, size_y, size_z = stretch_x - 1, + stretch_y - 1, stretch_z - 1 + + local new_pos2 = { + x = pos1.x + (pos2.x - pos1.x) * stretch_x + size_x, + y = pos1.y + (pos2.y - pos1.y) * stretch_y + size_y, + z = pos1.z + (pos2.z - pos1.z) * stretch_z + size_z, + } + worldedit.keep_loaded(pos1, new_pos2) + + local pos = {x=pos2.x, y=0, z=0} + local big_pos = {x=0, y=0, z=0} + while pos.x >= pos1.x do + pos.y = pos2.y + while pos.y >= pos1.y do + pos.z = pos2.z + while pos.z >= pos1.z do + local node = get_node(pos) -- Get current node + local meta = get_meta(pos):to_table() -- Get meta of current node + + -- Calculate far corner of the big node + local pos_x = pos1.x + (pos.x - pos1.x) * stretch_x + local pos_y = pos1.y + (pos.y - pos1.y) * stretch_y + local pos_z = pos1.z + (pos.z - pos1.z) * stretch_z + + -- Create large node + placeholder_node.name = node.name + placeholder_node.param2 = node.param2 + big_pos.x, big_pos.y, big_pos.z = pos_x, pos_y, pos_z + place_schematic(big_pos, schematic) + + -- Fill in large node meta + if next(meta.fields) ~= nil or next(meta.inventory) ~= nil then + -- Node has meta fields + for x = 0, size_x do + for y = 0, size_y do + for z = 0, size_z do + big_pos.x = pos_x + x + big_pos.y = pos_y + y + big_pos.z = pos_z + z + -- Set metadata of new node + get_meta(big_pos):from_table(meta) + end + end + end + end + pos.z = pos.z - 1 + end + pos.y = pos.y - 1 + end + pos.x = pos.x - 1 + end + return worldedit.volume(pos1, pos2) * stretch_x * stretch_y * stretch_z, pos1, new_pos2 +end + +-- =================================================================== + +--- Transposes a region between two axes. +-- @return The number of nodes transposed. +-- @return The new transposed position 1. +-- @return The new transposed position 2. + +function worldedit.transpose(pos1, pos2, axis1, axis2) + local pos1, pos2 = worldedit.sort_pos(pos1, pos2) + + local compare + local extent1, extent2 = pos2[axis1] - pos1[axis1], pos2[axis2] - pos1[axis2] + + if extent1 > extent2 then + compare = function(extent1, extent2) + return extent1 > extent2 + end + else + compare = function(extent1, extent2) + return extent1 < extent2 + end + end + + -- Calculate the new position 2 after transposition + local new_pos2 = {x=pos2.x, y=pos2.y, z=pos2.z} + new_pos2[axis1] = pos1[axis1] + extent2 + new_pos2[axis2] = pos1[axis2] + extent1 + + local upper_bound = {x=pos2.x, y=pos2.y, z=pos2.z} + if upper_bound[axis1] < new_pos2[axis1] then upper_bound[axis1] = new_pos2[axis1] end + if upper_bound[axis2] < new_pos2[axis2] then upper_bound[axis2] = new_pos2[axis2] end + worldedit.keep_loaded(pos1, upper_bound) + + local pos = {x=pos1.x, y=0, z=0} + local get_node, get_meta, set_node = minetest.get_node, + minetest.get_meta, minetest.set_node + while pos.x <= pos2.x do + pos.y = pos1.y + while pos.y <= pos2.y do + pos.z = pos1.z + while pos.z <= pos2.z do + local extent1, extent2 = pos[axis1] - pos1[axis1], pos[axis2] - pos1[axis2] + if compare(extent1, extent2) then -- Transpose only if below the diagonal + local node1 = get_node(pos) + local meta1 = get_meta(pos):to_table() + local value1, value2 = pos[axis1], pos[axis2] -- Save position values + pos[axis1], pos[axis2] = pos1[axis1] + extent2, pos1[axis2] + extent1 -- Swap axis extents + local node2 = get_node(pos) + local meta2 = get_meta(pos):to_table() + set_node(pos, node1) + get_meta(pos):from_table(meta1) + pos[axis1], pos[axis2] = value1, value2 -- Restore position values + set_node(pos, node2) + get_meta(pos):from_table(meta2) + end + pos.z = pos.z + 1 + end + pos.y = pos.y + 1 + end + pos.x = pos.x + 1 + end + return worldedit.volume(pos1, pos2), pos1, new_pos2 +end + +-- =================================================================== + +--- Flips a region along `axis`. +-- @return The number of nodes flipped. + +function worldedit.flip(pos1, pos2, axis) + local pos1, pos2 = worldedit.sort_pos(pos1, pos2) + + worldedit.keep_loaded(pos1, pos2) + + --- TODO: Flip the region slice by slice along the flip axis using schematic method. + local pos = {x=pos1.x, y=0, z=0} + local start = pos1[axis] + pos2[axis] + pos2[axis] = pos1[axis] + math.floor((pos2[axis] - pos1[axis]) / 2) + local get_node, get_meta, set_node = minetest.get_node, + minetest.get_meta, minetest.set_node + while pos.x <= pos2.x do + pos.y = pos1.y + while pos.y <= pos2.y do + pos.z = pos1.z + while pos.z <= pos2.z do + local node1 = get_node(pos) + local meta1 = get_meta(pos):to_table() + local value = pos[axis] -- Save position + pos[axis] = start - value -- Shift position + local node2 = get_node(pos) + local meta2 = get_meta(pos):to_table() + set_node(pos, node1) + get_meta(pos):from_table(meta1) + pos[axis] = value -- Restore position + set_node(pos, node2) + get_meta(pos):from_table(meta2) + pos.z = pos.z + 1 + end + pos.y = pos.y + 1 + end + pos.x = pos.x + 1 + end + return worldedit.volume(pos1, pos2) +end + +-- =================================================================== + +--- Rotates a region clockwise around an axis. +-- @param pos1 +-- @param pos2 +-- @param axis Axis ("x", "y", or "z"). +-- @param angle Angle in degrees (90 degree increments only). +-- @return The number of nodes rotated. +-- @return The new first position. +-- @return The new second position. + +function worldedit.rotate(pos1, pos2, axis, angle) + local pos1, pos2 = worldedit.sort_pos(pos1, pos2) + + if worldedit.volume (pos1, pos2) > 1000000 then + minetest.chat_send_all ("//rotate is limited to 1M nodes", + false) + return + end + + local other1, other2 = worldedit.get_axis_others(axis) + angle = angle % 360 + + local count + if angle == 90 then + worldedit.flip(pos1, pos2, other1) + count, pos1, pos2 = worldedit.transpose(pos1, pos2, other1, other2) + elseif angle == 180 then + worldedit.flip(pos1, pos2, other1) + count = worldedit.flip(pos1, pos2, other2) + elseif angle == 270 then + worldedit.flip(pos1, pos2, other2) + count, pos1, pos2 = worldedit.transpose(pos1, pos2, other1, other2) + else + error("Only 90 degree increments are supported!") + end + return count, pos1, pos2 +end + +-- =================================================================== + +-- Rotates all oriented nodes in a region clockwise around the Y axis. +-- @param pos1 +-- @param pos2 +-- @param angle Angle in degrees (90 degree increments only). +-- @return The number of nodes oriented. +-- TODO: Support 6D facedir rotation along arbitrary axis. + +function worldedit.orient(pos1, pos2, angle) + local pos1, pos2 = worldedit.sort_pos(pos1, pos2) + + if worldedit.volume (pos1, pos2) > 1000000 then + minetest.chat_send_all ("//orient is limited to 1M nodes", + false) + return + end + + local registered_nodes = minetest.registered_nodes + + local wallmounted = { + [90] = {[0]=0, 1, 5, 4, 2, 3}, + [180] = {[0]=0, 1, 3, 2, 5, 4}, + [270] = {[0]=0, 1, 4, 5, 3, 2} + } + local facedir = { + [90] = {[0]=1, 2, 3, 0}, + [180] = {[0]=2, 3, 0, 1}, + [270] = {[0]=3, 0, 1, 2} + } + + angle = angle % 360 + if angle == 0 then + return 0 + end + if angle % 90 ~= 0 then + error("Only 90 degree increments are supported!") + end + local wallmounted_substitution = wallmounted[angle] + local facedir_substitution = facedir[angle] + + worldedit.keep_loaded(pos1, pos2) + + local count = 0 + local set_node, get_node, get_meta, swap_node = minetest.set_node, + minetest.get_node, minetest.get_meta, minetest.swap_node + local pos = {x=pos1.x, y=0, z=0} + while pos.x <= pos2.x do + pos.y = pos1.y + while pos.y <= pos2.y do + pos.z = pos1.z + while pos.z <= pos2.z do + local node = get_node(pos) + local def = registered_nodes[node.name] + if def then + if def.paramtype2 == "wallmounted" then + node.param2 = wallmounted_substitution[node.param2] + local meta = get_meta(pos):to_table() + set_node(pos, node) + get_meta(pos):from_table(meta) + count = count + 1 + elseif def.paramtype2 == "facedir" then + node.param2 = facedir_substitution[node.param2] + local meta = get_meta(pos):to_table() + set_node(pos, node) + get_meta(pos):from_table(meta) + count = count + 1 + end + end + pos.z = pos.z + 1 + end + pos.y = pos.y + 1 + end + pos.x = pos.x + 1 + end + return count +end + +-- =================================================================== + +-- Attempts to fix the lighting in a region. +-- @return The number of nodes updated. + +function worldedit.fixlight(pos1, pos2) + local pos1, pos2 = worldedit.sort_pos (pos1, pos2) + + local epos1 = { x=pos1.x-32, y=pos1.y-32, z=pos1.z-32 } + local epos2 = { x=pos2.x+32, y=pos2.y+32, z=pos2.z+32 } + vm = minetest.get_voxel_manip() + vm:read_from_map (epos1, epos2) + vm:set_lighting ({day=15,night=4}, epos1, epos2) + vm:calc_lighting (epos1, epos2) + vm:update_liquids() + vm:write_to_map() + + return worldedit.volume (pos1, pos2) +end + +-- =================================================================== + +-- Clears all objects in a region. +-- @return The number of objects cleared. + +function worldedit.clear_objects(pos1, pos2) + pos1, pos2 = worldedit.sort_pos(pos1, pos2) + + worldedit.keep_loaded(pos1, pos2) + + -- Offset positions to include full nodes (positions are in the center of nodes) + local pos1x, pos1y, pos1z = pos1.x - 0.5, pos1.y - 0.5, pos1.z - 0.5 + local pos2x, pos2y, pos2z = pos2.x + 0.5, pos2.y + 0.5, pos2.z + 0.5 + + -- Center of region + local center = { + x = pos1x + ((pos2x - pos1x) / 2), + y = pos1y + ((pos2y - pos1y) / 2), + z = pos1z + ((pos2z - pos1z) / 2) + } + -- Bounding sphere radius + local radius = math.sqrt( + (center.x - pos1x) ^ 2 + + (center.y - pos1y) ^ 2 + + (center.z - pos1z) ^ 2) + + local count = 0 + for _, obj in pairs (minetest.get_objects_inside_radius (center, radius)) do + + local entity = obj:get_luaentity() + -- Avoid players and WorldEdit entities + if not obj:is_player() and (not entity or + not entity.name:find("^worldedit:")) then + local pos = obj:getpos() + if pos.x >= pos1x and pos.x <= pos2x and + pos.y >= pos1y and pos.y <= pos2y and + pos.z >= pos1z and pos.z <= pos2z then + -- Inside region + obj:remove() + count = count + 1 + end + end + end + return count +end diff --git a/Bucket_Game-branches/remove_io_and_os-vs-bg220909/mods/codercore/coderskins/skinlist.lua b/Bucket_Game-branches/remove_io_and_os-vs-bg220909/mods/codercore/coderskins/skinlist.lua new file mode 100644 index 0000000..3dcf9f1 --- /dev/null +++ b/Bucket_Game-branches/remove_io_and_os-vs-bg220909/mods/codercore/coderskins/skinlist.lua @@ -0,0 +1,331 @@ +coderskins.desc1 = {} +coderskins.desc2 = {} + +-- =================================================================== + +coderskins.desc2 ["skin_Actual_Cat" ] = "How Now Meow Wow" +coderskins.desc2 ["skin_Apple_Tree" ] = "Apple a Day Hooray" +coderskins.desc2 ["skin_Patience" ] = "Patience leads to focus" + +-- =================================================================== + +coderskins.list = { + + "skin_Chinese_Off_White" , + "skin_Corona" , + "skin_Mumbo_Jumbo" , + "skin_RedMinionToby" , + "skin_SAF_Army1" , + "skin_SAF_Army3G" , + "skin_Hope" , + "skin_Jessa_PJs" , + + "skin_09SharkBoy" , + "skin_Unspeakable" , + "skin_LDShadow_Lady" , + "skin_Steve_Watch" , + "skin_Business_Kermit" , + "skin_Stampy_Boots" , + "skin_iBallistic_Squid" , + "skin_MooseCraft" , + "sscharacter_120" , + + "skin_Actual_Cat" , + "skin_Apple_Tree" , + "skin_Black_Panther" , + "skin_Farmer_Green" , + "skin_Patience" , + "skin_Bear" , + "skin_Hotdog" , + "skin_Robocop" , + "skin_Capt_America" , + "skin_Queen_Elsa" , + "skin_Cola" , + "skin_Santa" , + "skin_Tiger" , + "skin_Cool_Panda" , + + "skin_Athena" , + "skin_Brianna_Playz" , + "skin_Chad_Wild_Clay" , + "skin_Chara" , + "skin_Duck" , + "skin_Kata_Red_Hair" , + "skin_Potion_Master" , + "skin_Preston_Playz" , + + "skin_Batman" , + "skin_Battery" , + "skin_Bear_Overalls" , + "skin_Bearded_Wizard" , + "skin_Alejo_Facheraso" , + "skin_Bee" , + "skin_Capt_Blue_Sparrow" , + "skin_Doraemon" , + "skin_Green_Boy" , + + "skin_Grey_Dog" , + "skin_Hispanic_Napoleon" , + "skin_King_Turtle" , + "skin_Krypto" , + "skin_Pink_Tiger" , + "skin_Recon_Expert" , + "skin_Big_Bird" , + "skin_Gold_Cylon" , + "skin_Gold_Knight" , + "skin_Leo" , + "skin_Wonder_Woman" , + "skin_Mr_Spock" , + "skin_Regular_Cylon" , + "skin_Rosalyn_Potion_Master" , + "skin_Red_Wolf_Boy" , + "skin_Rosa" , + "skin_Shovel_Knight" , + "skin_Wonder_Boy" , + "skin_Boy_Red_Hoodie" , + "skin_Boy_Water_Jacket" , + "skin_Fire_Enderman" , + "skin_Fox" , + "skin_Gamer_Guy" , + "skin_Girl_Casual" , + "skin_Good_Witch" , + "skin_Green_Claus_Wizard" , + "skin_Heather_Elf" , + "skin_Hobbit" , + "skin_Jane_Foster" , + "skin_Kyle_Rayner" , + "skin_Lego_Person" , + "skin_Lego_Spaceman" , + "skin_Link" , + "skin_Luigi" , + "skin_Mario" , + "skin_Marley_Xia" , + "skin_Mutant_Fox" , + "skin_Owl" , + "skin_Pachilo155" , + "skin_Pie" , + "skin_Pizza_Girl" , + "skin_Polar_Bear" , + "skin_Purple_Outfit" , + "skin_Purple_Princess" , + "skin_Quackin_Hood" , + "skin_Rabbit" , + "skin_Rabbit_Coco" , + "skin_Rainboots" , + "skin_Squirrel" , + "skin_Stampy" , + "skin_Steampunk" , + "skin_Super_Jack" , + "skin_Supercow" , + "skin_Superpollo" , + "skin_Thanatos" , + "skin_Trainer_Red" , + "skin_Wafleman" , + "skin_White_Bear" , + "skin_White_Dress" , + "skin_Puppy" , + "skin_Bakugo" , + + "sdskin_Blue_Girl" , + "sdskin_Calinou" , + "sdskin_Son_Goku" , + "sdskin_StormChaser_30000" , + "sdskin_oOChainLynxOo" , + "sdskin_sdzen" , + + "sscharacter_1" , + "sscharacter_100" , + "sscharacter_101" , + "sscharacter_102" , + "sscharacter_103" , + "sscharacter_106" , + "sscharacter_107" , + "sscharacter_108" , + "sscharacter_109" , + "sscharacter_110" , + "sscharacter_111" , + "sscharacter_113" , + "sscharacter_114" , + "sscharacter_116" , + "sscharacter_118" , + "sscharacter_119" , + "sscharacter_121" , + "sscharacter_122" , + "sscharacter_123" , + "sscharacter_126" , + "sscharacter_129" , + "sscharacter_13" , + "sscharacter_132" , + "sscharacter_133" , + "sscharacter_134" , + "sscharacter_135" , + "sscharacter_136" , + "sscharacter_14" , + "sscharacter_140" , + "sscharacter_141" , + "sscharacter_142" , + "sscharacter_143" , + "sscharacter_146" , + "sscharacter_148" , + "sscharacter_149" , + "sscharacter_15" , + "sscharacter_150" , + "sscharacter_151" , + "sscharacter_152" , + "sscharacter_16" , + "sscharacter_2" , + "sscharacter_20" , + "sscharacter_21" , + "sscharacter_22" , + "sscharacter_23" , + "sscharacter_24" , + "sscharacter_25" , + "sscharacter_26" , + "sscharacter_28" , + "sscharacter_30" , + "sscharacter_32" , + "sscharacter_33" , + "sscharacter_47" , + "sscharacter_51" , + "sscharacter_56" , + "sscharacter_57" , + "sscharacter_59" , + "sscharacter_6" , + "sscharacter_64" , + "sscharacter_66" , + "sscharacter_70" , + "sscharacter_71" , + "sscharacter_73" , + "sscharacter_75" , + "sscharacter_78" , + "sscharacter_80" , + "sscharacter_81" , + "sscharacter_83" , + "sscharacter_84" , + "sscharacter_85" , + "sscharacter_90" , + "sscharacter_99" , + "uskins_1" , + "uskins_10" , + "uskins_11" , + "uskins_12" , + "uskins_13" , + "uskins_14" , + "uskins_16" , + "uskins_17" , + "uskins_18" , + "uskins_19" , + "uskins_2" , + "uskins_20" , + "uskins_21" , + "uskins_22" , + "uskins_23" , + "uskins_25" , + "uskins_26" , + "uskins_27" , + "uskins_28" , + "uskins_29" , + "uskins_3" , + "uskins_30" , + "uskins_31" , + "uskins_32" , + "uskins_33" , + "uskins_34" , + "uskins_35" , + "uskins_36" , + "uskins_37" , + "uskins_38" , + "uskins_39" , + "uskins_4" , + "uskins_40" , + "uskins_41" , + "uskins_45" , + "uskins_46" , + "uskins_47" , + "uskins_48" , + "uskins_5" , + "uskins_50" , + "uskins_51" , + "uskins_52" , + "uskins_53" , + "uskins_54" , + "uskins_55" , + "uskins_56" , + "uskins_58" , + "uskins_59" , + "uskins_6" , + "uskins_60" , + "uskins_61" , + "uskins_62" , + "uskins_63" , + "uskins_64" , + "uskins_65" , + "uskins_66" , + "uskins_68" , + "uskins_69" , + "uskins_70" , + "uskins_71" , + "uskins_72" , + "uskins_73" , + "uskins_74" , + "uskins_75" , + "uskins_77" , + "uskins_79" , + "uskins_8" , + "uskins_80" , + "uskins_81" , + "uskins_82" , + "uskins_83" , + "uskins_84" , + "uskins_85" , + "uskins_86" , + "uskins_87" , + "uskins_88" , + "uskins_89" , + "uskins_9" , + "uskins_90" , + "uskins_91" , + "uskins_92" , + "uskins_93" , + "uskins_94" , + "uskins_95" , + "uskins_96" , + "uskins_97" , + "uskins_98" , + "uskins_99" , + "uskins_103" , +} + +-- =================================================================== +-- Add local skins. + +if ocutil.bool_setting ("local_skins", true) then + + local ktable = ocutil.vtable_to_ktable (coderskins.list) + local dir = coderskins.textdir + local newlist = {} + local ofname, dfname + + for _, ofname in ipairs(minetest.get_dir_list(dir, false)) + do + ofname = ofname:gsub (".*/" , "") + ofname = ofname:gsub ("%.png$" , "") + dfname = ofname:gsub ("_preview.*$" , "") + + if dfname == ofname and ktable [dfname] == nil then + ktable [dfname] = true + table.insert (newlist, dfname) + end + end + + for _, dfname in ipairs (coderskins.list) do + table.insert (newlist, dfname) + end + + coderskins.list = newlist + ktable = {} + newlist = {} +end + +-- =================================================================== +-- End of file. diff --git a/Bucket_Game-branches/remove_io_and_os-vs-bg220909/mods/coderedit/worldedit/manipulations.lua b/Bucket_Game-branches/remove_io_and_os-vs-bg220909/mods/coderedit/worldedit/manipulations.lua new file mode 100644 index 0000000..44f3607 --- /dev/null +++ b/Bucket_Game-branches/remove_io_and_os-vs-bg220909/mods/coderedit/worldedit/manipulations.lua @@ -0,0 +1,1466 @@ +-- Generic node manipulations +-- @module worldedit.manipulations + +-- =================================================================== + +local coderedit_debug = + minetest.setting_get ("coderedit_debug" ) + +local coderedit_disable_verbose = + minetest.setting_get ("coderedit_disable_verbose" ) or + minetest.setting_get ("disable_coderedit_verbose" ) + +local coderedit_noqueue = + minetest.setting_get ("coderedit_noqueue" ) + +-- =================================================================== + +local mh = worldedit.manip_helpers + +-- Sets a region to `node_names` +-- @param pos1 +-- @param pos2 +-- @param node_names Node name or list of node names. +-- @return The number of nodes set. + +-- =================================================================== + +worldedit.cmd_queue = {} +worldedit.emerge_busy = 0 +worldedit.use_queue = 1 + +if coderedit_noqueue then worldedit.use_queue = 0 end + +-- =================================================================== + +local function idiv (a, b) + return (a - (a % b)) / b +end + +-- =================================================================== + +local function sort2num (a, b) + if a > b then return b, a end + return a, b +end + +-- =================================================================== + +local function deblog (str) + if coderedit_debug then + ocutil.log ("[we] " .. str) + end +end + +-- =================================================================== + +function worldedit.toggle_queue() + if worldedit.use_queue == 0 then + worldedit.use_queue = 1 + minetest.chat_send_all ("CoderEdit commands are queued" ) + else + worldedit.use_queue = 0 + minetest.chat_send_all ("CoderEdit commands are not queued" ) + end +end + +-- =================================================================== + +local function end_of_start_emerge (pos1, pos2, mode) + + if collectgarbage ("count") > 307200 then collectgarbage() end + deblog ("emerge started") + + if not coderedit_disable_verbose then + minetest.chat_send_all ("Volume may print immediately," .. + " but we're not done") + minetest.chat_send_all ("Wait for DONE message") + minetest.chat_send_all ("This may take 5 to 45 minutes" .. + " for large schems") + end + + return worldedit.volume (pos1, pos2) +end + +-- =================================================================== + +local function end_of_emerge (mode) + + if collectgarbage ("count") > 307200 then collectgarbage() end + minetest.chat_send_all ("*** " .. mode .." DONE ***") + deblog ("emerge done") + + worldedit.emerge_busy = 0 + worldedit.place_base = nil + worldedit.place_both = nil + worldedit.place_name = nil + worldedit.place_path = nil + worldedit.place_pos = nil +end + +-- =================================================================== + +local function emerge_callback_copy (blockpos, action, numleft, param) + + if collectgarbage ("count") > 307200 then collectgarbage() end + if numleft ~= 0 then return end + + local pos1 = param.pos1 + local pos2 = param.pos2 + local axis = param.axis + local amount = param.amount + local overlap = param.overlap + + local newpos1 = { x=pos1.x, y=pos1.y, z=pos1.z } + local newpos2 = { x=pos2.x, y=pos2.y, z=pos2.z } + + newpos1 [axis] = newpos1 [axis] + amount + newpos2 [axis] = newpos2 [axis] + amount + + if overlap then + if not coderedit_disable_verbose then + minetest.chat_send_all ("Emerge done, skipping" .. + " set air due to overlap") + minetest.chat_send_all ("Dark areas may result." .. + " Starting actual copy.") + end + else + if not coderedit_disable_verbose then + minetest.chat_send_all ("Emerge done, starting set air") + end + + deblog ("copy callback: set to air start" ) + worldedit.old_set (newpos1, newpos2, "air") + deblog ("copy callback: set to air done" ) + + if not coderedit_disable_verbose then + minetest.chat_send_all ("Set air done, starting" .. + " actual copy") + end + end + + deblog ("copy callback: actual copy start" ) + worldedit.old_copy (pos1, pos2, axis, amount) + deblog ("copy callback: actual copy done" ) + + end_of_emerge ("COPY") +end + +-- =================================================================== + +local function emerge_callback_move (blockpos, action, numleft, param) + + if collectgarbage ("count") > 307200 then collectgarbage() end + if numleft ~= 0 then return end + + local pos1 = param.pos1 + local pos2 = param.pos2 + local axis = param.axis + local amount = param.amount + local overlap = param.overlap + + local newpos1 = { x=pos1.x, y=pos1.y, z=pos1.z } + local newpos2 = { x=pos2.x, y=pos2.y, z=pos2.z } + + newpos1 [axis] = newpos1 [axis] + amount + newpos2 [axis] = newpos2 [axis] + amount + + if overlap then + if not coderedit_disable_verbose then + minetest.chat_send_all ("Emerge done, skipping" .. + " set air due to overlap") + minetest.chat_send_all ("Dark areas may result." .. + " Starting actual move.") + end + else + if not coderedit_disable_verbose then + minetest.chat_send_all ("Emerge done, starting set air") + end + + deblog ("move callback: set to air start" ) + worldedit.old_set (newpos1, newpos2, "air") + deblog ("move callback: set to air done" ) + + if not coderedit_disable_verbose then + minetest.chat_send_all ("Set air done, starting" .. + " actual move") + end + end + + deblog ("move callback: actual move start" ) + worldedit.old_move (pos1, pos2, axis, amount) + deblog ("move callback: actual move done" ) + + end_of_emerge ("MOVE") +end + +-- =================================================================== + +local function emerge_callback_emerge (blockpos, action, + numleft, param) + + if collectgarbage ("count") > 307200 then collectgarbage() end + if numleft ~= 0 then return end + end_of_emerge ("EMERGE") +end + +-- =================================================================== + +local function emerge_callback_set (blockpos, action, numleft, param) + + if false and (numleft % 8192) == 0 then + ocutil.log ("emerge left: " .. numleft) + end + if numleft ~= 0 then return end + + if not coderedit_disable_verbose then + minetest.chat_send_all ("Emerge done, starting actual set") + end + + if type (param.node_names) ~= "string" or + param.node_names ~= "default:emerge" then + worldedit.old_set (param.pos1, + param.pos2, param.node_names) + end + + local pbase = worldedit.place_base + local pboth = worldedit.place_both + local pname = worldedit.place_name + local ppos = worldedit.place_pos + local ppath = worldedit.place_path + + if (ppos ~= nil) and (ppath ~= nil) then + if not coderedit_disable_verbose then + minetest.chat_send_all ("Set done, starting actual place") + end + + if minetest.place_schematic (ppos, ppath) == nil then + minetest.chat_send_all ("Failed to place MTS", false) + else + local ps = minetest.pos_to_string (ppos) + minetest.chat_send_all ("Placed MTS at " .. ps, false) + + if (pname ~= nil) and (pbase ~= nil) and + (pboth ~= nil) and pboth then + worldedit.loadwe (pname, pbase) + minetest.chat_send_all ("Placed WE at " .. ps, false) + end + end + end + + end_of_emerge ("SET or PLACE") +end + +-- =================================================================== + +-- Copies a region along `axis` by `amount` nodes. +-- @param pos1 +-- @param pos2 +-- @param axis Axis ("x", "y", or "z") +-- @param amount +-- @return The number of nodes copied. + +function worldedit.old_copy (xpos1, xpos2, axis, amount) + + local pos1, pos2 = worldedit.sort_pos (xpos1, xpos2) + worldedit.keep_loaded (pos1, pos2) + + local get_node, get_meta, set_node = minetest.get_node, + minetest.get_meta, minetest.set_node + -- Copy things backwards when negative to avoid corruption. + -- FIXME: Lots of code duplication here. + + if amount < 0 then + local pos = {} + pos.x = pos1.x + + while pos.x <= pos2.x do + pos.y = pos1.y + + while pos.y <= pos2.y do + pos.z = pos1.z + + while pos.z <= pos2.z do + + -- Obtain current node + local node = get_node (pos) + + -- Get meta of current node + local meta = get_meta (pos):to_table() + + -- Store current position + local value = pos [axis] + + -- Move along axis + pos[axis] = value + amount + + -- Copy node to new position + set_node (pos, node) + + -- Set metadata of new node + get_meta (pos):from_table (meta) + + -- Restore old position + pos [axis] = value + + pos.z = pos.z + 1 + end + + pos.y = pos.y + 1 + end + + pos.x = pos.x + 1 + end + else + local pos = {} + pos.x = pos2.x + + while pos.x >= pos1.x do + pos.y = pos2.y + + while pos.y >= pos1.y do + pos.z = pos2.z + + while pos.z >= pos1.z do + + -- Obtain current node + local node = get_node (pos) + + -- Get meta of current node + local meta = get_meta (pos):to_table() + + -- Store current position + local value = pos [axis] + + -- Move along axis + pos[axis] = value + amount + + -- Copy node to new position + set_node (pos, node) + + -- Set metadata of new node + get_meta (pos):from_table (meta) + + -- Restore old position + pos [axis] = value + + pos.z = pos.z - 1 + end + + pos.y = pos.y - 1 + end + + pos.x = pos.x - 1 + end + end + + return worldedit.volume (pos1, pos2) +end + +-- =================================================================== + +function worldedit.wait_copy (p) + worldedit.copy (p.xpos1, p.xpos2, p.axis, p.amount) + return 0 +end + +function worldedit.wait_emerge_area (p) + worldedit.emerge_area (p.xpos1, p.xpos2) + return 0 +end + +function worldedit.wait_move (p) + worldedit.move (p.xpos1, p.xpos2, p.axis, p.amount) + return 0 +end + +function worldedit.wait_set (p) + worldedit.set (p.xpos1, p.xpos2, p.node_names) + return 0 +end + +-- =================================================================== + +function worldedit.pop_queue() + if #worldedit.cmd_queue == 0 then return 0 end + if worldedit.emerge_busy == 1 then + deblog ("pop_queue: WE is busy, waiting 1 second") + minetest.after (1, worldedit.pop_queue) + return 0 + end + + deblog ("pop_queue: WE is free, running next command") + local qe = table.remove (worldedit.cmd_queue, 1) + qe.func (qe.param) + return 0 +end + +-- =================================================================== + +function worldedit.copy (xpos1, xpos2, axis, amount) + if worldedit.emerge_busy == 1 then + deblog ("worldedit.copy called but WE is busy") + else + deblog ("worldedit.copy called and WE is free") + end + + local pos1, pos2 = worldedit.sort_pos (xpos1, xpos2) + + if worldedit.volume (pos1, pos2) > 1500000 then + minetest.chat_send_all ("//copy is limited to 1.5M nodes", + false) + return 0 + end + + if worldedit.emerge_busy == 1 then + if worldedit.use_queue == 0 then + minetest.chat_send_all ("A previous //operation is busy") + else + local qe = { + func = worldedit.wait_copy , + param = { + xpos1=xpos1, xpos2=xpos2, axis=axis, amount=amount + } + } + + deblog ("queuing for later: copy " .. + ocutil.pos_to_str (xpos1) .. " " .. + ocutil.pos_to_str (xpos2) .. " " .. + axis .. " " .. amount) + + qe = ocutil.clone_table (qe) + table.insert (worldedit.cmd_queue, qe) + minetest.after (1, worldedit.pop_queue) + end + return 0 + else + deblog ("WE is free, proceeding: copy " .. + ocutil.pos_to_str (xpos1) .. " " .. + ocutil.pos_to_str (xpos2) .. " " .. + axis .. " " .. amount) + end + +-- =================================================================== + + local newpos1 = { x=pos1.x, y=pos1.y, z=pos1.z } + local newpos2 = { x=pos2.x, y=pos2.y, z=pos2.z } + + newpos1 [axis] = newpos1 [axis] + amount + newpos2 [axis] = newpos2 [axis] + amount + +-- =================================================================== + + local os1 = minetest.pos_to_string (pos1) + local os2 = minetest.pos_to_string (pos2) + + local ps1 = minetest.pos_to_string (newpos1) + local ps2 = minetest.pos_to_string (newpos2) + +-- =================================================================== + + if not coderedit_disable_verbose then + minetest.chat_send_all ("//copy " .. + "Source: " .. os1 .. " " .. os2 .. " " .. + "Axis: " .. axis .. " " .. + "Amount: " .. amount) + minetest.chat_send_all ("//copy Destin:" .. + ps1 .. " " .. ps2) + end + + deblog ("//copy " .. + "Source: " .. os1 .. " " .. os2 .. " " .. + "Axis: " .. axis .. " " .. + "Amount: " .. amount) + deblog ("//copy Destin: " .. ps1 .. " " .. ps2) + +-- =================================================================== + + local x1min, x1max = sort2num (pos1.x, pos2.x) + local y1min, y1max = sort2num (pos1.y, pos2.y) + local z1min, z1max = sort2num (pos1.z, pos2.z) + + local x2min, x2max = sort2num (newpos1.x, newpos2.x) + local y2min, y2max = sort2num (newpos1.y, newpos2.y) + local z2min, z2max = sort2num (newpos1.z, newpos2.z) + + local overlap = true + if x1max < x2min or x2max < x1min or + y1max < y2min or y2max < y1min or + z1max < z2min or z2max < z1min then + overlap = false + end + + if overlap then + minetest.chat_send_all ("Source and dest regions" .. + " overlap, there may be dark areas") + end + +-- =================================================================== + + worldedit.emerge_busy = 1 + if collectgarbage ("count") > 307200 then collectgarbage() end + + local param = { + pos1=pos1 , pos2=pos2 , axis=axis , amount=amount , + overlap=overlap , + } + + minetest.emerge_area (newpos1, newpos2, + emerge_callback_copy, param) + + return end_of_start_emerge (pos1, pos2, "COPY") +end + +-- =================================================================== + +function worldedit.emerge_area (xpos1, xpos2) + + if worldedit.emerge_busy == 1 then + if worldedit.use_queue == 0 then + minetest.chat_send_all ("A previous //operation is busy") + else + local qe = { + func = worldedit.wait_emerge_area , + param = { xpos1=xpos1, xpos2=xpos2 } , + } + + qe = ocutil.clone_table (qe) + table.insert (worldedit.cmd_queue, qe) + minetest.after (1, worldedit.pop_queue) + end + return 0 + end + + worldedit.emerge_busy = 1 + local pos1, pos2 = worldedit.sort_pos (xpos1, xpos2) + if collectgarbage ("count") > 307200 then collectgarbage() end + local param = { pos1=pos1, pos2=pos2 } + + minetest.emerge_area (pos1, pos2, emerge_callback_emerge, param) + return end_of_start_emerge (pos1, pos2, "EMERGE") +end + +-- =================================================================== + +-- Replaces all instances of "search_node" with "replace_node" in a +-- region. When "inverse" is "true", replaces all instances that are +-- NOT "search_node". +-- @return The number of nodes replaced. + +function worldedit.replace (pos1, pos2, search_node, + replace_node, inverse) + + pos1, pos2 = worldedit.sort_pos (pos1, pos2) + local manip, area = mh.init (pos1, pos2) + local data = manip:get_data() + + local search_id = ocutil.get_content_id (search_node ) + if search_id == nil then + minetest.chat_send_all ("Error: Unknown node " .. search_node ) + return + end + + local replace_id = ocutil.get_content_id (replace_node) + if replace_id == nil then + minetest.chat_send_all ("Error: Unknown node " .. replace_node ) + return + end + + local count = 0 + + --- TODO: This could be shortened by checking `inverse` in the loop, + -- but that would have a speed penalty. Is the penalty big enough + -- to matter? + + if not inverse then + for i in area:iterp (pos1, pos2) do + if data [i] == search_id then + data [i] = replace_id + count = count + 1 + end + end + else + for i in area:iterp (pos1, pos2) do + if data [i] ~= search_id then + data [i] = replace_id + count = count + 1 + end + end + end + + mh.finish (manip, data) + return count +end + +-- =================================================================== + +-- Sets a region to node_names. +-- @param pos1 +-- @param pos2 +-- @param node_names Node name or list of node names. +-- @return The number of nodes set. + +function worldedit.old_set (xpos1, xpos2, node_names) + + local pos1, pos2 + pos1, pos2 = worldedit.sort_pos (xpos1, xpos2) + + local xdelta = pos2.x - pos1.x + local ydelta = pos2.y - pos1.y + local zdelta = pos2.z - pos1.z + + if xdelta >= 30 or xdelta <= -30 then + local m1 = idiv (xdelta, 2) + local m2 = xdelta - m1 + local posa = { x=pos1.x+m1, y=pos2.y, z=pos2.z } + local posb = { x=pos1.x+m2, y=pos1.y, z=pos1.z } + worldedit.old_set (pos1, posa, node_names) + worldedit.old_set (posb, pos2, node_names) + return worldedit.volume (pos1, pos2) + end + + if ydelta >= 30 or ydelta <= -30 then + local m1 = idiv (ydelta, 2) + local m2 = ydelta - m1 + local posa = { x=pos2.x, y=pos1.y+m1, z=pos2.z } + local posb = { x=pos1.x, y=pos1.y+m2, z=pos1.z } + worldedit.old_set (pos1, posa, node_names) + worldedit.old_set (posb, pos2, node_names) + return worldedit.volume (pos1, pos2) + end + + if zdelta >= 30 or zdelta <= -30 then + local m1 = idiv (zdelta, 2) + local m2 = zdelta - m1 + local posa = { x=pos2.x, y=pos2.y, z=pos1.z+m1 } + local posb = { x=pos1.x, y=pos1.y, z=pos1.z+m2 } + worldedit.old_set (pos1, posa, node_names) + worldedit.old_set (posb, pos2, node_names) + return worldedit.volume (pos1, pos2) + end + + local manip, area = mh.init (pos1, pos2) + manip:update_map() + + local data = mh.get_empty_data (area) + if collectgarbage ("count") > 307200 then collectgarbage() end + + if type (node_names) == "string" then -- Only one type of node + if node_names ~= "default:emerge" then + local id = ocutil.get_content_id (node_names) + if id == nil then + minetest.chat_send_all ("Error: Unknown node " .. node_names) + return + end + + -- Fill area with node + for i in area:iterp (pos1, pos2) do + data [i] = id + end + end + else -- Several types of nodes specified + local node_ids = {} + for i, v in ipairs (node_names) do + node_ids [i] = ocutil.get_content_id (v) + if node_ids [i] == nil then + minetest.chat_send_all ("Error: Unknown node " .. v) + return + end + end + -- Fill area randomly with nodes + local id_count, rand = #node_ids, math.random + for i in area:iterp (pos1, pos2) do + data [i] = node_ids [rand (id_count)] + end + end + + if collectgarbage ("count") > 307200 then collectgarbage() end + manip:set_data (data) + data = {} + manip:update_liquids() + manip:write_to_map() + manip:update_map() + + if collectgarbage ("count") > 307200 then collectgarbage() end + return worldedit.volume (pos1, pos2) +end + +-- =================================================================== + +function worldedit.set (xpos1, xpos2, node_names) + + if worldedit.emerge_busy == 1 then + if worldedit.use_queue == 0 then + minetest.chat_send_all ("A previous //operation is busy") + else + local qe = { + func = worldedit.wait_set , + param = { + xpos1=xpos1, xpos2=xpos2, node_names=node_names + } + } + + qe = ocutil.clone_table (qe) + table.insert (worldedit.cmd_queue, qe) + minetest.after (1, worldedit.pop_queue) + end + return 0 + end + + worldedit.emerge_busy = 1 + local pos1, pos2 = worldedit.sort_pos (xpos1, xpos2) + if collectgarbage ("count") > 307200 then collectgarbage() end + local vol = worldedit.volume (pos1, pos2) + + if type (node_names) ~= "string" or + node_names ~= "default:emerge" then + if (vol > 190000000) then + worldedit.emerge_busy = 0 + minetest.chat_send_all ("//set is limited to 190M nodes") + return 0 + end + end + + if not coderedit_disable_verbose then + minetest.chat_send_all ("Starting set of " .. vol .. + " node(s)") + end + + local param = { pos1=pos1, pos2=pos2, node_names=node_names } + minetest.emerge_area (pos1, pos2, emerge_callback_set, param) + return end_of_start_emerge (pos1, pos2, "SET") +end + +-- =================================================================== + +--- Sets param2 of a region. +-- @param pos1 +-- @param pos2 +-- @param param2 Value of param2 to set +-- @return The number of nodes set. + +function worldedit.set_param2 (pos1, pos2, param2) + + pos1, pos2 = worldedit.sort_pos (pos1, pos2) + + local manip, area = mh.init (pos1, pos2) + local param2_data = manip:get_param2_data() + + -- Set param2 for every node + for i in area:iterp (pos1, pos2) do + param2_data [i] = param2 + end + + -- Update map + manip:set_param2_data (param2_data) + manip:write_to_map() + manip:update_map() + + return worldedit.volume (pos1, pos2) +end + +-- =================================================================== + +--- Duplicates a region `amount` times with offset vector `direction`. +-- Stacking is spread across server steps, one copy per step. +-- @return The number of nodes stacked. + +function worldedit.stack2 (pos1, pos2, direction, amount, finished) + + local i = 0 + local translated = {x=0, y=0, z=0} + local function next_one() + if i < amount then + i = i + 1 + translated.x = translated.x + direction.x + translated.y = translated.y + direction.y + translated.z = translated.z + direction.z + + worldedit.copy2 (pos1, pos2, translated) + minetest.after (0, next_one) + else + if finished then + finished() + end + end + end + + next_one() + return worldedit.volume (pos1, pos2) * amount +end + +-- =================================================================== + +--- Copies a region by offset vector `off`. +-- @param pos1 +-- @param pos2 +-- @param off +-- @return The number of nodes copied. + +function worldedit.copy2 (pos1, pos2, off) + + local pos1, pos2 = worldedit.sort_pos (pos1, pos2) + worldedit.keep_loaded (pos1, pos2) + + local get_node, get_meta, set_node = minetest.get_node, + minetest.get_meta, minetest.set_node + + local pos = {} + pos.x = pos2.x + while pos.x >= pos1.x do + pos.y = pos2.y + while pos.y >= pos1.y do + pos.z = pos2.z + while pos.z >= pos1.z do + local node = get_node(pos) -- Obtain current node + local meta = get_meta(pos):to_table() -- Get meta of current node + local newpos = vector.add(pos, off) -- Calculate new position + set_node(newpos, node) -- Copy node to new position + get_meta(newpos):from_table(meta) -- Set metadata of new node + + pos.z = pos.z - 1 + end + + pos.y = pos.y - 1 + end + + pos.x = pos.x - 1 + end + + return worldedit.volume (pos1, pos2) +end + +-- =================================================================== + +-- Moves a region along `axis` by `amount` nodes. +-- @return The number of nodes moved. + +function worldedit.old_move (pos1, pos2, axis, amount) + + local pos1, pos2 = worldedit.sort_pos (pos1, pos2) + worldedit.keep_loaded (pos1, pos2) + + --- TODO: Move slice by slice using schematic method in the move axis + -- and transfer metadata in separate loop (and if the amount is + -- greater than the length in the axis, copy whole thing at a time and + -- erase original after, using schematic method). + + local get_node, get_meta, set_node, remove_node = minetest.get_node, + minetest.get_meta, minetest.set_node, minetest.remove_node + -- Copy things backwards when negative to avoid corruption. + --- FIXME: Lots of code duplication here. + + if amount < 0 then + local pos = {} + pos.x = pos1.x + + while pos.x <= pos2.x do + pos.y = pos1.y + + while pos.y <= pos2.y do + pos.z = pos1.z + + while pos.z <= pos2.z do + + -- Obtain current node + local node = get_node (pos) + + -- Get metadata of current node + local meta = get_meta (pos):to_table() + + -- Remove current node + remove_node (pos) + + -- Store current position + local value = pos [axis] + + -- Move along axis + pos[axis] = value + amount + + -- Move node to new position + set_node (pos, node) + + -- Set metadata of new node + get_meta (pos):from_table (meta) + + -- Restore old position + pos [axis] = value + + pos.z = pos.z + 1 + end + + pos.y = pos.y + 1 + end + + pos.x = pos.x + 1 + end + else + local pos = {} + pos.x = pos2.x + + while pos.x >= pos1.x do + pos.y = pos2.y + + while pos.y >= pos1.y do + pos.z = pos2.z + + while pos.z >= pos1.z do + + -- Obtain current node + local node = get_node (pos) + + -- Get metadata of current node + local meta = get_meta (pos):to_table() + + -- Remove current node + remove_node (pos) + + -- Store current position + local value = pos [axis] + + -- Move along axis + pos[axis] = value + amount + + -- Move node to new position + set_node (pos, node) + + -- Set metadata of new node + get_meta (pos):from_table (meta) + + -- Restore old position + pos [axis] = value + + pos.z = pos.z - 1 + end + + pos.y = pos.y - 1 + end + + pos.x = pos.x - 1 + end + end + + return worldedit.volume (pos1, pos2) +end + +-- =================================================================== + +function worldedit.move (xpos1, xpos2, axis, amount) + + if worldedit.emerge_busy == 1 then + deblog ("worldedit.move called but WE is busy") + else + deblog ("worldedit.move called and WE is free") + end + local pos1, pos2 = worldedit.sort_pos (xpos1, xpos2) + + if worldedit.volume (pos1, pos2) > 1500000 then + minetest.chat_send_all ("//move is limited to 1.5M nodes", + false) + return 0 + end + + if worldedit.emerge_busy == 1 then + if worldedit.use_queue == 0 then + minetest.chat_send_all ("A previous //operation is busy") + else + local qe = { + func = worldedit.wait_move , + param = { + xpos1=xpos1, xpos2=xpos2, axis=axis, amount=amount + } + } + + deblog ("queuing for later: move " .. + ocutil.pos_to_str (xpos1) .. " " .. + ocutil.pos_to_str (xpos2) .. " " .. + axis .. " " .. amount) + + qe = ocutil.clone_table (qe) + table.insert (worldedit.cmd_queue, qe) + minetest.after (1, worldedit.pop_queue) + end + return 0 + else + deblog ("WE is free, proceeding: move " .. + ocutil.pos_to_str (xpos1) .. " " .. + ocutil.pos_to_str (xpos2) .. " " .. + axis .. " " .. + amount) + end + +-- =================================================================== + + local newpos1 = { x=pos1.x, y=pos1.y, z=pos1.z } + local newpos2 = { x=pos2.x, y=pos2.y, z=pos2.z } + + newpos1 [axis] = newpos1 [axis] + amount + newpos2 [axis] = newpos2 [axis] + amount + +-- =================================================================== + + local os1 = minetest.pos_to_string (pos1) + local os2 = minetest.pos_to_string (pos2) + + local ps1 = minetest.pos_to_string (newpos1) + local ps2 = minetest.pos_to_string (newpos2) + +-- =================================================================== + + if not coderedit_disable_verbose then + minetest.chat_send_all ("//move " .. + "Source: " .. os1 .. " " .. os2 .. " " .. + "Axis: " .. axis .. " " .. + "Amount: " .. amount) + minetest.chat_send_all ("//move Destin:" .. + ps1 .. " " .. ps2) + end + + deblog ("//move " .. + "Source: " .. os1 .. " " .. os2 .. " " .. + "Axis: " .. axis .. " " .. + "Amount: " .. amount) + deblog ("//move Destin: " .. ps1 .. " " .. ps2) + +-- =================================================================== + + local x1min, x1max = sort2num (pos1.x, pos2.x) + local y1min, y1max = sort2num (pos1.y, pos2.y) + local z1min, z1max = sort2num (pos1.z, pos2.z) + + local x2min, x2max = sort2num (newpos1.x, newpos2.x) + local y2min, y2max = sort2num (newpos1.y, newpos2.y) + local z2min, z2max = sort2num (newpos1.z, newpos2.z) + + local overlap = true + if x1max < x2min or x2max < x1min or + y1max < y2min or y2max < y1min or + z1max < z2min or z2max < z1min then + overlap = false + end + + if overlap then + minetest.chat_send_all ("Source and dest regions" .. + " overlap, there may be dark areas") + end + +-- =================================================================== + + worldedit.emerge_busy = 1 + if collectgarbage ("count") > 307200 then collectgarbage() end + + local param = { + pos1=pos1 , pos2=pos2 , axis=axis , amount=amount , + overlap=overlap , + } + + minetest.emerge_area (newpos1, newpos2, + emerge_callback_move, param) + + return end_of_start_emerge (pos1, pos2, "MOVE") +end + +-- =================================================================== + +-- Duplicates a region along `axis` `amount` times. +-- Stacking is spread across server steps, one copy per step. +-- @param pos1 +-- @param pos2 +-- @param axis Axis direction, "x", "y", or "z". +-- @param count +-- @return The number of nodes stacked. + +function worldedit.stack (pos1, pos2, axis, count) + + local pos1, pos2 = worldedit.sort_pos(pos1, pos2) + local length = pos2[axis] - pos1[axis] + 1 + if count < 0 then + count = -count + length = -length + end + local amount = 0 + local copy = worldedit.copy + local i = 1 + local function next_one() + if i <= count then + i = i + 1 + amount = amount + length + copy(pos1, pos2, axis, amount) + minetest.after(0, next_one) + end + end + next_one() + return worldedit.volume(pos1, pos2) * count +end + +-- =================================================================== + +--- Stretches a region by a factor of positive integers along the X, Y, and Z +-- axes, respectively, with `pos1` as the origin. +-- @param pos1 +-- @param pos2 +-- @param stretch_x Amount to stretch along X axis. +-- @param stretch_y Amount to stretch along Y axis. +-- @param stretch_z Amount to stretch along Z axis. +-- @return The number of nodes scaled. +-- @return The new scaled position 1. +-- @return The new scaled position 2. + +function worldedit.stretch (pos1, pos2, stretch_x, stretch_y, stretch_z) + + local pos1, pos2 = worldedit.sort_pos(pos1, pos2) + + -- Prepare schematic of large node + local get_node, get_meta, place_schematic = minetest.get_node, + minetest.get_meta, minetest.place_schematic + local placeholder_node = {name="", param1=255, param2=0} + local nodes = {} + for i = 1, stretch_x * stretch_y * stretch_z do + nodes[i] = placeholder_node + end + + local schematic = {size={x=stretch_x, y=stretch_y, z=stretch_z}, + data=nodes} + + local size_x, size_y, size_z = stretch_x - 1, + stretch_y - 1, stretch_z - 1 + + local new_pos2 = { + x = pos1.x + (pos2.x - pos1.x) * stretch_x + size_x, + y = pos1.y + (pos2.y - pos1.y) * stretch_y + size_y, + z = pos1.z + (pos2.z - pos1.z) * stretch_z + size_z, + } + worldedit.keep_loaded(pos1, new_pos2) + + local pos = {x=pos2.x, y=0, z=0} + local big_pos = {x=0, y=0, z=0} + while pos.x >= pos1.x do + pos.y = pos2.y + while pos.y >= pos1.y do + pos.z = pos2.z + while pos.z >= pos1.z do + local node = get_node(pos) -- Get current node + local meta = get_meta(pos):to_table() -- Get meta of current node + + -- Calculate far corner of the big node + local pos_x = pos1.x + (pos.x - pos1.x) * stretch_x + local pos_y = pos1.y + (pos.y - pos1.y) * stretch_y + local pos_z = pos1.z + (pos.z - pos1.z) * stretch_z + + -- Create large node + placeholder_node.name = node.name + placeholder_node.param2 = node.param2 + big_pos.x, big_pos.y, big_pos.z = pos_x, pos_y, pos_z + place_schematic(big_pos, schematic) + + -- Fill in large node meta + if next(meta.fields) ~= nil or next(meta.inventory) ~= nil then + -- Node has meta fields + for x = 0, size_x do + for y = 0, size_y do + for z = 0, size_z do + big_pos.x = pos_x + x + big_pos.y = pos_y + y + big_pos.z = pos_z + z + -- Set metadata of new node + get_meta(big_pos):from_table(meta) + end + end + end + end + pos.z = pos.z - 1 + end + pos.y = pos.y - 1 + end + pos.x = pos.x - 1 + end + return worldedit.volume(pos1, pos2) * stretch_x * stretch_y * stretch_z, pos1, new_pos2 +end + +-- =================================================================== + +--- Transposes a region between two axes. +-- @return The number of nodes transposed. +-- @return The new transposed position 1. +-- @return The new transposed position 2. + +function worldedit.transpose(pos1, pos2, axis1, axis2) + local pos1, pos2 = worldedit.sort_pos(pos1, pos2) + + local compare + local extent1, extent2 = pos2[axis1] - pos1[axis1], pos2[axis2] - pos1[axis2] + + if extent1 > extent2 then + compare = function(extent1, extent2) + return extent1 > extent2 + end + else + compare = function(extent1, extent2) + return extent1 < extent2 + end + end + + -- Calculate the new position 2 after transposition + local new_pos2 = {x=pos2.x, y=pos2.y, z=pos2.z} + new_pos2[axis1] = pos1[axis1] + extent2 + new_pos2[axis2] = pos1[axis2] + extent1 + + local upper_bound = {x=pos2.x, y=pos2.y, z=pos2.z} + if upper_bound[axis1] < new_pos2[axis1] then upper_bound[axis1] = new_pos2[axis1] end + if upper_bound[axis2] < new_pos2[axis2] then upper_bound[axis2] = new_pos2[axis2] end + worldedit.keep_loaded(pos1, upper_bound) + + local pos = {x=pos1.x, y=0, z=0} + local get_node, get_meta, set_node = minetest.get_node, + minetest.get_meta, minetest.set_node + while pos.x <= pos2.x do + pos.y = pos1.y + while pos.y <= pos2.y do + pos.z = pos1.z + while pos.z <= pos2.z do + local extent1, extent2 = pos[axis1] - pos1[axis1], pos[axis2] - pos1[axis2] + if compare(extent1, extent2) then -- Transpose only if below the diagonal + local node1 = get_node(pos) + local meta1 = get_meta(pos):to_table() + local value1, value2 = pos[axis1], pos[axis2] -- Save position values + pos[axis1], pos[axis2] = pos1[axis1] + extent2, pos1[axis2] + extent1 -- Swap axis extents + local node2 = get_node(pos) + local meta2 = get_meta(pos):to_table() + set_node(pos, node1) + get_meta(pos):from_table(meta1) + pos[axis1], pos[axis2] = value1, value2 -- Restore position values + set_node(pos, node2) + get_meta(pos):from_table(meta2) + end + pos.z = pos.z + 1 + end + pos.y = pos.y + 1 + end + pos.x = pos.x + 1 + end + return worldedit.volume(pos1, pos2), pos1, new_pos2 +end + +-- =================================================================== + +--- Flips a region along `axis`. +-- @return The number of nodes flipped. + +function worldedit.flip(pos1, pos2, axis) + local pos1, pos2 = worldedit.sort_pos(pos1, pos2) + + worldedit.keep_loaded(pos1, pos2) + + --- TODO: Flip the region slice by slice along the flip axis using schematic method. + local pos = {x=pos1.x, y=0, z=0} + local start = pos1[axis] + pos2[axis] + pos2[axis] = pos1[axis] + math.floor((pos2[axis] - pos1[axis]) / 2) + local get_node, get_meta, set_node = minetest.get_node, + minetest.get_meta, minetest.set_node + while pos.x <= pos2.x do + pos.y = pos1.y + while pos.y <= pos2.y do + pos.z = pos1.z + while pos.z <= pos2.z do + local node1 = get_node(pos) + local meta1 = get_meta(pos):to_table() + local value = pos[axis] -- Save position + pos[axis] = start - value -- Shift position + local node2 = get_node(pos) + local meta2 = get_meta(pos):to_table() + set_node(pos, node1) + get_meta(pos):from_table(meta1) + pos[axis] = value -- Restore position + set_node(pos, node2) + get_meta(pos):from_table(meta2) + pos.z = pos.z + 1 + end + pos.y = pos.y + 1 + end + pos.x = pos.x + 1 + end + return worldedit.volume(pos1, pos2) +end + +-- =================================================================== + +--- Rotates a region clockwise around an axis. +-- @param pos1 +-- @param pos2 +-- @param axis Axis ("x", "y", or "z"). +-- @param angle Angle in degrees (90 degree increments only). +-- @return The number of nodes rotated. +-- @return The new first position. +-- @return The new second position. + +function worldedit.rotate(pos1, pos2, axis, angle) + local pos1, pos2 = worldedit.sort_pos(pos1, pos2) + + if worldedit.volume (pos1, pos2) > 1000000 then + minetest.chat_send_all ("//rotate is limited to 1M nodes", + false) + return + end + + local other1, other2 = worldedit.get_axis_others(axis) + angle = angle % 360 + + local count + if angle == 90 then + worldedit.flip(pos1, pos2, other1) + count, pos1, pos2 = worldedit.transpose(pos1, pos2, other1, other2) + elseif angle == 180 then + worldedit.flip(pos1, pos2, other1) + count = worldedit.flip(pos1, pos2, other2) + elseif angle == 270 then + worldedit.flip(pos1, pos2, other2) + count, pos1, pos2 = worldedit.transpose(pos1, pos2, other1, other2) + else + error("Only 90 degree increments are supported!") + end + return count, pos1, pos2 +end + +-- =================================================================== + +-- Rotates all oriented nodes in a region clockwise around the Y axis. +-- @param pos1 +-- @param pos2 +-- @param angle Angle in degrees (90 degree increments only). +-- @return The number of nodes oriented. +-- TODO: Support 6D facedir rotation along arbitrary axis. + +function worldedit.orient(pos1, pos2, angle) + local pos1, pos2 = worldedit.sort_pos(pos1, pos2) + + if worldedit.volume (pos1, pos2) > 1000000 then + minetest.chat_send_all ("//orient is limited to 1M nodes", + false) + return + end + + local registered_nodes = minetest.registered_nodes + + local wallmounted = { + [90] = {[0]=0, 1, 5, 4, 2, 3}, + [180] = {[0]=0, 1, 3, 2, 5, 4}, + [270] = {[0]=0, 1, 4, 5, 3, 2} + } + local facedir = { + [90] = {[0]=1, 2, 3, 0}, + [180] = {[0]=2, 3, 0, 1}, + [270] = {[0]=3, 0, 1, 2} + } + + angle = angle % 360 + if angle == 0 then + return 0 + end + if angle % 90 ~= 0 then + error("Only 90 degree increments are supported!") + end + local wallmounted_substitution = wallmounted[angle] + local facedir_substitution = facedir[angle] + + worldedit.keep_loaded(pos1, pos2) + + local count = 0 + local set_node, get_node, get_meta, swap_node = minetest.set_node, + minetest.get_node, minetest.get_meta, minetest.swap_node + local pos = {x=pos1.x, y=0, z=0} + while pos.x <= pos2.x do + pos.y = pos1.y + while pos.y <= pos2.y do + pos.z = pos1.z + while pos.z <= pos2.z do + local node = get_node(pos) + local def = registered_nodes[node.name] + if def then + if def.paramtype2 == "wallmounted" then + node.param2 = wallmounted_substitution[node.param2] + local meta = get_meta(pos):to_table() + set_node(pos, node) + get_meta(pos):from_table(meta) + count = count + 1 + elseif def.paramtype2 == "facedir" then + node.param2 = facedir_substitution[node.param2] + local meta = get_meta(pos):to_table() + set_node(pos, node) + get_meta(pos):from_table(meta) + count = count + 1 + end + end + pos.z = pos.z + 1 + end + pos.y = pos.y + 1 + end + pos.x = pos.x + 1 + end + return count +end + +-- =================================================================== + +-- Attempts to fix the lighting in a region. +-- @return The number of nodes updated. + +function worldedit.fixlight(pos1, pos2) + local pos1, pos2 = worldedit.sort_pos (pos1, pos2) + + local epos1 = { x=pos1.x-32, y=pos1.y-32, z=pos1.z-32 } + local epos2 = { x=pos2.x+32, y=pos2.y+32, z=pos2.z+32 } + vm = minetest.get_voxel_manip() + vm:read_from_map (epos1, epos2) + vm:set_lighting ({day=15,night=4}, epos1, epos2) + vm:calc_lighting (epos1, epos2) + vm:update_liquids() + vm:write_to_map() + + return worldedit.volume (pos1, pos2) +end + +-- =================================================================== + +-- Clears all objects in a region. +-- @return The number of objects cleared. + +function worldedit.clear_objects(pos1, pos2) + pos1, pos2 = worldedit.sort_pos(pos1, pos2) + + worldedit.keep_loaded(pos1, pos2) + + -- Offset positions to include full nodes (positions are in the center of nodes) + local pos1x, pos1y, pos1z = pos1.x - 0.5, pos1.y - 0.5, pos1.z - 0.5 + local pos2x, pos2y, pos2z = pos2.x + 0.5, pos2.y + 0.5, pos2.z + 0.5 + + -- Center of region + local center = { + x = pos1x + ((pos2x - pos1x) / 2), + y = pos1y + ((pos2y - pos1y) / 2), + z = pos1z + ((pos2z - pos1z) / 2) + } + -- Bounding sphere radius + local radius = math.sqrt( + (center.x - pos1x) ^ 2 + + (center.y - pos1y) ^ 2 + + (center.z - pos1z) ^ 2) + + local count = 0 + for _, obj in pairs (minetest.get_objects_inside_radius (center, radius)) do + + local entity = obj:get_luaentity() + -- Avoid players and WorldEdit entities + if not obj:is_player() and (not entity or + not entity.name:find("^worldedit:")) then + local pos = obj:getpos() + if pos.x >= pos1x and pos.x <= pos2x and + pos.y >= pos1y and pos.y <= pos2y and + pos.z >= pos1z and pos.z <= pos2z then + -- Inside region + obj:remove() + count = count + 1 + end + end + end + return count +end