{"id":65,"date":"2019-01-19T15:52:23","date_gmt":"2019-01-19T15:52:23","guid":{"rendered":"http:\/\/evertechsandbox.com\/?p=65"},"modified":"2020-12-27T16:57:41","modified_gmt":"2020-12-27T16:57:41","slug":"how-to-lua","status":"publish","type":"post","link":"http:\/\/evertechsandbox.com\/?p=65","title":{"rendered":"How to lua"},"content":{"rendered":"<h4>Up-to-date docs are here:<\/h4>\n<h4><a href=\"http:\/\/vitsum.ml\/evertech\/docs\/#\/\">http:\/\/vitsum.ml\/evertech\/docs\/#\/<\/a><\/h4>\n<h2><\/h2>\n<h2>Introduction<\/h2>\n<p>Finally we now have support for lua scripting in our lovely game! So now you can make mods which are not just changed 3d model&#8230; your mods now can do stuff!<\/p>\n<p>Available since version 0.18.*<\/p>\n<h2>Getting Started<\/h2>\n<p>Before we start you need to read <a href=\"http:\/\/evertechsandbox.com\/?p=42\">how to make a simple mod<\/a>. If you already can make a simple mod you can continue reading this article.<\/p>\n<p>To add a script to your mod you need to add a .lua file to your mods directory and reference it in your info.json file.<\/p>\n<p><a href=\"http:\/\/evertechsandbox.com\/wp-content\/uploads\/2019\/01\/mod-script.png\"><img decoding=\"async\" loading=\"lazy\" class=\"alignnone size-full wp-image-66\" src=\"http:\/\/evertechsandbox.com\/wp-content\/uploads\/2019\/01\/mod-script.png\" alt=\"\" width=\"587\" height=\"426\" \/><\/a><\/p>\n<p><!--more--><\/p>\n<p>You can name your script however you want. I recommend creating a folder &#8220;scripts&#8221; and put all your scripts there just dont forget to add the folder name in the path like &#8220;scripts\/script.lua&#8221;<\/p>\n<h3>Scripting<\/h3>\n<p>And now you want to know what you can write to a <em>script.lua<\/em>.<\/p>\n<p><a href=\"http:\/\/evertechsandbox.com\/wp-content\/uploads\/2019\/01\/mod-script-functions.png\"><img decoding=\"async\" loading=\"lazy\" class=\"alignnone size-full wp-image-67\" src=\"http:\/\/evertechsandbox.com\/wp-content\/uploads\/2019\/01\/mod-script-functions.png\" alt=\"\" width=\"264\" height=\"242\" \/><\/a><\/p>\n<p>In your script you can define functions with these names and they will be called by Evertech Sandbox game at some events.<\/p>\n<p>onPlace will be called when the player placed your modded item.<\/p>\n<p>start will be called after initializing the object, it can be called after you placed an item or after the level loaded from a save file.<\/p>\n<p>update will be called every frame<\/p>\n<p>fixedUpdate will be called 50 times per second and is used for things related to physics<\/p>\n<h3>Hello world<\/h3>\n<p>Let&#8217;s write a hello world program.<\/p>\n<p><a href=\"http:\/\/evertechsandbox.com\/wp-content\/uploads\/2019\/01\/helloworld.png\"><img decoding=\"async\" loading=\"lazy\" class=\"alignnone size-full wp-image-68\" src=\"http:\/\/evertechsandbox.com\/wp-content\/uploads\/2019\/01\/helloworld.png\" alt=\"\" width=\"236\" height=\"53\" \/><\/a><\/p>\n<p>You see, it is very small&#8230; It just writes a &#8220;Hello world&#8221; string to a console. But wait, what is console?<\/p>\n<p>You can activate a console if you go to a pause menu in a game, then go to settings -&gt; lua settings and click the &#8220;Show Console&#8221; button. Wait a little bit while it loads itself, then you can close it and since this moment it will log all messages from lua programs.<\/p>\n<p>Now if you created your hello world mod we can test it. Activate a console, then place your modded item somewhere. If you did everything right you should see\u00a0 &#8220;LUA: Hello world&#8221; in the console.<\/p>\n<p><a href=\"http:\/\/evertechsandbox.com\/wp-content\/uploads\/2019\/01\/console-hello-world.png\"><img decoding=\"async\" loading=\"lazy\" class=\"alignnone size-full wp-image-69\" src=\"http:\/\/evertechsandbox.com\/wp-content\/uploads\/2019\/01\/console-hello-world.png\" alt=\"\" width=\"744\" height=\"497\" \/><\/a><\/p>\n<p>By the way you can also enable debug info in (Settings -&gt; Common Settings -&gt; Show Debug Info) and you will be able to see last 5 messages from lua while you are playing.<\/p>\n<h3>Evertech Sandbox API<\/h3>\n<p>In order to do something useful we need to call Evertech Sandbox API methods. To access them we will use a &#8220;es&#8221; object.<\/p>\n<p>For example let&#8217;s create a modded item which will delete itself in 5 seconds after it was placed.<\/p>\n<p><a href=\"http:\/\/evertechsandbox.com\/wp-content\/uploads\/2019\/01\/deleteItselftExample.png\"><img decoding=\"async\" loading=\"lazy\" class=\"alignnone size-full wp-image-71\" src=\"http:\/\/evertechsandbox.com\/wp-content\/uploads\/2019\/01\/deleteItselftExample.png\" alt=\"\" width=\"329\" height=\"175\" \/><\/a><\/p>\n<p>startTime = os.time()<\/p>\n<p>Here we created a global variable named startTime and used a function time() of the os module. You can read about it <a href=\"https:\/\/www.lua.org\/pil\/22.1.html\">on official lua website<\/a>.\u00a0The\u00a0<code>time<\/code>\u00a0function, when called without arguments, returns the current date and time, coded as a number. (In most systems, that number is the number of seconds since some epoch.)<\/p>\n<p>So we stored a time when the script was initialized, then we initialized a new variable named timer with a value 5.<\/p>\n<p>In the update function which is called every frame we check how many seconds have passed since initialization of our script. And if is more than 5 seconds we destroy are item.<\/p>\n<p>To destroy an item we used &#8220;es&#8221; object, got a MultiBlock object which represents current object, and called a method of it named Destroy().<\/p>\n<p>Now if you test this mod, you can place an item and it will delete itself in 5 seconds.<\/p>\n<h3>MultiBlock<\/h3>\n<p>Now it is time to talk about MultiBlock type. In Evertech Sandbox almost every Item is a MultiBlock. It may contain several Blocks, which is also a type. More than that we have a Root type which contains Blocks and MultiBlocks&#8230;<\/p>\n<p>Root is a place where every item is stored. It is like a grid, and you can put a block in each cell. But we have Items which are bigger than 1x1x1 cube. And in order to unite the blocks of one Item we have a type MultiBlock.<\/p>\n<p><a href=\"http:\/\/evertechsandbox.com\/wp-content\/uploads\/2019\/01\/pointInRoot.png\"><img decoding=\"async\" loading=\"lazy\" class=\"alignnone size-full wp-image-72\" src=\"http:\/\/evertechsandbox.com\/wp-content\/uploads\/2019\/01\/pointInRoot.png\" alt=\"\" width=\"377\" height=\"119\" \/><\/a><\/p>\n<p>Here we created a local variable p to store a coordinates of a block of our mod. Simple blocks have only one block in it. MultiBlock type contains an array of Blocks, arrays in lua are indexed starting with 1. To access the first element of an array we use square brackets and a number 1. The Block type contains a property PointInRoot which stores a coordinate of this block in the root.<\/p>\n<p>If you created a mod with this script you can test it out. Don&#8217;t forget to activate a console first by going to settings and pressing the button &#8220;Show Console&#8221;.<\/p>\n<p>After you placed couple of modded items you should see something like this in the console .<\/p>\n<p><a href=\"http:\/\/evertechsandbox.com\/wp-content\/uploads\/2019\/01\/block-pos.png\"><img decoding=\"async\" loading=\"lazy\" class=\"alignnone size-full wp-image-73\" src=\"http:\/\/evertechsandbox.com\/wp-content\/uploads\/2019\/01\/block-pos.png\" alt=\"\" width=\"751\" height=\"503\" \/><\/a><\/p>\n<h3>The Clock<\/h3>\n<p>Now let&#8217;s just look at one example and I will try to explain what is going on here.<\/p>\n<p><a href=\"http:\/\/evertechsandbox.com\/wp-content\/uploads\/2019\/01\/clock-example.jpg\"><img decoding=\"async\" loading=\"lazy\" class=\"alignnone size-full wp-image-74\" src=\"http:\/\/evertechsandbox.com\/wp-content\/uploads\/2019\/01\/clock-example.jpg\" alt=\"\" width=\"790\" height=\"920\" \/><\/a><\/p>\n<p><a href=\"http:\/\/evertechsandbox.com\/wp-content\/uploads\/2019\/01\/clock_screen.jpg\"><img decoding=\"async\" loading=\"lazy\" class=\"alignnone size-full wp-image-75\" src=\"http:\/\/evertechsandbox.com\/wp-content\/uploads\/2019\/01\/clock_screen.jpg\" alt=\"\" width=\"672\" height=\"504\" \/><\/a><\/p>\n<p>This mod works in such a way that when you place it it will check his 6 neighbors and if it finds an item of type Sign it will write a current time to it. In order for it to work you need to place a Sign, then remove some blocks behind it if there is no place for a new one, then place a mod block so it will find a sign. And if everything is right it will show the current time.<\/p>\n<p>Now let&#8217;s see how it works.<\/p>\n<p>You can ignore an onPlace function, it left here from previous example.<\/p>\n<p>Let&#8217;s look at start function. Here we call a function findMultiBlockOfType(itemType). It is the function which we defined ourselves, it checks neighbors at left,right,top,bottom,back and forward. If it finds the item of a needed type it will return the MultiBlock, otherwise it will return nil.<\/p>\n<p>The signMB variable will store a result of findMultiBlockOfType function, MB in it&#8217;s name is because it is of type MultiBlock, but you can name your variables hovewer you want.<\/p>\n<p>Then we check if signMB not equals nil, if it is not nil, then we found a Sign and we can continue to work with it. We print a message to a console &#8216;sign found&#8217; then we store an object of type Sign to a variable sign. The MultiBlock type has a field Sign, it will return nil if it is not a Sign, but if it is a sign it will return an object of type Sign with help of which we can change the text and colors of a Sign.<\/p>\n<p>In the update function we check if the sign variable is not a nil and if it is not a nil then we put a result of a call os.date(&#8220;%X&#8221;) which returns a time in a format (&#8220;hh:mm:ss&#8221;). You can read about os.date <a href=\"https:\/\/www.lua.org\/pil\/22.1.html\">here<\/a>.<\/p>\n<p>And now let&#8217;s focus on the body of findMultiBlockOfType function and I will try you to explain how it works.<\/p>\n<p>In a local variable p we store the coordiates of a first block of our multiblock. (mod blocks have only one block in MultiBlock).<\/p>\n<p>Then we store a Root object in a variable called r just not to write es.Root every time.<\/p>\n<p>For each of 6 sides we call a function GetBlock(x,y,z) of a Root. This function will return a block or a nill if this cell is empty.<\/p>\n<p>Then for each of these 6 variables we check if they are not nil, and if they are not nil we compare their type with the type we passed as an argument. And if the types match we return a MultiBlock object of this block. If we don&#8217;t find the object of needed type (Signe) then we return nil.<\/p>\n<h4>Another example<\/h4>\n<p>This mod will paint each of his neighbors to a different color, if there is a neighbor and if it is paintable. Block.DownBlock,Block.UpBlock etc, will return a neighbor block relative to a block orientation.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/pp.userapi.com\/c848628\/v848628227\/10e7ee\/YXsSjVfntes.jpg\" \/><\/p>\n<h3>Reference<\/h3>\n<h4>es<\/h4>\n<p>es is an object which is used to access Evertech Sandbox Mod API<\/p>\n<p>es.MultiBlock &#8211; returns MultiBlock object of current Item<\/p>\n<p>es.Root &#8211; is a shortcut of MultiBlock.Root<\/p>\n<p>es.TryGetMultiBlock(Vector3 pos, Vector3 dir, float rayLength) &#8211; casts a ray of length rayLength and if it intersects with a multiblock then this multiblock will be returned, otherwise nil will be return;<\/p>\n<p>es.PlaySound(string pathToSound) &#8211; plays a sound from your mod folder<\/p>\n<p>es.SetSoundVolume(float volume) &#8211; sets a volume of sound<\/p>\n<p>es.SetSoundLoop(bool loop) &#8211; sets if this sound should start playing again after it ends<\/p>\n<h4>MultiBlock<\/h4>\n<p>MultiBlock &#8211; almost everything in evertech sandbox is a multiblock, it has info about the type of object and it contains array of Blocks which are stored in a root grid.<\/p>\n<p>MultiBlock.Blocks &#8211; an array of blocks of this multiblock<\/p>\n<p>MultiBlock.Type &#8211; returns a type of this item. It is a string.<\/p>\n<p>MultiBlock.IsPaintable &#8211; a boolean property which tells if this item can be painted<\/p>\n<p>MultiBlock.Paint({r,g,b}) &#8211; is a method which takes an array of red green and blue components of a color. Each component should be from 0 to 1, example {0.5,0.23,0.79}<\/p>\n<p>MultiBlock.Sign &#8211; if the multiblock has type &#8220;Sign&#8221; then this property will return an object of type Sign<\/p>\n<p>MultiBlock.Switch &#8211; if the multiblock has type &#8220;Switch&#8221; then this property will return an object of type Switch<\/p>\n<p>MultiBlock.Destroy() &#8211; this method will destroy this item.<\/p>\n<p>MultiBlock.Root &#8211; this property will return a Root object<\/p>\n<p>MultiBlock.Rigidbody &#8211; is a shortcut for MultiBlock.Root.Rigidbody<\/p>\n<p>MultiBlock.Position &#8211; is a shortcut for MultiBlock.Transform.Position<\/p>\n<p>MultiBlock.Transform &#8211; returns a transform<\/p>\n<h4>Block<\/h4>\n<p>Block is a type which is stored in a root grid to reserve a place for a MultiBlock so two big multiblocks cannot be placed at one spot and will not intersect each other. Each block has a mass of 1 kg, the Root object will sum up all blocks and calculate it&#8217;s mass depending on blocks count.<\/p>\n<p>Block.PointInRoot &#8211; returns a coordinate in a root grid. Coordinates are of type Point<\/p>\n<p>Block.MultiBlock &#8211; returns a multiblock to which this block belongs to.<\/p>\n<p>Block.Type &#8211; is a shortcut to Block.MultiBlock.Type<\/p>\n<p>Block.Position &#8211; is a shortcut to Block.Transform.Position. Is a position in world coordinates and is just an array of 3 numbers<\/p>\n<p>Block.Transform &#8211; is a transform of this block. Contains Position and direction vectors.<\/p>\n<p>Block.Root &#8211; this property will return a Root object<\/p>\n<p>Block.DownBlock &#8211; will return a Block which is below current Block relatively to the transform of a current block, if there is no block it will return nil<\/p>\n<p>Block.UpBlock &#8211; returns Upper block<\/p>\n<p>Block.LeftBlock &#8211; return Left block<\/p>\n<p>Block.RightBlock &#8211; return Right block<\/p>\n<p>Block.BackBlock &#8211; return Back block<\/p>\n<p>Block.ForwardBlock &#8211; return Forward block<\/p>\n<h4>Point<\/h4>\n<p>Point is an object which stores a coordinates in root grid.<\/p>\n<p>X &#8211; x coordinate, integer<\/p>\n<p>Y &#8211; y coordinate, integer<\/p>\n<p>Z &#8211; z coordinate, integer<\/p>\n<p>ToString() &#8211; returns a string representation of a point in format X:Y:Z<\/p>\n<h4>Root<\/h4>\n<p>Root is an object which is parent to all Multiblocks and blocks. There is a ground root and dynamic roots.<\/p>\n<p>Root.GetBlock(x,y,z) &#8211; returns a block if it has it in these coordinates<\/p>\n<p>Root.GetBlock(Vector3 coords)- the same as above but you can pass an array of 3 numbers to it ({x,y,z})<\/p>\n<p>Root.Rigidbody &#8211; returns a rigidbody if it is not a ground root.<\/p>\n<h4>Rigidbody<\/h4>\n<p>Rigidbody &#8211;\u00a0With rigidbody you can apply forces or change velocity of the object.<\/p>\n<p>Rigidbody.IsKinematic &#8211; is a boolean property. False by default. If it is true then no forces are applied to this object and it will just freeze in space like if you used a tv remote on it.<\/p>\n<p>Rigidbody.Mass\u00a0 &#8211; ReadOnly. returns a mass of this root. The mass is calculated as a count of blocks in a root multiplied by 1.<\/p>\n<p>Rigidbody.WorldCenterOfMass &#8211; ReadOnly. is an array of 3 numbers. Returns a position of a center of mass of this object in world coordinates.<\/p>\n<p>Rigidbody.LocalCenterOfMass &#8211; ReadOnly. returns a position of a center of mass relative to a root transform.<\/p>\n<p>Rigidbody.Velocity &#8211; an array of 3 numbers. Returns a velocity vector. You can also set it by yourself.<\/p>\n<p>Rigidbody.UseGravity &#8211; is a boolean property. If it is false this object will behave as it is no gravity.<\/p>\n<p>Rigidbody.Position &#8211; returns an array of 3 numbers. The position in world coordinates. You can also set the value. For example: Rigidbody.Position = {10,20,30}<\/p>\n<p>Rigidbody.AddForceAtPosition(Vector3 force, Vector3 pos) &#8211; Applies a force at position. Vector3 is an array of 3 numbers. Example of use: es.MultiBlock.Rigidbody.AddForceAtPosition({0,30,0},es.MultiBlock.Position)<\/p>\n<p>Rigidbody.AddTorque(Vector3 torque)<\/p>\n<h4>Transform<\/h4>\n<p>Transform stores a position, rotation and direction vectors<\/p>\n<p>Transform.Position &#8211; world position of the object. Is a Vector3 aka array of 3 numbers<\/p>\n<p>Transform.Up &#8211; a vector of up direction relative to this object.<\/p>\n<p>Transform.Right &#8211; a vector of right direction relative to this object.<\/p>\n<p>Transform.Forward &#8211; a vector of forward direction relative to this object.<\/p>\n<p>Transform.Down &#8211; you can guess<\/p>\n<p>Transform.Back &#8211; same as above<\/p>\n<p>Transform.Left &#8211; same as above<\/p>\n<p>&#8212; rotation coming soon<\/p>\n<h4>Sign<\/h4>\n<p>Sign is a type to control a Sign Item.<\/p>\n<p>Sign.Text &#8211; is a string property. You can read or write a string from or to it.<\/p>\n<p>Sign.TextColor &#8211; a color property. You can set or read a color of text. Example: Sign.TextColor = {1,0,0}<\/p>\n<p>Sign.BackgroundColor &#8211; a color property. The Color of a background of a sign.<\/p>\n<h4>Switch<\/h4>\n<p>Switch is a type to control a Switch button<\/p>\n<p>Switch.IsOn &#8211; is a boolean property. You can read or write the value.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Up-to-date docs are here: http:\/\/vitsum.ml\/evertech\/docs\/#\/ Introduction Finally we now have support for lua scripting in our lovely game! So now you can make mods which are not just changed 3d model&#8230; your mods now can do stuff! Available since version 0.18.* Getting Started Before we start you need to read how to make a simple [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[1],"tags":[],"_links":{"self":[{"href":"http:\/\/evertechsandbox.com\/index.php?rest_route=\/wp\/v2\/posts\/65"}],"collection":[{"href":"http:\/\/evertechsandbox.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/evertechsandbox.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/evertechsandbox.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/evertechsandbox.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=65"}],"version-history":[{"count":21,"href":"http:\/\/evertechsandbox.com\/index.php?rest_route=\/wp\/v2\/posts\/65\/revisions"}],"predecessor-version":[{"id":119,"href":"http:\/\/evertechsandbox.com\/index.php?rest_route=\/wp\/v2\/posts\/65\/revisions\/119"}],"wp:attachment":[{"href":"http:\/\/evertechsandbox.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=65"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/evertechsandbox.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=65"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/evertechsandbox.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=65"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}