Initial Commit
commit
bd9f5049e9
|
@ -0,0 +1,10 @@
|
|||
MeseCode
|
||||
========
|
||||
|
||||
A readable modding format for Minetest. Scripts are written in MeseCode, which is then converted into Lua.
|
||||
|
||||
Created by rubenwardy.
|
||||
|
||||
License: GPL 3.0 or later
|
||||
|
||||
The copyright of mesecode scripts, and any resulting Lua files, remains with their author.
|
|
@ -0,0 +1,175 @@
|
|||
import re, sys
|
||||
|
||||
# How many spaces in a tab.
|
||||
# -1 disables support for spaces as tabs (recommended)
|
||||
# There are usually 4 spaces in a tab
|
||||
SPACES_PER_TAB = -1
|
||||
|
||||
class Node():
|
||||
def __init__(self, desc):
|
||||
self.desc = desc
|
||||
self.name = desc.lower().replace(" ", "_")
|
||||
self.groups = []
|
||||
self.last_prop = None
|
||||
self.type = "node"
|
||||
self.eaten = None
|
||||
self.drops = []
|
||||
def build(self, project):
|
||||
name = self.name
|
||||
if name.find(":") == -1:
|
||||
name = project.modname + ":" + name
|
||||
retval = "minetest.register_node(\"" + name + "\", {\n"
|
||||
retval += "\tdescription = \"" + self.desc + "\",\n"
|
||||
|
||||
if self.eaten is not None:
|
||||
retval += "\ton_use = minetest.item_eat(" + self.eaten + "),\n"
|
||||
|
||||
is_ground_content = False
|
||||
if len(self.groups) > 0:
|
||||
retval += "\tgroups = {"
|
||||
for group in self.groups:
|
||||
if group == "ground":
|
||||
is_ground_content = True
|
||||
continue
|
||||
if group.find("=") == -1:
|
||||
group += " = 1"
|
||||
retval += group + ", "
|
||||
retval += "}\n"
|
||||
|
||||
if len(self.drops) == 1:
|
||||
retval += "\tdrop = \"" + project.getItemName(self.drops[0]) + "\",\n"
|
||||
elif len(self.drops) > 1:
|
||||
retval += "\tdrop = {\n"
|
||||
for dropped in self.drops:
|
||||
retval += "\t\t\"" + project.getItemName(dropped) + "\",\n"
|
||||
retval += "\t},"
|
||||
|
||||
if is_ground_content:
|
||||
retval += "\tis_ground_content = true,\n"
|
||||
retval += "})\n"
|
||||
return retval
|
||||
|
||||
class Script:
|
||||
def __init__(self, filename):
|
||||
self.filename = filename
|
||||
self.type = "script"
|
||||
def build(self, project):
|
||||
return "dofile(minetest.get_modpath(\"" + project.modname + "\") .. \"" + self.filename + "\")\n"
|
||||
|
||||
class ParseError(Exception):
|
||||
def __init__(self, value):
|
||||
self.value = value
|
||||
def __str__(self):
|
||||
return self.value
|
||||
|
||||
def throwParseError(msg):
|
||||
print("\033[91mParse Error: " + msg + "\033[0m")
|
||||
sys.exit(-1)
|
||||
|
||||
def parse_list(the_list, line):
|
||||
if line == "":
|
||||
return
|
||||
arr = line.split(",")
|
||||
for item in arr:
|
||||
item = item.strip()
|
||||
if item != "":
|
||||
the_list.append(item)
|
||||
|
||||
class Project:
|
||||
def getItemName(self, desc):
|
||||
for item in self.objects:
|
||||
if item.type == "node" and item.desc.lower() == desc.lower():
|
||||
if item.name.find(":") == -1:
|
||||
return self.modname + ":" + item.name
|
||||
else:
|
||||
return item.name.strip(":")
|
||||
return ""
|
||||
def __init__(self, filename):
|
||||
file = open(filename, "r")
|
||||
|
||||
self.modname = None
|
||||
self.objects = []
|
||||
|
||||
lineno = 0
|
||||
for line in file.readlines():
|
||||
lineno += 1
|
||||
|
||||
# Remove comments
|
||||
if line.find("--") != -1:
|
||||
line = line[:line.find("--")]
|
||||
if line.strip() == "":
|
||||
continue
|
||||
|
||||
# Find indentation level
|
||||
if SPACES_PER_TAB != -1:
|
||||
line = line.replace(SPACES_PER_TAB * " ", "\t")
|
||||
indented = 0
|
||||
m = re.search('([\\t]+)', line)
|
||||
if m:
|
||||
indented = len(m.group(1))
|
||||
|
||||
# Strip redundant symbols
|
||||
line = line.strip()
|
||||
|
||||
self.processLine(line, indented, lineno)
|
||||
|
||||
def processLine(self, line, indented, lineno):
|
||||
if indented > 2 or indented < 0:
|
||||
throwParseError("Too many levels of indentation at " + str(lineno))
|
||||
elif indented == 0:
|
||||
#
|
||||
# Top Level Statements
|
||||
#
|
||||
|
||||
if line.startswith("mod "):
|
||||
if self.modname is not None:
|
||||
throwParseError("Mod name redefined on line " + str(lineno))
|
||||
self.modname = line[4:].strip()
|
||||
elif line.startswith("node "):
|
||||
self.objects.append(Node(line[5:].strip()))
|
||||
elif line.startswith("script "):
|
||||
self.objects.append(Script(line[7:].strip()))
|
||||
else:
|
||||
throwParseError("Unknown definition on line " + str(lineno))
|
||||
else:
|
||||
if len(self.objects) == 0:
|
||||
throwParseError("Too many levels of indentation at " + str(lineno))
|
||||
curobj = self.objects[len(self.objects) - 1]
|
||||
|
||||
#
|
||||
# Properties
|
||||
#
|
||||
if indented == 1:
|
||||
curobj.last_prop = None
|
||||
if line.startswith("is"):
|
||||
parse_list(curobj.groups, line[2:].strip())
|
||||
curobj.last_prop = curobj.groups
|
||||
elif line.startswith("name "):
|
||||
curobj.name = line[5:].strip()
|
||||
elif line.startswith("eaten "):
|
||||
curobj.eaten = line[6:].strip()
|
||||
elif curobj.type == "node":
|
||||
if line.startswith("drops "):
|
||||
parse_list(curobj.drops, line[6:].strip())
|
||||
curobj.last_prop = curobj.drops
|
||||
else:
|
||||
throwParseError("Unknown property in '" + curobj.type + "/" + curobj.name + "' on line " + str(lineno))
|
||||
else:
|
||||
throwParseError("Unknown property in '" + curobj.type + "/" + curobj.name + "' on line " + str(lineno))
|
||||
#
|
||||
# Lists
|
||||
#
|
||||
elif indented == 2:
|
||||
curprop = curobj.last_prop
|
||||
if curprop is None:
|
||||
throwParseError("Too many levels of indentation at " + str(lineno))
|
||||
curprop.append(line)
|
||||
|
||||
def write(self, directory):
|
||||
print("-- Mod namespace: " + self.modname)
|
||||
print("-- Generated using the Minetest Readable Modding Format\n")
|
||||
for item in self.objects:
|
||||
print(item.build(self))
|
||||
|
||||
|
||||
Project("test.mese").write("test")
|
|
@ -0,0 +1,118 @@
|
|||
Minetest Readable Modding Format
|
||||
================================
|
||||
|
||||
(Just a specification, a converter has not been written)
|
||||
|
||||
Here is the definition of default:stone:
|
||||
|
||||
```
|
||||
mod default
|
||||
|
||||
node Stone
|
||||
is ground, cracky, stone
|
||||
drops Cobble
|
||||
```
|
||||
|
||||
This is translated into the following code:
|
||||
|
||||
```Lua
|
||||
minetest.register_node("default:stone", {
|
||||
description = "Stone",
|
||||
tiles = {"default_stone.png"},
|
||||
is_ground_content = true,
|
||||
groups = {cracky=3, stone=1},
|
||||
drop = 'default:cobble'
|
||||
})
|
||||
```
|
||||
|
||||
Line 1 in the script file declares the name of this mod.
|
||||
|
||||
Line 3 is the start of the definition of a node.
|
||||
The description is just the phrase after 'node'.
|
||||
The node's name is a decapitalised version of the description,
|
||||
with underscores instead of spaces.
|
||||
The tile is in the form modname_itemname.png.
|
||||
|
||||
Overwriting description and name
|
||||
--------------------------------
|
||||
|
||||
It is possible to overwrite the name of a node or item.
|
||||
For example:
|
||||
|
||||
```
|
||||
mod some_foods
|
||||
|
||||
node Milk Chocolate Bar
|
||||
name chocolate_milk
|
||||
eaten 2
|
||||
```
|
||||
|
||||
Lists
|
||||
-----
|
||||
|
||||
Some properties require lists.
|
||||
These two code snippets do exactly the same thing:
|
||||
|
||||
```
|
||||
node test
|
||||
is one, two, three
|
||||
```
|
||||
|
||||
|
||||
```
|
||||
node test
|
||||
is
|
||||
one
|
||||
two
|
||||
three
|
||||
```
|
||||
Tiles
|
||||
-----
|
||||
|
||||
Sometimes you want to give a node multiple tiles.
|
||||
|
||||
```
|
||||
mod compass
|
||||
|
||||
node Compass
|
||||
6 tiles
|
||||
is cracky, oddly_breakable_by_hand
|
||||
```
|
||||
|
||||
Allows compass_compass_top.png, compass_compass_left.png, compass_compass_back.png, etc to be used.
|
||||
|
||||
You can use the tiles property as a list, like this:
|
||||
|
||||
```
|
||||
mod special_grass
|
||||
|
||||
node grass
|
||||
tiles
|
||||
top.png
|
||||
bottom.png
|
||||
right.png
|
||||
left.png
|
||||
back.png
|
||||
front.png
|
||||
```
|
||||
|
||||
Lua Scripting
|
||||
-------------
|
||||
|
||||
```
|
||||
script script1.lua
|
||||
```
|
||||
|
||||
```
|
||||
node furnace
|
||||
on right click: function
|
||||
on punch: script2.lua
|
||||
```
|
||||
|
||||
```
|
||||
!! Lua
|
||||
|
||||
|
||||
|
||||
!! End Lua
|
||||
```
|
Loading…
Reference in New Issue