Initial Commit

master
rubenwardy 2014-10-12 19:23:20 +01:00
commit bd9f5049e9
4 changed files with 313 additions and 0 deletions

10
README.md Normal file
View File

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

175
mesecode.py Normal file
View File

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

118
specification.md Normal file
View File

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

10
test.mese Normal file
View File

@ -0,0 +1,10 @@
mod test
script scripting.lua
node My Node
is ground, cracky, silly = 6
drops Another Node
node Another Node
name hello
eaten 5