Mineshafts-prototype2/engine/WAEditor/WAEngine.gd

555 lines
16 KiB
GDScript

extends Control
var paswc = "9n#3d!fnDSFP¤&(=)90&¤/TVba+v89H)(¤Hpo0F?)"
var nodes = {}
var tmpnodes = {}
var nodereg
var timer = 0
var events = 0
var stackoverflow = 400
var editor
func _ready():
var e = load("res://engine/WAEditor/WAEditor.gd").new()
nodereg = e.nodereg
func _process(delta):
timer += delta
if timer > 0.01:
timer = 0
events = 0
func scan(DIR="user://mods",getlist={},get=false):
var d = Directory.new()
d.open(DIR)
d.list_dir_begin()
var dir = d.get_next()
while dir != "":
if dir.begins_with(".") == false:
var cd = str(d.get_current_dir(),"/",dir)
var ex = dir.get_extension()
if d.current_is_dir():
getlist = scan(cd,getlist,get)
elif ex == "mmode" or ex == "mmodt":
getlist = load_mod(cd,getlist,get)
dir = d.get_next()
d.list_dir_end()
return getlist
func reload_mod(s,edit=null):
editor = edit
var l = s.name.length()
for id in nodes:
if id.substr(0,l) == s.name:
nodes.erase(id)
if tmpnodes.get(s.name):
for node in tmpnodes[s.name]:
if is_instance_valid(node):
node.free()
tmpnodes[s.name] = null
for id in s.data:
var d = s.data[id]
if nodereg.get(d.name) == null:
core.Error(str("ERROR: invalid node: ",d.name))
return
d.mod_name = s.name
d.mod_idname = str(s.name,":",id)
nodes[d.mod_idname] = d
for idname in nodes:
var ob = nodes[idname]
var def = nodereg.get(ob.name)
if def.get("init") != null and idname.substr(0,l) == s.name:
node_actions(ob,"init",null)
func load_mod(path,getlist,get=false):
var file = File.new()
var ex = path.get_extension()
var s
if ex == "mmodt":
file.open(path,File.READ)
s = str2var(file.get_as_text())
file.close()
if s is String:
core.Error(str("ERROR: modfile not valid: ",path))
return
elif ex == "mmode":
file.open_encrypted_with_pass(path,File.READ,paswc)
s = file.get_var()
file.close()
if s != null:
if get:
s.path = path
getlist[s.name] = s
return getlist
elif core.save.mods.get(s.name) != true:
return
for id in s.data:
var d = s.data[id]
if nodereg.get(d.name) == null:
core.Error(str('A fatal error occorpted:\nMod "',s.name,'" is outdated (invalid node: "',d.name,'")\nCurrent game version: ',core.version,"\nBuild in version: ",s.game_version))
return
d.mod_name = s.name
d.mod_idname = str(s.name,":",id)
nodes[d.mod_idname] = d
elif getlist != null:
var fn = path.get_file()
getlist[fn.replace(str(".",fn.get_extension()),"")] = {path=path,broken=true}
return getlist
func init():
for idname in nodes:
var ob = nodes[idname]
var def = nodereg.get(ob.name)
if def.get("init") != null:
node_actions(ob,"init",null)
func connection_flash(n):
var u = ColorRect.new()
u.rect_size = Vector2(10,10)
u.rect_position = n.rect_global_position
u.color = Color(1,1,1)
core.add_child(u)
yield(get_tree().create_timer(0.1),"timeout")
u.free()
func next_connection(ob1,output:String,value=null):
events += 1
if events > stackoverflow:
return
if is_by_editor(ob1):
var edob = editor.nodes[ob1.id]
var edop = edob.options
for op1name in ob1.options:
var op1value = ob1.options[op1name]
if op1value != null:
var op2 = edop[op1name]
op2.node.set(op2.method,op1value)
#op2.node[op2.method] = op1value
var out = edob.output.get(output)
if out != null:
connection_flash(out.node)
var c = ob1.connections.get(output)
if c != null:
var outputs = c
for ob2_input_key in outputs:
var ob2_input = outputs[ob2_input_key]
var ob2 = nodes[str(ob1.mod_name,":",ob2_input.id)]
node_actions(ob2,ob2_input.name,value)
func tempnodes(ob,node):
tmpnodes[ob.mod_name] = [] if tmpnodes.get(ob.mod_name) == null else tmpnodes[ob.mod_name]
tmpnodes[ob.mod_name].push_back(node)
func text_to_groups(a):
a = a.replace(" ","")
var g = {}
for i in a.split(",",false):
var l = i.find("=")
if l == -1:
return str("invalid input: ",i)
var name = i.substr(0,l)
var n = i.substr(l+1,-1)
var I = n.is_valid_integer()
if name.is_valid_identifier() == false:
return str("invalid name: ",name)
elif I == false and n.is_valid_float() == false:
return str("invalid value: ",n)
var intn = int(n)
g[name] = intn if I else float(n)
return g
func text_to_drop(a):
a = a.replace(" ","")
var g = {}
for d in a.split(";",false):
var count = 1
var additional = true
var item = ""
var chance = 10
for i in d.split(",",false):
var l = i.find("=")
if l == -1:
return str("invalid input: ",i)
var name = i.substr(0,l)
var n = i.substr(l+1,-1)
var I = n.is_valid_integer()
#var p = false
#if I == false:
# return str("invalid value: ",n)
if name == "+" and not (n == "false" or n == "true"):
return str("invalid + value: ",n)
elif name == "+" and n == "false":
additional = false
elif (name == "chance" and I == false):
return str("invalid chance value: ",n)
elif name == "chance":
chance = int(n)
elif name.find(":") > 0:
var ndef = name.split(":")
if ndef.size() != 2 or not (ndef[0].is_valid_identifier() and ndef[1].is_valid_identifier()):
return str("invalid item name: ",name)
elif I == false:
return str("invalid item count: ",name)
else:
count = int(n)
item = name
else:
return str("invalid option: ",name)
if item == "":
return str("invalid drop: no item")
g[item] = {chance=chance,count=count,additional=additional}
return g
func is_valid_itemstack(s):
if s is Dictionary:
if s.get("name") is String:
return core.get_item_reg(s.name) != null
return false
func is_by_editor(ob):
return editor != null and editor.get_node("manu/name").text == ob.mod_name
func editor_error(ob,opname,message):
if is_by_editor(ob):
core.option_flash(editor.nodes[ob.id].options[opname].node,message)
func get_opmanu_value(nodedef,name,i):
for op in nodereg[nodedef].op:
if op.get("name") == name:
return op.manu[i]
# ==================================================================
# functions ========================================================
# ==================================================================
func node_actions(ob,input:String="",value=null):
if is_by_editor(ob):
var inp = editor.nodes[ob.id].input.get(input)
if inp != null:
connection_flash(inp.node)
var name = ob.name
match name:
"print":
print(value)
"world":
if input == "init":
next_connection(ob,"Enter")
next_connection(ob,"Wolrd name",core.world.name)
else:
next_connection(ob,"Quit")
"string":
match input:
"Set (1)":
ob.options.text1 = value
"Set (2)":
ob.options.text2 = value
"Number to string (1)":
ob.options.text2 = str(value)
"Replace":
next_connection(ob,"Value",value.replace(ob.options.text1,ob.options.text2))
"Add front":
ob.options.text1 = str(value,ob.options.text1)
"Add back":
ob.options.text1 = str(ob.options.text1,value)
next_connection(ob,"Value",ob.options.text1)
"gate":
match input:
"In":
if ob.options.checkbox1:
next_connection(ob,"Opened",value)
else:
next_connection(ob,"Closed",value)
"Open":
ob.options.checkbox1 = true
"Close":
ob.options.checkbox1 = false
"Toggle":
ob.options.checkbox1 = ob.options.checkbox1 == false
"number":
if input == "In":
next_connection(ob,"Value",ob.options.number1)
return
elif ob.options.checkbox1:
value = int(value)
elif ob.options.checkbox1 == false:
value = float(value)
ob.options.number1 = 0 if ob.options.number1 == null else ob.options.number1
match input:
#"In":
"Set":
ob.options.number1 = value
"String to number":
ob.options.number1 = value
"+":
ob.options.number1 += value
"-":
ob.options.number1 -= value
"*":
ob.options.number1 *= value
"/":
ob.options.number1 /= value
next_connection(ob,"Value",ob.options.number1)
"timer":
match input:
"Start":
var t
ob.options.number1 = 0 if ob.options.number1 == null else ob.options.number1
if ob.get("timer") == null:
t = Timer.new()
ob.timer = t
tempnodes(ob,t)
core.add_child(t)
else:
t = ob.timer
t.disconnect("timeout",self,"node_actions")
t.one_shot = false if ob.options.checkbox1 != true else true
t.connect("timeout",self,"node_actions",[ob,"Timeout",value])
t.wait_time = ob.options.number1
ob.timer.start()
"Stop":
if ob.get("timer") != null:
ob.timer.stop()
"Set":
ob.options.number1 = value
ob.timer.wait_time = value
"Timeout":
next_connection(ob,"Timeout",value)
"delay":
yield(get_tree().create_timer(ob.options.number1),"timeout")
next_connection(ob,"Out",value)
"set_node":
if input == "node":
ob.options.text1 = input
else:
var r = core.get_node_reg(ob.options.node)
if r == null:
editor_error(ob,"text1",str("invalid node"))
else:
core.set_node({name=ob.options.node,pos=value})
"vector":
ob.options.text1 = ob.options.text1.replace(" ","")
var s = ob.options.text1.split(",",false)
var msg
var n = s.size()
if n < 2 or n > 3:
msg = "2 or 3 numbers allowed"
else:
for i in s:
if i.is_valid_integer() == false and i.is_valid_float() == false:
msg = "Invalid vector\n(only numbers allowed)"
if msg != null and is_by_editor(ob):
core.option_flash(editor.nodes[ob.id].options["text1"].node,msg)
return
if n == 2:
value = str2var(str("Vector2(",s[0],",",s[1],")"))
else:
value = str2var(str("Vector3(",s[0],",",s[1],",",s[2],")"))
next_connection(ob,str("Vector",n),value)
# "get_player_by_name":
# if input == "Player name":
# ob.options.playername = value
# else:
# var p = core.players.get(ob.options.playername)
# if p != null:
# next_connection(ob,"Player",core.player.object)
"player":
next_connection(ob,"Player",core.player.object)
"add_to_inventory":
match input:
"Stack input":
if is_valid_itemstack(value) and ob.options.get("object_var") != null:
var stack2
if ob.options.object_var is Vector3:
stack2 = core.add_to_inventory(ob.options.object_var,ob.options.listname,value)
elif is_instance_valid(ob.options.object_var):
# wrong ob.options.listname will crash
var o = ob.options.object_var
if o.get("player"):
o = o.player
elif o.get("mob"):
o = o.mob
elif o.get("object"):
o = o.object
else:
return
stack2 = core.add_to_inventory(o,ob.options.listname,value)
if ob.options.object_var.get("player"):
ob.options.object_var.update_player()
if stack2.count > 0:
next_connection(ob,"Leftover",stack2)
"listname":
ob.options.listname = value
"Set object":
if value is KinematicBody and (value.get("player") != null or value.get("mob") != null):
ob.options.object_var = value
elif is_by_editor(ob):
core.option_flash(editor.nodes[ob.id].options["label"].node,"Not valid")
return
"Set position":
ob.options.object_var = value
"itemstack":
match input:
"In":
if ob.options.item_name != null and core.get_item_reg(ob.options.item_name) != null:
next_connection(ob,"Stack",core.itemstack(ob.options.item_name,{count=ob.options.count}))
"Item name":
if core.get_item_reg(value) == null:
if is_by_editor(ob):
core.option_flash(editor.nodes[ob.id].options["item_name"].node,"Invalid item")
return
ob.options.item_name = value
"Count":
ob.options.count = value
"distribute":
var v = typeof(value)
if v == TYPE_INT or v == TYPE_REAL:
next_connection(ob,"Number",value)
elif v == TYPE_STRING:
next_connection(ob,"String",value)
elif v == TYPE_BOOL:
next_connection(ob,"Bool",value)
elif v == TYPE_ARRAY:
next_connection(ob,"Array",value)
elif v == TYPE_DICTIONARY:
next_connection(ob,"Tree",value)
elif v == TYPE_VECTOR3:
next_connection(ob,"Vector3",value)
elif v == TYPE_VECTOR2:
next_connection(ob,"Vector2",value)
elif is_instance_valid(value) and value.get("player") != null:
next_connection(ob,"Player",value)
elif is_instance_valid(value) and value.get("mob") != null:
next_connection(ob,"Mob",value)
elif value is StreamTexture:
next_connection(ob,"Texture",value)
elif is_instance_valid(value):
next_connection(ob,"Object",value)
else:
next_connection(ob,"Variant",value)
"counter":
if ob.options.number1 == null:
ob.options.number1 = 1
match input:
"In":
next_connection(ob,"Value",ob.options.number1)
"Reset":
ob.options.number1 = 0
"Add (variant: 1, number: value)":
ob.options.number1 += 1 if typeof(value) != TYPE_REAL and typeof(value) != TYPE_INT else value
"Set (1)":
ob.options.number1 = value
"Set (2)":
ob.options.number2 = value
var a = 0 if ob.options.number1 == null else ob.options.number1
var b = 0 if ob.options.number2 == null else ob.options.number2
if a < b:
next_connection(ob,"<",value)
elif a <= b:
next_connection(ob,"<=",value)
if a > b:
next_connection(ob,">",value)
elif a >= b:
next_connection(ob,">=",value)
if a == b:
next_connection(ob,"==",value)
elif a != b:
next_connection(ob,"~",value)
"texture":
if input == "In":
var l = load(ob.options.text1)
if l is StreamTexture:
next_connection(ob,"Value", l)
else:
ob.options.text1 = value if value != null else ""
"default_chest_inventory":
if core.existsMeta(value) == false:
core.create_node_inventory(value,"main")
GUI.show(core.player,"background[8;8.5]inventory[player:player1;main;0;4.5;8;4]inventory[node:"+var2str(value)+";main;0;0;8;4]")
"change_world":
if ob.options.name != "":
core.world.name = ob.options.name
core.world.mapgen = get_opmanu_value("change_world","mapgen",ob.options.mapgen)
core.world_main(true)
"register_item":
var o = ob.options
var inv_image = load(ob.options.inv_image)
var groups = text_to_groups(ob.options.groups)
var item_groups = text_to_groups(ob.options.item_groups)
if o.name.is_valid_filename() == false:
if is_by_editor(ob):
core.option_flash(editor.nodes[ob.id].options["name"].node,"Invalid name")
return
elif not inv_image is StreamTexture:
if is_by_editor(ob):
core.option_flash(editor.nodes[ob.id].options["inv_image"].node,"Texture not found")
return
elif groups is String:
if is_by_editor(ob):
core.option_flash(editor.nodes[ob.id].options["groups"].node,groups)
return
elif item_groups is String:
if is_by_editor(ob):
core.option_flash(editor.nodes[ob.id].options["item_groups"].node,item_groups)
return
var reg_item_name = str(ob.mod_name,":",o.name)
core.register.items[reg_item_name] = {
name = reg_item_name,
type = "item",
inv_image = inv_image,
max_count = o.max_count,
groups = o.item_groups,
}
if o.capabilities:
core.register.items[reg_item_name].item_capabilities = {
punch_interval = o.punch_interval,
damage = o.damage,
durability = o.durability,
groups = groups,
}
"register_node":
var groups = text_to_groups(ob.options.groups)
var drops = text_to_drop(ob.options.drops)
var tiles = []
if ob.options.name.is_valid_identifier() == false:
editor_error(ob,"name","invalid name")
elif groups is String:
editor_error(ob,"groups",groups)
return
elif ob.options.drops != "" and drops is String:
editor_error(ob,"drops",drops)
return
if ob.options.drops == "":
drops = null
for i in range(1,6):
var t = ob.options[str("tile",i)]
if t != "":
var l = load(t)
if l is StreamTexture:
tiles.push_back(l)
else:
editor_error(ob,str("tile",i),str("not found"))
return
core.register_node({
name = str(ob.mod_name,":",ob.options.name),
drop = drops,
drawtype = get_opmanu_value("register_node","drawtype",ob.options.drawtype),
groups=groups,
max_count = ob.options.max_count,
replaceable = ob.options.replaceable,
collidable = ob.options.collidable,
transparent = ob.options.transparent,
solid_surface = ob.options.solid_surface,
touchable = ob.options.touchable,
activatable = ob.options.activatable,
tiles = tiles,
})
next_connection(ob,"on_register")