mirror of https://github.com/dsrw/enu.git
Moved most script logic to ScriptController
This commit is contained in:
parent
f6bea8cae3
commit
c87ce39651
|
@ -1,4 +1,5 @@
|
|||
# begin Nimble config (version 1)
|
||||
--experimental:overloadableEnums
|
||||
when fileExists("nimble.paths"):
|
||||
include "nimble.paths"
|
||||
# end Nimble config
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
--tlsEmulation:off
|
||||
--threadAnalysis:off
|
||||
--define:nimPreviewHashRef
|
||||
--experimental:dynamicBindSym
|
||||
#--define:nimLeakDetector
|
||||
--define:enuHacks
|
||||
|
||||
|
|
|
@ -2,32 +2,13 @@ import std / [strutils, os, tables]
|
|||
import pkg / [model_citizen, print]
|
||||
import pkg/godot except print
|
||||
import godotapi / [node, spatial]
|
||||
import models, models / scripts, world / [bot_node, build_node], engine / contexts
|
||||
import models, world / [bot_node, build_node]
|
||||
|
||||
type
|
||||
UnitController* = object
|
||||
NodeController* = object
|
||||
|
||||
let state = GameState.active
|
||||
|
||||
proc change_code(self: Unit, code: string, retry = true) =
|
||||
self.transform.value = self.start_transform
|
||||
if not retry_failures:
|
||||
state.paused = false
|
||||
self.reset()
|
||||
state.console.show_errors.value = false
|
||||
if code.strip == "" and file_exists(self.script_file):
|
||||
remove_file self.script_file
|
||||
remove_module self.script_file
|
||||
elif code.strip != "":
|
||||
write_file(self.script_file, code)
|
||||
if self.script_ctx.is_nil:
|
||||
self.script_ctx = ScriptCtx.init
|
||||
unit_ctxs[self.script_ctx.engine] = self
|
||||
self.script_ctx.script = self.script_file
|
||||
if retry:
|
||||
self.script_ctx.retry_on_nil = true
|
||||
self.load_script()
|
||||
|
||||
proc remove_from_scene(unit: Unit) =
|
||||
unit.reset()
|
||||
if unit == previous_build: previous_build = nil
|
||||
|
@ -39,14 +20,11 @@ proc remove_from_scene(unit: Unit) =
|
|||
field.untrack_all
|
||||
if unit of Build: Build(unit).untrack_all
|
||||
elif unit of Bot: Bot(unit).untrack_all
|
||||
if not unit.script_ctx.is_nil and not unit.script_ctx.engine.is_nil:
|
||||
let e = unit.script_ctx.engine
|
||||
unit_ctxs[e] = nil
|
||||
ctxs[e] = nil
|
||||
unit.script_ctx.engine.callback = nil
|
||||
unit.script_ctx.callback = nil
|
||||
if not unit.clone_of:
|
||||
remove_file unit.script_file
|
||||
remove_module unit.script_file
|
||||
# TODO?
|
||||
# remove_module unit.script_file
|
||||
remove_dir unit.data_dir
|
||||
for child in unit.units:
|
||||
child.remove_from_scene()
|
||||
|
@ -101,12 +79,6 @@ proc find_nested_changes(parent: Change[Unit]) =
|
|||
change.item.add_to_scene()
|
||||
elif Removed in change.changes:
|
||||
change.item.remove_from_scene()
|
||||
if Added in change.changes and change of Change[string] and parent.field_name == "code":
|
||||
let change = Change[string](change)
|
||||
parent.item.change_code(change.item)
|
||||
if Touched in change.changes and change of Change[string] and parent.field_name == "code":
|
||||
let change = Change[string](change)
|
||||
parent.item.change_code(change.item, false)
|
||||
if change of Change[ModelFlags]:
|
||||
let change = Change[ModelFlags](change)
|
||||
if change.item == Global:
|
||||
|
@ -115,7 +87,7 @@ proc find_nested_changes(parent: Change[Unit]) =
|
|||
elif Removed in change.changes:
|
||||
parent.item.set_global(false)
|
||||
|
||||
proc watch*(f: UnitController, state: GameState) =
|
||||
proc watch*(f: NodeController, state: GameState) =
|
||||
state.units.changes:
|
||||
if added():
|
||||
change.item.add_to_scene()
|
||||
|
@ -124,14 +96,6 @@ proc watch*(f: UnitController, state: GameState) =
|
|||
elif removed():
|
||||
change.item.remove_from_scene()
|
||||
|
||||
proc reload_all*(_: type UnitController) =
|
||||
ctxs.clear()
|
||||
unit_ctxs.clear()
|
||||
reset_interpreter()
|
||||
walk_tree state.units.value, proc(unit: Unit) =
|
||||
unit.script_ctx = nil
|
||||
unit.code.touch unit.code.value
|
||||
|
||||
proc init*(_: type UnitController): UnitController =
|
||||
result = UnitController()
|
||||
proc init*(_: type NodeController): NodeController =
|
||||
result = NodeController()
|
||||
result.watch state
|
|
@ -0,0 +1,373 @@
|
|||
import std / [macros, sugar, sets, os, strutils, times, monotimes, sequtils, importutils, tables]
|
||||
import pkg / [print, model_citizen]
|
||||
import pkg / compiler / vm except get_int
|
||||
import pkg / compiler / ast except new_node
|
||||
import pkg / compiler / [vmdef, options, lineinfos, astalgo, renderer, msgs]
|
||||
|
||||
import core, models / [types, states, bots, units], libs / [interpreters, eval]
|
||||
|
||||
include script_controllers/converters
|
||||
|
||||
type ScriptController* = ref object
|
||||
interpreter: Interpreter
|
||||
module_names: HashSet[string]
|
||||
active_unit: Unit
|
||||
unit_map: Table[PNode, Unit]
|
||||
node_map: Table[Unit, PNode]
|
||||
|
||||
const ADVANCE_STEP* = 0.5.seconds
|
||||
|
||||
let state = GameState.active
|
||||
|
||||
var failed: seq[tuple[unit: Unit, ex: ref VMQuit]]
|
||||
|
||||
proc map_unit(self: ScriptController, unit: Unit, pnode: PNode) =
|
||||
self.unit_map[pnode] = unit
|
||||
self.node_map[unit] = pnode
|
||||
|
||||
proc unmap_unit(self: ScriptController, unit: Unit) =
|
||||
if unit in self.node_map:
|
||||
self.unit_map.del self.node_map[unit]
|
||||
self.node_map.del unit
|
||||
|
||||
proc get_unit(self: ScriptController, a: VmArgs, pos: int): Unit =
|
||||
let pnode = a.get_node(pos)
|
||||
self.unit_map[pnode]
|
||||
|
||||
proc begin_turn(self: ScriptController, unit: Unit, direction: Vector3, degrees: float, move_mode: int): string =
|
||||
var degrees = degrees
|
||||
var direction = direction
|
||||
let ctx = self.active_unit.script_ctx
|
||||
if degrees < 0:
|
||||
degrees = degrees * -1
|
||||
direction = direction * -1
|
||||
ctx.callback = unit.on_begin_turn(direction, degrees, 1)
|
||||
if not ctx.callback.is_nil:
|
||||
ctx.pause()
|
||||
|
||||
proc begin_move(self: ScriptController, unit: Unit, direction: Vector3, steps: float, move_mode: int) =
|
||||
var steps = steps
|
||||
var direction = direction
|
||||
let ctx = self.active_unit.script_ctx
|
||||
if steps < 0:
|
||||
steps = steps * -1
|
||||
direction = direction * -1
|
||||
ctx.callback = unit.on_begin_move(direction, steps, 1)
|
||||
if not ctx.callback.is_nil:
|
||||
ctx.pause()
|
||||
|
||||
proc register_active(self: ScriptController, pnode: PNode) =
|
||||
self.map_unit(self.active_unit, pnode)
|
||||
|
||||
proc new_instance(self: ScriptController, src: Unit, dest: PNode) =
|
||||
var clone = src.clone(self.active_unit)
|
||||
clone.script_ctx = ScriptCtx(timer: MonoTime.high, interpreter: self.interpreter,
|
||||
module_name: src.script_ctx.module_name)
|
||||
self.map_unit(clone, dest)
|
||||
self.active_unit.units.add(clone)
|
||||
let active = self.active_unit
|
||||
self.active_unit = clone
|
||||
defer:
|
||||
self.active_unit = active
|
||||
discard clone.script_ctx.call_proc("run_script", dest)
|
||||
|
||||
proc echo_console(msg: string) =
|
||||
echo msg
|
||||
|
||||
proc action_running(self: Unit): bool =
|
||||
self.script_ctx.action_running
|
||||
|
||||
proc `action_running=`(self: Unit, value: bool) =
|
||||
if value:
|
||||
self.script_ctx.timer = get_mono_time() + ADVANCE_STEP
|
||||
else:
|
||||
self.script_ctx.timer = MonoTime.high
|
||||
self.script_ctx.action_running = value
|
||||
|
||||
proc yield_script(self: ScriptController, unit: Unit) =
|
||||
let ctx = unit.script_ctx
|
||||
ctx.callback = ctx.saved_callback
|
||||
ctx.saved_callback = nil
|
||||
ctx.pause()
|
||||
|
||||
macro bind_procs(self: ScriptController, proc_refs: varargs[typed]): untyped =
|
||||
result = new_stmt_list()
|
||||
result.add quote do:
|
||||
let script_controller {.inject.} = `self`
|
||||
|
||||
for proc_ref in proc_refs:
|
||||
let
|
||||
proc_impl = proc_ref.get_impl
|
||||
proc_name = proc_impl[0].str_val
|
||||
return_node = proc_impl[3][0]
|
||||
arg_nodes = proc_impl[3][1..^1]
|
||||
|
||||
let args = collect:
|
||||
var pos = -1
|
||||
for ident_def in arg_nodes:
|
||||
let typ = ident_def[1].str_val
|
||||
if typ == $ScriptController.type:
|
||||
ident"script_controller"
|
||||
elif typ == "VmArgs":
|
||||
ident"a"
|
||||
elif typ in ["Unit", "Bot", "Build"]:
|
||||
let getter = "get_" & typ
|
||||
pos.inc
|
||||
new_call(bind_sym(getter), ident"script_controller", ident"a", new_lit(pos))
|
||||
else:
|
||||
let getter = "get_" & typ
|
||||
pos.inc
|
||||
new_call(bind_sym(getter), ident"a", new_lit(pos))
|
||||
|
||||
var call = new_call(proc_ref, args)
|
||||
if return_node.kind == nnkSym:
|
||||
call = new_call(bind_sym"set_result", ident"a", new_call(bind_sym"to_node", call))
|
||||
|
||||
result.add quote do:
|
||||
mixin implement_routine
|
||||
`self`.interpreter.implement_routine "*", "base_api", `proc_name`, proc(a {.inject.}: VmArgs) {.gcsafe.} =
|
||||
`call`
|
||||
|
||||
proc script_error(self: ScriptController, unit: Unit, e: ref VMQuit) =
|
||||
echo "error: ", e.msg
|
||||
|
||||
proc advance_unit(self: ScriptController, unit: Unit, delta: float) =
|
||||
let ctx = unit.script_ctx
|
||||
if ctx and ctx.running:
|
||||
let now = get_mono_time()
|
||||
|
||||
if unit of Build:
|
||||
let unit = Build(unit)
|
||||
unit.voxels_remaining_this_frame += unit.voxels_per_frame
|
||||
var resume_script = true
|
||||
try:
|
||||
while resume_script and not state.paused:
|
||||
resume_script = false
|
||||
|
||||
if ctx.callback == nil or (not ctx.callback(delta)):
|
||||
ctx.timer = MonoTime.high
|
||||
ctx.action_running = false
|
||||
assert self.active_unit.is_nil
|
||||
self.active_unit = unit
|
||||
ctx.running = ctx.resume()
|
||||
if unit of Build:
|
||||
let unit = Build(unit)
|
||||
if unit.voxels_per_frame > 0 and ctx.running and unit.voxels_remaining_this_frame >= 1:
|
||||
resume_script = true
|
||||
elif now >= ctx.timer:
|
||||
ctx.timer = now + ADVANCE_STEP
|
||||
ctx.saved_callback = ctx.callback
|
||||
ctx.callback = nil
|
||||
# TODO
|
||||
self.active_unit = unit
|
||||
discard ctx.resume()
|
||||
except VMQuit as e:
|
||||
self.script_error(unit, e)
|
||||
finally:
|
||||
self.active_unit = nil
|
||||
|
||||
proc load_script(self: ScriptController, unit: Unit) =
|
||||
let ctx = unit.script_ctx
|
||||
self.active_unit = unit
|
||||
try:
|
||||
if not state.paused:
|
||||
let module_name = ctx.script.split_file.name
|
||||
var others = self.module_names
|
||||
self.module_names.incl module_name
|
||||
others.excl module_name
|
||||
let imports = if others.card > 0:
|
||||
"import " & others.to_seq.join(", ")
|
||||
else:
|
||||
""
|
||||
let code = unit.code_template(imports)
|
||||
ctx.load(state.config.script_dir, ctx.script, code, state.config.lib_dir)
|
||||
# if not initialized:
|
||||
# with ctx.engine:
|
||||
# expose "yield_script", proc(a: VmArgs):bool =
|
||||
# active_engine().callback = active_engine().saved_callback
|
||||
# active_engine().saved_callback = nil
|
||||
# true
|
||||
#
|
||||
# expose "begin_move", a => self.begin_move(get_vec3(a, 0), get_float(a, 1), get_int(a, 2).int)
|
||||
# expose "begin_turn", a => self.begin_turn(get_vec3(a, 0), get_float(a, 1), get_int(a, 2).int)
|
||||
# expose "echo_console", proc(a: VmArgs): bool =
|
||||
# let msg = a.get_string(0)
|
||||
# echo msg
|
||||
# state.console.log += msg
|
||||
# expose "create_new", a => self.create_new()
|
||||
# expose "collision", proc(a: VmArgs): bool =
|
||||
# for collision in self.collisions:
|
||||
# if collision.model == state.player:
|
||||
# a.set_result(collision.normal.snapped(vec3(1, 1, 1)).to_node)
|
||||
# return false
|
||||
# a.set_result(vec3().to_node)
|
||||
# false
|
||||
# expose "sleep", proc(a: VmArgs): bool =
|
||||
# self.load_vars()
|
||||
# let seconds = get_float(a, 0)
|
||||
# var duration = 0.0
|
||||
# active_engine().callback = proc(delta: float): bool =
|
||||
# duration += delta
|
||||
# return duration < seconds
|
||||
# true
|
||||
# expose "quit", proc(a: VmArgs): bool =
|
||||
# let e = active_engine()
|
||||
# e.exit_code = some(a.get_int(0).int)
|
||||
# e.pause()
|
||||
# e.running = false
|
||||
# result = false
|
||||
# expose "set_global", proc(a: VmArgs): bool =
|
||||
# let global = a.get_bool(0)
|
||||
# if global:
|
||||
# self.flags += Global
|
||||
# else:
|
||||
# self.flags -= Global
|
||||
# false
|
||||
# expose "get_global", proc(a: VmArgs): bool =
|
||||
# a.set_result((Global in self.flags).to_node)
|
||||
# false
|
||||
# expose "get_position", proc(a: VmArgs): bool =
|
||||
# let n = self.to_global(vec3(0, 0, 0)).to_node
|
||||
# a.set_result(n)
|
||||
# return false
|
||||
# expose "set_position", proc(a: VmArgs): bool =
|
||||
# let v = a.get_vec3(0)
|
||||
# self.transform.origin = v
|
||||
# false
|
||||
# expose "get_rotation", proc(a: VmArgs): bool =
|
||||
# # TODO: fix this
|
||||
# proc nm(f: float): float =
|
||||
# if f.is_equal_approx(0):
|
||||
# return 0
|
||||
# elif f < 0:
|
||||
# return f + (2 * PI)
|
||||
# else:
|
||||
# return f
|
||||
#
|
||||
# proc nm(v: Vector3): Vector3 =
|
||||
# vec3(v.x.nm, v.y.nm, v.z.nm)
|
||||
#
|
||||
# let e = self.transform.basis.get_euler
|
||||
#
|
||||
# let n = e.nm
|
||||
# let v = vec3(nm(n.x).rad_to_deg, nm(n.y).rad_to_deg, nm(n.z).rad_to_deg)
|
||||
# let m = if v.z > 0: 1.0 else: -1.0
|
||||
# let v2 = vec3(0.0, (v.x - v.y) * m, 0.0)
|
||||
# a.set_result(v2.to_node)
|
||||
# return false
|
||||
# self.on_script_loaded()
|
||||
if not state.paused:
|
||||
ctx.running = ctx.run()
|
||||
#self.update_running_state ctx.run()
|
||||
|
||||
except VMQuit as e:
|
||||
#if retry_failures:
|
||||
ctx.running = false
|
||||
#failed.add (self, e)
|
||||
#else:
|
||||
# discard
|
||||
#self.error(e)
|
||||
finally:
|
||||
self.active_unit = nil
|
||||
|
||||
proc remove_module*(self: ScriptController, file_name: string) =
|
||||
self.module_names.excl file_name.split_file.name
|
||||
|
||||
proc change_code(self: ScriptController, unit: Unit, code: string) =
|
||||
|
||||
# if not retry_failures:
|
||||
# state.paused = false
|
||||
unit.reset()
|
||||
state.console.show_errors.value = false
|
||||
if code.strip == "" and file_exists(unit.script_file):
|
||||
remove_file unit.script_file
|
||||
self.remove_module unit.script_file
|
||||
elif code.strip != "":
|
||||
write_file(unit.script_file, code)
|
||||
if unit.script_ctx.is_nil:
|
||||
unit.script_ctx = ScriptCtx(timer: MonoTime.high, interpreter: self.interpreter)
|
||||
#unit_ctxs[unit.script_ctx.engine] = unit
|
||||
unit.script_ctx.script = unit.script_file
|
||||
|
||||
self.load_script(unit)
|
||||
|
||||
proc watch_code(self: ScriptController, unit: Unit) =
|
||||
unit.code.changes:
|
||||
if added or touched:
|
||||
self.change_code(unit, change.item)
|
||||
|
||||
proc watch_units(self: ScriptController, units: ZenSeq[Unit]) =
|
||||
units.changes:
|
||||
let unit = change.item
|
||||
if added:
|
||||
unit.frame_delta.changes:
|
||||
if touched:
|
||||
self.advance_unit(unit, change.item)
|
||||
self.watch_code unit
|
||||
self.watch_units unit.units
|
||||
|
||||
if not unit.clone_of and file_exists(unit.script_file):
|
||||
unit.code.value = read_file(unit.script_file)
|
||||
if removed:
|
||||
self.unmap_unit(unit)
|
||||
|
||||
proc reload_all*(self: ScriptController) =
|
||||
# TODO?
|
||||
# reset_interpreter()
|
||||
walk_tree state.units.value, proc(unit: Unit) =
|
||||
unit.script_ctx = nil
|
||||
unit.code.touch unit.code.value
|
||||
|
||||
proc init*(_: type ScriptController): ScriptController =
|
||||
private_access ScriptCtx
|
||||
|
||||
let interpreter = Interpreter.init(state.config.script_dir, state.config.lib_dir)
|
||||
let controller = ScriptController(interpreter: interpreter)
|
||||
|
||||
interpreter.register_error_hook proc(config, info, msg, severity: auto) {.gcsafe.} =
|
||||
let ctx = controller.active_unit.script_ctx
|
||||
if severity == Severity.Error and config.error_counter >= config.error_max:
|
||||
let file_name = if info.file_index.int >= 0:
|
||||
config.m.file_infos[info.file_index.int].full_path.string
|
||||
else:
|
||||
"???"
|
||||
let msg = &"{file_name}({int info.line},{int info.col}): {msg}"
|
||||
echo "error: ", msg, " from ", ctx.file_name
|
||||
ctx.errors.add (msg, info)
|
||||
#ctx.exit_code = some(99)
|
||||
raise (ref VMQuit)(info: info, msg: msg)
|
||||
|
||||
interpreter.register_enter_hook proc(c, pc, tos, instr: auto) =
|
||||
assert controller
|
||||
assert controller.active_unit
|
||||
assert controller.active_unit.script_ctx
|
||||
|
||||
let ctx = controller.active_unit.script_ctx
|
||||
let info = c.debug[pc]
|
||||
|
||||
if ctx.previous_line != info:
|
||||
let config = interpreter.config
|
||||
if info.file_index.int >= 0 and info.file_index.int < config.m.file_infos.len:
|
||||
let file_name = config.m.file_infos[info.file_index.int].full_path.string
|
||||
if file_name == ctx.file_name:
|
||||
if ctx.line_changed != nil:
|
||||
ctx.line_changed(info, ctx.previous_line)
|
||||
(ctx.previous_line, ctx.current_line) = (ctx.current_line, info)
|
||||
|
||||
if ctx.pause_requested:
|
||||
ctx.pause_requested = false
|
||||
ctx.ctx = c
|
||||
ctx.pc = pc
|
||||
ctx.tos = tos
|
||||
raise new_exception(VMPause, "vm paused")
|
||||
|
||||
result = controller
|
||||
result.watch_units state.units
|
||||
|
||||
result.bind_procs begin_turn, begin_move, register_active, echo_console, new_instance,
|
||||
action_running, `action_running=`, yield_script
|
||||
|
||||
when is_main_module:
|
||||
state.config.lib_dir = current_source_path().parent_dir / ".." / ".." / "vmlib"
|
||||
var b = Bot.init
|
||||
let c = ScriptController.init
|
|
@ -0,0 +1,41 @@
|
|||
proc get_int(a: VmArgs; i: Natural): int = int vm.get_int(a, i)
|
||||
|
||||
proc get_pnode(a: VmArgs, pos: int): PNode {.inline.} = a.get_node(pos)
|
||||
|
||||
proc get_vector3(a: VmArgs, pos: int): Vector3 =
|
||||
proc float_val(node: PNode, name: string): float =
|
||||
assert node.kind == nkExprColonExpr
|
||||
assert node.sons[0].sym.kind == skField
|
||||
assert node.sons[0].sym.name.s == name
|
||||
result = node.sons[1].float_val
|
||||
let
|
||||
fields = a.get_node(pos).sons
|
||||
x = float_val(fields[1], "x")
|
||||
y = float_val(fields[2], "y")
|
||||
z = float_val(fields[3], "z")
|
||||
result = vec3(x, y, z)
|
||||
|
||||
# adapted from https://github.com/h0lley/embeddedNimScript/blob/6101fb37d4bd3f947db86bac96f53b35d507736a/embeddedNims/enims.nim#L31
|
||||
proc to_node(val: int): PNode =
|
||||
echo "converting int"
|
||||
new_int_node(nkIntLit, val)
|
||||
proc to_node(val: float): PNode = new_float_node(nkFloatLit, val)
|
||||
proc to_node(val: string): PNode = new_str_node(nkStrLit, val)
|
||||
proc to_node(val: bool): BiggestInt = BiggestInt(val)
|
||||
proc to_node(val: enum): PNode = val.ord.to_node
|
||||
|
||||
proc to_node(list: open_array[int|float|string|bool|enum]): PNode =
|
||||
result = nkBracket.new_node
|
||||
result.sons.initialize(list.len)
|
||||
for i in 0..list.high: result.sons[i] = list[i].to_node()
|
||||
|
||||
proc to_node(tree: tuple|object): PNode =
|
||||
result = nkPar.new_tree
|
||||
for field in tree.fields:
|
||||
result.sons.add(field.to_node)
|
||||
|
||||
proc to_node(tree: ref tuple|ref object): PNode =
|
||||
result = nkPar.new_tree
|
||||
if tree.is_nil: return result
|
||||
for field in tree.fields:
|
||||
result.sons.add(field.to_node)
|
|
@ -113,7 +113,7 @@ proc trunc*(self: Vector3): Vector3 {.inline.} =
|
|||
proc inverse_normalized*(self: Vector3): Vector3 {.inline.} =
|
||||
(self - vec3(self.length, self.length, self.length)) * -1
|
||||
|
||||
proc first*[T](arr: openArray[T], test: proc(x: T): bool): Option[T] =
|
||||
proc first*[T](arr: open_array[T], test: proc(x: T): bool): Option[T] =
|
||||
for item in arr:
|
||||
if test(item):
|
||||
return some(item)
|
||||
|
|
|
@ -1,247 +0,0 @@
|
|||
import std / [monotimes, os, hashes, sets, strutils, sugar, math]
|
||||
import pkg / godot except print
|
||||
import pkg / print
|
||||
import godotapi / [node]
|
||||
import core, engine/engine, models, globals
|
||||
|
||||
export engine
|
||||
|
||||
let state = GameState.active
|
||||
let config = state.config
|
||||
|
||||
var
|
||||
module_names: HashSet[string]
|
||||
failed: seq[tuple[unit: Unit, ex: ref VMQuit]]
|
||||
retry_failures* = false
|
||||
|
||||
proc load_script*(self: Unit, script = "")
|
||||
proc create_new(self: Unit): bool
|
||||
|
||||
proc destroy*(ctx: ScriptCtx) =
|
||||
if ctx.engine in ctxs:
|
||||
ctxs.del(ctx.engine)
|
||||
|
||||
proc init*(_: type ScriptCtx): ScriptCtx =
|
||||
let e = Engine.init()
|
||||
result = ScriptCtx(engine: e, timer: MonoTime.high)
|
||||
ctxs[e] = result
|
||||
|
||||
proc is_script_loadable*(self: Unit): bool =
|
||||
let ctx = self.script_ctx
|
||||
ctx.script != "none" and ctx.script.file_exists
|
||||
|
||||
proc error*(self: Unit, ex: ref VMQuit) =
|
||||
var ctx = self.script_ctx
|
||||
ctx.engine.running = false
|
||||
when defined(enu_simulate):
|
||||
raise ex
|
||||
else:
|
||||
let (root, _) = self.find_root(true)
|
||||
ctx = root.script_ctx
|
||||
if ctx.retry_on_nil and ("attempt to access a nil address" in ex.msg):
|
||||
root.code.touch root.code.value
|
||||
|
||||
else:
|
||||
state.err "Exception executing " & self.script_ctx.script
|
||||
state.err ex.msg
|
||||
state.console.show_errors.value = true
|
||||
|
||||
proc retry_failed_scripts* =
|
||||
var prev_failed = failed
|
||||
failed = @[]
|
||||
for f in prev_failed:
|
||||
echo "retrying: ", f.unit.script_ctx.script
|
||||
f.unit.load_script()
|
||||
if failed.len > 0 and prev_failed.len == failed.len:
|
||||
prev_failed = failed
|
||||
for f in prev_failed:
|
||||
f.unit.error(f.ex)
|
||||
|
||||
proc update_running_state(self: Unit, running: bool) =
|
||||
self.script_ctx.engine.running = running
|
||||
if not running:
|
||||
self.load_vars()
|
||||
state.debug(self.script_ctx.script & " done.")
|
||||
|
||||
proc remove_module*(file_name: string) =
|
||||
module_names.excl file_name.split_file.name
|
||||
|
||||
proc advance*(self: Unit, delta: float64) =
|
||||
let now = get_mono_time()
|
||||
let c = self.script_ctx
|
||||
let e = c.engine
|
||||
|
||||
if self of Build:
|
||||
let self = Build(self)
|
||||
self.voxels_remaining_this_frame += self.voxels_per_frame
|
||||
var resume_script = true
|
||||
try:
|
||||
while resume_script and not state.paused:
|
||||
resume_script = false
|
||||
|
||||
if e.callback == nil or (not e.callback(delta)):
|
||||
c.timer = MonoTime.high
|
||||
discard e.call_proc("set_action_running", e.module_name, false)
|
||||
self.update_running_state e.resume()
|
||||
if self of Build:
|
||||
let self = Build(self)
|
||||
if self.voxels_per_frame > 0 and e.running and self.voxels_remaining_this_frame >= 1:
|
||||
resume_script = true
|
||||
elif now >= c.timer:
|
||||
c.timer = now + ADVANCE_STEP
|
||||
e.saved_callback = e.callback
|
||||
e.callback = nil
|
||||
discard e.resume()
|
||||
except VMQuit as e:
|
||||
self.error(e)
|
||||
|
||||
proc begin_move(self: Unit, direction: Vector3, steps: float, move_mode: int): bool =
|
||||
self.load_vars()
|
||||
var steps = steps
|
||||
var direction = direction
|
||||
if steps < 0:
|
||||
steps = steps * -1
|
||||
direction = direction * -1
|
||||
active_engine().callback = self.on_begin_move(direction, steps, move_mode)
|
||||
result = not active_engine().callback.is_nil
|
||||
|
||||
proc begin_turn(self: Unit, direction: Vector3, degrees: float, move_mode: int): bool =
|
||||
self.load_vars()
|
||||
var degrees = degrees
|
||||
var direction = direction
|
||||
if degrees < 0:
|
||||
degrees = degrees * -1
|
||||
direction = direction * -1
|
||||
active_engine().callback = self.on_begin_turn(direction, degrees, move_mode)
|
||||
result = not active_engine().callback.is_nil
|
||||
|
||||
proc load_script*(self: Unit, script = "") =
|
||||
let ctx = self.script_ctx
|
||||
|
||||
if script != "":
|
||||
ctx.script = script
|
||||
ctx.engine.callback = nil
|
||||
try:
|
||||
if not self.is_script_loadable:
|
||||
return
|
||||
if not state.paused:
|
||||
let module_name = ctx.script.split_file.name
|
||||
var others = module_names
|
||||
if not ctx.is_clone:
|
||||
module_names.incl module_name
|
||||
others.excl module_name
|
||||
let imports = if others.card > 0:
|
||||
"import " & others.to_seq.join(", ")
|
||||
else:
|
||||
""
|
||||
let code = self.code_template(imports)
|
||||
|
||||
let initialized = ctx.engine.initialized
|
||||
let suffex = if ctx.is_clone: "_clone" & self.id else: ""
|
||||
ctx.load_vars = proc() = self.load_vars()
|
||||
ctx.engine.load(config.script_dir, ctx.script, code, config.lib_dir, suffex)
|
||||
if not initialized:
|
||||
with ctx.engine:
|
||||
expose "yield_script", proc(a: VmArgs):bool =
|
||||
active_engine().callback = active_engine().saved_callback
|
||||
active_engine().saved_callback = nil
|
||||
true
|
||||
|
||||
expose "begin_move", a => self.begin_move(get_vec3(a, 0), get_float(a, 1), get_int(a, 2).int)
|
||||
expose "begin_turn", a => self.begin_turn(get_vec3(a, 0), get_float(a, 1), get_int(a, 2).int)
|
||||
expose "echo_console", proc(a: VmArgs): bool =
|
||||
let msg = a.get_string(0)
|
||||
echo msg
|
||||
state.console.log += msg
|
||||
expose "create_new", a => self.create_new()
|
||||
expose "collision", proc(a: VmArgs): bool =
|
||||
for collision in self.collisions:
|
||||
if collision.model == state.player:
|
||||
a.set_result(collision.normal.snapped(vec3(1, 1, 1)).to_node)
|
||||
return false
|
||||
a.set_result(vec3().to_node)
|
||||
false
|
||||
expose "sleep", proc(a: VmArgs): bool =
|
||||
self.load_vars()
|
||||
let seconds = get_float(a, 0)
|
||||
var duration = 0.0
|
||||
active_engine().callback = proc(delta: float): bool =
|
||||
duration += delta
|
||||
return duration < seconds
|
||||
true
|
||||
expose "quit", proc(a: VmArgs): bool =
|
||||
let e = active_engine()
|
||||
e.exit_code = some(a.get_int(0).int)
|
||||
e.pause()
|
||||
e.running = false
|
||||
result = false
|
||||
expose "set_global", proc(a: VmArgs): bool =
|
||||
let global = a.get_bool(0)
|
||||
if global:
|
||||
self.flags += Global
|
||||
else:
|
||||
self.flags -= Global
|
||||
false
|
||||
expose "get_global", proc(a: VmArgs): bool =
|
||||
a.set_result((Global in self.flags).to_node)
|
||||
false
|
||||
expose "get_position", proc(a: VmArgs): bool =
|
||||
let n = self.to_global(vec3(0, 0, 0)).to_node
|
||||
a.set_result(n)
|
||||
return false
|
||||
expose "set_position", proc(a: VmArgs): bool =
|
||||
let v = a.get_vec3(0)
|
||||
self.transform.origin = v
|
||||
false
|
||||
expose "get_rotation", proc(a: VmArgs): bool =
|
||||
# TODO: fix this
|
||||
proc nm(f: float): float =
|
||||
if f.is_equal_approx(0):
|
||||
return 0
|
||||
elif f < 0:
|
||||
return f + (2 * PI)
|
||||
else:
|
||||
return f
|
||||
|
||||
proc nm(v: Vector3): Vector3 =
|
||||
vec3(v.x.nm, v.y.nm, v.z.nm)
|
||||
|
||||
let e = self.transform.basis.get_euler
|
||||
|
||||
let n = e.nm
|
||||
let v = vec3(nm(n.x).rad_to_deg, nm(n.y).rad_to_deg, nm(n.z).rad_to_deg)
|
||||
let m = if v.z > 0: 1.0 else: -1.0
|
||||
let v2 = vec3(0.0, (v.x - v.y) * m, 0.0)
|
||||
a.set_result(v2.to_node)
|
||||
return false
|
||||
self.on_script_loaded()
|
||||
if not state.paused:
|
||||
self.update_running_state ctx.engine.run()
|
||||
|
||||
except VMQuit as e:
|
||||
if retry_failures:
|
||||
self.script_ctx.engine.running = false
|
||||
failed.add (self, e)
|
||||
else:
|
||||
self.error(e)
|
||||
|
||||
proc create_new(self: Unit): bool =
|
||||
let unit = active_unit()
|
||||
let ae = active_engine()
|
||||
let clone = self.clone(unit, active_ctx())
|
||||
clone.script_ctx = ScriptCtx.init
|
||||
clone.script_ctx.is_clone = true
|
||||
clone.script_ctx.script = self.script_file
|
||||
let new_engine = clone.script_ctx.engine
|
||||
unit_ctxs[new_engine] = clone
|
||||
|
||||
ae.callback = proc(delta: float): bool =
|
||||
if not new_engine.initialized:
|
||||
clone.code.value = clone.script_file.read_file
|
||||
true
|
||||
else:
|
||||
false
|
||||
|
||||
set_active(ae)
|
||||
unit.units.add(clone)
|
||||
result = true
|
|
@ -0,0 +1,131 @@
|
|||
import std / [monotimes, os, hashes, sets, strutils, sugar, math]
|
||||
import pkg / godot except print
|
||||
import pkg / print
|
||||
import godotapi / [node]
|
||||
import core, engine/engine, models, globals
|
||||
|
||||
export engine
|
||||
|
||||
let state = GameState.active
|
||||
let config = state.config
|
||||
|
||||
|
||||
#retry_failures* = false
|
||||
|
||||
#proc load_script*(self: Unit, script = "")
|
||||
#proc create_new(self: Unit): bool
|
||||
|
||||
proc destroy*(ctx: ScriptCtx) =
|
||||
if ctx.engine in ctxs:
|
||||
ctxs.del(ctx.engine)
|
||||
|
||||
# proc is_script_loadable*(self: Unit): bool =
|
||||
# let ctx = self.script_ctx
|
||||
# ctx.script != "none" and ctx.script.file_exists
|
||||
|
||||
proc error*(self: Unit, ex: ref VMQuit) =
|
||||
var ctx = self.script_ctx
|
||||
ctx.engine.running = false
|
||||
when defined(enu_simulate):
|
||||
raise ex
|
||||
else:
|
||||
let (root, _) = self.find_root(true)
|
||||
ctx = root.script_ctx
|
||||
if ctx.retry_on_nil and ("attempt to access a nil address" in ex.msg):
|
||||
root.code.touch root.code.value
|
||||
|
||||
else:
|
||||
state.err "Exception executing " & self.script_ctx.script
|
||||
state.err ex.msg
|
||||
state.console.show_errors.value = true
|
||||
|
||||
proc retry_failed_scripts* =
|
||||
var prev_failed = failed
|
||||
failed = @[]
|
||||
for f in prev_failed:
|
||||
echo "retrying: ", f.unit.script_ctx.script
|
||||
f.unit.load_script()
|
||||
if failed.len > 0 and prev_failed.len == failed.len:
|
||||
prev_failed = failed
|
||||
for f in prev_failed:
|
||||
f.unit.error(f.ex)
|
||||
|
||||
proc update_running_state(self: Unit, running: bool) =
|
||||
self.script_ctx.engine.running = running
|
||||
if not running:
|
||||
self.load_vars()
|
||||
state.debug(self.script_ctx.script & " done.")
|
||||
|
||||
proc remove_module*(file_name: string) =
|
||||
module_names.excl file_name.split_file.name
|
||||
|
||||
proc advance*(self: Unit, delta: float64) =
|
||||
let now = get_mono_time()
|
||||
let c = self.script_ctx
|
||||
let e = c.engine
|
||||
|
||||
if self of Build:
|
||||
let self = Build(self)
|
||||
self.voxels_remaining_this_frame += self.voxels_per_frame
|
||||
var resume_script = true
|
||||
try:
|
||||
while resume_script and not state.paused:
|
||||
resume_script = false
|
||||
|
||||
if e.callback == nil or (not e.callback(delta)):
|
||||
c.timer = MonoTime.high
|
||||
discard e.call_proc("set_action_running", e.module_name, false)
|
||||
self.update_running_state e.resume()
|
||||
if self of Build:
|
||||
let self = Build(self)
|
||||
if self.voxels_per_frame > 0 and e.running and self.voxels_remaining_this_frame >= 1:
|
||||
resume_script = true
|
||||
elif now >= c.timer:
|
||||
c.timer = now + ADVANCE_STEP
|
||||
e.saved_callback = e.callback
|
||||
e.callback = nil
|
||||
discard e.resume()
|
||||
except VMQuit as e:
|
||||
self.error(e)
|
||||
|
||||
proc begin_move(self: Unit, direction: Vector3, steps: float, move_mode: int): bool =
|
||||
self.load_vars()
|
||||
var steps = steps
|
||||
var direction = direction
|
||||
if steps < 0:
|
||||
steps = steps * -1
|
||||
direction = direction * -1
|
||||
active_engine().callback = self.on_begin_move(direction, steps, move_mode)
|
||||
result = not active_engine().callback.is_nil
|
||||
|
||||
proc begin_turn(self: Unit, direction: Vector3, degrees: float, move_mode: int): bool =
|
||||
self.load_vars()
|
||||
var degrees = degrees
|
||||
var direction = direction
|
||||
if degrees < 0:
|
||||
degrees = degrees * -1
|
||||
direction = direction * -1
|
||||
active_engine().callback = self.on_begin_turn(direction, degrees, move_mode)
|
||||
result = not active_engine().callback.is_nil
|
||||
|
||||
|
||||
proc create_new(self: Unit): bool =
|
||||
let unit = active_unit()
|
||||
let ae = active_engine()
|
||||
let clone = self.clone(unit, active_ctx())
|
||||
clone.script_ctx = ScriptCtx.init
|
||||
clone.script_ctx.is_clone = true
|
||||
clone.script_ctx.script = self.script_file
|
||||
let new_engine = clone.script_ctx.engine
|
||||
unit_ctxs[new_engine] = clone
|
||||
|
||||
ae.callback = proc(delta: float): bool =
|
||||
if not new_engine.initialized:
|
||||
clone.code.value = clone.script_file.read_file
|
||||
true
|
||||
else:
|
||||
false
|
||||
|
||||
set_active(ae)
|
||||
unit.units.add(clone)
|
||||
result = true
|
|
@ -1,209 +0,0 @@
|
|||
import std / [os, strformat, with]
|
||||
import pkg / godot, pkg / compiler / [vm, vmdef, options, lineinfos, ast]
|
||||
import core, types, eval
|
||||
export Interpreter
|
||||
|
||||
export VmArgs, get_float, get_int, get_string, get_bool, set_result, to_int
|
||||
|
||||
type
|
||||
VMError* = object of CatchableError
|
||||
VMQuit* = object of VMError
|
||||
info*: TLineInfo
|
||||
VMPause* = object of CatchableError
|
||||
Engine* = ref object
|
||||
ctx: PCtx
|
||||
pc: int
|
||||
tos: PStackFrame
|
||||
line_changed*: proc(current, previous: TLineInfo)
|
||||
current_line*: TLineInfo
|
||||
previous_line: TLineInfo
|
||||
pause_requested: bool
|
||||
is_main_module: bool
|
||||
initialized*: bool
|
||||
code: string
|
||||
module_name*: string
|
||||
file_name: string
|
||||
exit_code*: Option[int]
|
||||
errors*: seq[tuple[msg: string, info: TLineInfo]]
|
||||
callback*: Callback
|
||||
saved_callback*: Callback
|
||||
running*: bool
|
||||
|
||||
const
|
||||
STDLIB_PATHS = [".", "core", "pure", "pure/collections", "pure/concurrency", "std", "fusion"]
|
||||
MAIN_SCRIPT = "scripts/main.nim"
|
||||
|
||||
var
|
||||
interpreter: Interpreter
|
||||
current: Engine
|
||||
|
||||
proc active_engine*(): Engine = current
|
||||
proc set_active*(e: Engine) =
|
||||
current = e
|
||||
|
||||
proc init*(t: typedesc[Engine]): Engine =
|
||||
result = Engine()
|
||||
|
||||
proc init_interpreter(script_dir, vmlib: string) =
|
||||
let std_paths = STDLIB_PATHS.map_it join_path(vmlib, "stdlib", it)
|
||||
let source_paths = std_paths & join_path(vmlib, "enu") & @[parent_dir MAIN_SCRIPT] & @[script_dir]
|
||||
interpreter = create_interpreter(MAIN_SCRIPT, source_paths)
|
||||
log_trace("create_interpreter")
|
||||
with interpreter:
|
||||
register_error_hook proc(config, info, msg, severity: auto) {.gcsafe.} =
|
||||
let e = active_engine()
|
||||
if severity == Severity.Error and config.error_counter >= config.error_max:
|
||||
let file_name = if info.file_index.int >= 0:
|
||||
config.m.file_infos[info.file_index.int].full_path.string
|
||||
else:
|
||||
"???"
|
||||
let msg = &"{file_name}({int info.line},{int info.col}): {msg}"
|
||||
echo "error: ", msg, " from ", e.file_name
|
||||
e.errors.add (msg, info)
|
||||
e.exit_code = some(99)
|
||||
raise (ref VMQuit)(info: info, msg: msg)
|
||||
|
||||
register_enter_hook proc(c, pc, tos, instr: auto) =
|
||||
let e = active_engine()
|
||||
let info = c.debug[pc]
|
||||
|
||||
if e.previous_line != info:
|
||||
let config = interpreter.config
|
||||
if info.file_index.int >= 0 and info.file_index.int < config.m.file_infos.len:
|
||||
let file_name = config.m.file_infos[info.file_index.int].full_path.string
|
||||
if file_name == e.file_name:
|
||||
if e.line_changed != nil:
|
||||
e.line_changed(info, e.previous_line)
|
||||
(e.previous_line, e.current_line) = (e.current_line, info)
|
||||
|
||||
if e.pause_requested:
|
||||
e.pause_requested = false
|
||||
e.ctx = c
|
||||
e.pc = pc
|
||||
e.tos = tos
|
||||
raise new_exception(VMPause, "vm paused")
|
||||
|
||||
proc pause*(e: Engine) =
|
||||
e.pause_requested = true
|
||||
|
||||
proc load*(e: Engine, script_dir, file_name, code, vmlib: string, module_suffix = "") =
|
||||
e.ctx = nil
|
||||
e.pc = 0
|
||||
e.tos = nil
|
||||
e.code = code
|
||||
if module_suffix == "":
|
||||
e.module_name = file_name.split_file.name
|
||||
e.file_name = file_name
|
||||
else:
|
||||
e.module_name = file_name.split_file.name & module_suffix
|
||||
e.file_name = e.module_name
|
||||
set_active e
|
||||
if interpreter.is_nil:
|
||||
init_interpreter(script_dir, vmlib)
|
||||
e.is_main_module = true
|
||||
e.initialized = true
|
||||
|
||||
proc run*(e: Engine): bool =
|
||||
set_active e
|
||||
e.exit_code = none(int)
|
||||
e.errors = @[]
|
||||
try:
|
||||
interpreter.load_module(e.file_name, e.code)
|
||||
false
|
||||
except VMPause:
|
||||
e.exit_code.is_none
|
||||
|
||||
proc get_vec3*(a: VmArgs, pos: int): Vector3 =
|
||||
proc float_val(node: PNode, name: string): float =
|
||||
assert node.kind == nkExprColonExpr
|
||||
assert node.sons[0].sym.kind == skField
|
||||
assert node.sons[0].sym.name.s == name
|
||||
result = node.sons[1].float_val
|
||||
let
|
||||
fields = a.get_node(0).sons
|
||||
x = float_val(fields[1], "x")
|
||||
y = float_val(fields[2], "y")
|
||||
z = float_val(fields[3], "z")
|
||||
result = vec3(x, y, z)
|
||||
|
||||
# adapted from https://github.com/h0lley/embeddedNimScript/blob/6101fb37d4bd3f947db86bac96f53b35d507736a/embeddedNims/enims.nim#L31
|
||||
proc to_node*(val: int): PNode = new_int_node(nkIntLit, val)
|
||||
proc to_node*(val: float): PNode = new_float_node(nkFloatLit, val)
|
||||
proc to_node*(val: string): PNode = new_str_node(nkStrLit, val)
|
||||
proc to_node*(val: bool): PNode = val.ord.to_node
|
||||
proc to_node*(val: enum): PNode = val.ord.to_node
|
||||
|
||||
proc to_node*(list: open_array[int|float|string|bool|enum]): PNode =
|
||||
result = nkBracket.new_node
|
||||
result.sons.initialize(list.len)
|
||||
for i in 0..list.high: result.sons[i] = list[i].to_node()
|
||||
|
||||
proc to_node*(tree: tuple|object): PNode =
|
||||
result = nkPar.new_tree
|
||||
for field in tree.fields:
|
||||
result.sons.add(field.to_node)
|
||||
|
||||
proc to_node*(tree: ref tuple|ref object): PNode =
|
||||
result = nkPar.new_tree
|
||||
if tree.is_nil: return result
|
||||
for field in tree.fields:
|
||||
result.sons.add(field.to_node)
|
||||
|
||||
proc call_proc*(e: Engine, proc_name: string, module_name = "", args: varargs[PNode, to_node]): PNode {.discardable.}=
|
||||
let foreign_proc = interpreter.select_routine(proc_name, module_name = module_name)
|
||||
if foreign_proc == nil:
|
||||
raise new_exception(VMError, &"script does not export a proc of the name: '{proc_name}'")
|
||||
return interpreter.call_routine(foreign_proc, args)
|
||||
|
||||
proc call*(e: Engine, proc_name: string): bool =
|
||||
set_active e
|
||||
try:
|
||||
discard e.call_proc(proc_name)
|
||||
false
|
||||
except VMPause:
|
||||
e.exit_code.is_none
|
||||
|
||||
proc expose*(e: Engine, proc_name: string,
|
||||
routine: proc(a: VmArgs): bool) {.gcsafe.} =
|
||||
interpreter.implement_routine "*", e.module_name, proc_name, proc(a: VmArgs) {.gcsafe.} =
|
||||
if routine(a):
|
||||
active_engine().pause()
|
||||
|
||||
proc call_float*(e: Engine, proc_name: string): float =
|
||||
e.call_proc(proc_name).get_float()
|
||||
|
||||
proc get_var*(e: Engine, var_name: string, module_name: string): PNode =
|
||||
let sym = interpreter.select_unique_symbol(var_name, module_name = module_name)
|
||||
interpreter.get_global_value(sym)
|
||||
|
||||
proc get_float*(e: Engine, var_name: string, module_name = ""): float =
|
||||
e.get_var(var_name, module_name).get_float
|
||||
|
||||
proc get_int*(e: Engine, var_name: string, module_name = ""): int =
|
||||
e.get_var(var_name, module_name).get_int.to_int
|
||||
|
||||
proc get_bool*(e: Engine, var_name: string, module_name = ""): bool =
|
||||
let b = e.get_var(var_name, module_name).get_int
|
||||
return b == 1
|
||||
|
||||
proc get_string*(e: Engine, var_name: string, module_name = ""): string =
|
||||
result = e.get_var(var_name, module_name).get_str
|
||||
|
||||
proc call_int*(e: Engine, proc_name: string): int =
|
||||
e.call_proc(proc_name).get_int.to_int
|
||||
|
||||
proc reset_interpreter*() =
|
||||
interpreter = nil
|
||||
current = nil
|
||||
|
||||
proc resume*(e: Engine): bool =
|
||||
assert not e.ctx.is_nil
|
||||
assert e.pc > 0
|
||||
assert not e.tos.is_nil
|
||||
|
||||
set_active e
|
||||
result = try:
|
||||
discard exec_from_ctx(e.ctx, e.pc, e.tos)
|
||||
false
|
||||
except VMPause:
|
||||
e.exit_code.is_none
|
|
@ -1,2 +0,0 @@
|
|||
type
|
||||
Callback* = proc(delta: float): bool
|
10
src/game.nim
10
src/game.nim
|
@ -4,7 +4,7 @@ import godotapi / [input, input_event, gd_os, node, scene_tree, viewport,
|
|||
packed_scene, sprite, control, viewport,
|
||||
performance, label, theme, dynamic_font, resource_loader, main_loop,
|
||||
gd_os, project_settings, input_map, input_event, input_event_action]
|
||||
import core, globals, controllers/unit_controllers, models / serializers
|
||||
import core, globals, controllers / [node_controllers, script_controllers], models / serializers
|
||||
|
||||
type
|
||||
UserConfig = object
|
||||
|
@ -30,7 +30,8 @@ gdobj Game of Node:
|
|||
scale_factor* = 0.0
|
||||
rescale_at = get_mono_time()
|
||||
save_at = get_mono_time() + auto_save_interval
|
||||
unit_controller: UnitController
|
||||
node_controller: NodeController
|
||||
script_controller: ScriptController
|
||||
|
||||
method process*(delta: float) =
|
||||
let time = get_mono_time()
|
||||
|
@ -84,7 +85,6 @@ gdobj Game of Node:
|
|||
|
||||
proc init* =
|
||||
state.nodes.game = self
|
||||
self.unit_controller = UnitController.init
|
||||
let
|
||||
screen_scale = get_screen_scale(-1)
|
||||
work_dir = get_user_data_dir()
|
||||
|
@ -127,6 +127,8 @@ gdobj Game of Node:
|
|||
config.lib_dir = join_path(exe_dir.parent_dir, "lib", "vmlib")
|
||||
|
||||
print config
|
||||
self.node_controller = NodeController.init
|
||||
self.script_controller = ScriptController.init
|
||||
|
||||
method ready* =
|
||||
state.nodes.data = state.nodes.game.find_node("Level").get_node("data")
|
||||
|
@ -228,7 +230,7 @@ gdobj Game of Node:
|
|||
elif event.is_action_pressed("save_and_reload"):
|
||||
echo "reload all"
|
||||
save_world()
|
||||
UnitController.reload_all()
|
||||
self.script_controller.reload_all()
|
||||
self.get_tree().set_input_as_handled()
|
||||
elif event.is_action_pressed("pause"):
|
||||
state.paused = not state.paused
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
include compiler/nimeval
|
||||
export Interpreter, VmArgs, PCtx, PStackFrame, TLineInfo
|
||||
|
||||
# from nimeval. Added moduleName
|
||||
proc selectUniqueSymbol*(i: Interpreter; name: string;
|
||||
|
@ -51,12 +52,11 @@ proc load_module*(i: Interpreter, module_name, code: string) =
|
|||
|
||||
proc config*(i: Interpreter): ConfigRef = i.graph.config
|
||||
|
||||
when callVMExecHooks:
|
||||
proc registerExitHook*(i: Interpreter, hook: proc (c: PCtx, pc: int, tos: PStackFrame)) =
|
||||
(PCtx i.graph.vm).exitHook = hook
|
||||
proc registerExitHook*(i: Interpreter, hook: proc (c: PCtx, pc: int, tos: PStackFrame)) =
|
||||
(PCtx i.graph.vm).exitHook = hook
|
||||
|
||||
proc registerEnterHook*(i: Interpreter, hook: proc (c: PCtx, pc: int, tos: PStackFrame, instr: TInstr)) =
|
||||
(PCtx i.graph.vm).enterHook = hook
|
||||
proc registerEnterHook*(i: Interpreter, hook: proc (c: PCtx, pc: int, tos: PStackFrame, instr: TInstr)) =
|
||||
(PCtx i.graph.vm).enterHook = hook
|
||||
|
||||
proc registerLeaveHook*(i: Interpreter, hook: proc (c: PCtx, pc: int, tos: PStackFrame, instr: TInstr)) =
|
||||
(PCtx i.graph.vm).leaveHook = hook
|
||||
proc registerLeaveHook*(i: Interpreter, hook: proc (c: PCtx, pc: int, tos: PStackFrame, instr: TInstr)) =
|
||||
(PCtx i.graph.vm).leaveHook = hook
|
|
@ -0,0 +1,64 @@
|
|||
import std / [os, strformat, with, importutils]
|
||||
import pkg / compiler / ast except new_node
|
||||
import pkg / godot except print
|
||||
import pkg / [print], pkg / compiler / [vm, vmdef, options, lineinfos]
|
||||
import core, eval
|
||||
import models/types
|
||||
|
||||
export Interpreter, VmArgs, set_result
|
||||
|
||||
const
|
||||
STDLIB_PATHS = [".", "core", "pure", "pure/collections", "pure/concurrency", "std", "fusion"]
|
||||
MAIN_SCRIPT = "scripts/main.nim"
|
||||
|
||||
private_access ScriptCtx
|
||||
|
||||
proc init*(_: type Interpreter, script_dir, vmlib: string): Interpreter =
|
||||
let std_paths = STDLIB_PATHS.map_it join_path(vmlib, "stdlib", it)
|
||||
let source_paths = std_paths & join_path(vmlib, "enu") & @[parent_dir MAIN_SCRIPT] & @[script_dir]
|
||||
print source_paths
|
||||
result = create_interpreter(MAIN_SCRIPT, source_paths)
|
||||
|
||||
proc pause*(ctx: ScriptCtx) =
|
||||
ctx.pause_requested = true
|
||||
|
||||
proc load*(self: ScriptCtx, script_dir, file_name, code, vmlib: string) =
|
||||
self.ctx = nil
|
||||
self.pc = 0
|
||||
self.tos = nil
|
||||
self.code = code
|
||||
self.module_name = file_name.split_file.name
|
||||
self.file_name = file_name
|
||||
|
||||
proc run*(self: ScriptCtx): bool =
|
||||
self.exit_code = none(int)
|
||||
self.errors = @[]
|
||||
try:
|
||||
self.interpreter.load_module(self.file_name, self.code)
|
||||
result = false
|
||||
except VMPause:
|
||||
result = self.exit_code.is_none
|
||||
|
||||
proc call_proc*(self: ScriptCtx, proc_name: string, args: varargs[PNode]): tuple[paused: bool, result: PNode] =
|
||||
let foreign_proc = self.interpreter.select_routine(proc_name, module_name = self.module_name)
|
||||
if foreign_proc == nil:
|
||||
raise new_exception(VMError, &"script does not export a proc of the name: '{proc_name}'")
|
||||
result = try:
|
||||
(false, self.interpreter.call_routine(foreign_proc, args))
|
||||
except VMPause:
|
||||
(self.exit_code.is_none, nil)
|
||||
|
||||
proc get_var*(self: ScriptCtx, var_name: string, module_name: string): PNode =
|
||||
let sym = self.interpreter.select_unique_symbol(var_name, module_name = module_name)
|
||||
self.interpreter.get_global_value(sym)
|
||||
|
||||
proc resume*(self: ScriptCtx): bool =
|
||||
assert not self.ctx.is_nil
|
||||
assert self.pc > 0
|
||||
assert not self.tos.is_nil
|
||||
|
||||
result = try:
|
||||
discard exec_from_ctx(self.ctx, self.pc, self.tos)
|
||||
false
|
||||
except VMPause:
|
||||
self.exit_code.is_none
|
|
@ -1,5 +1,5 @@
|
|||
import pkg / [model_citizen]
|
||||
import models / [types, states, units, builds, bots, ground, colors, scripts, player_model]
|
||||
import models / [types, states, units, builds, bots, ground, colors, player_model]
|
||||
|
||||
export model_citizen except `%`
|
||||
export types, states, units, builds, bots, ground, colors, scripts
|
||||
export types, states, units, builds, bots, ground, colors
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
import std / [math, sugar, monotimes]
|
||||
import pkg / model_citizen
|
||||
import core, models / [types, states, scripts, units], engine / engine
|
||||
import core, models / [types, states, units]
|
||||
include "default_robot.nim.nimf"
|
||||
|
||||
let state = GameState.active
|
||||
|
||||
method code_template*(self: Bot, imports: string): string =
|
||||
result = default_robot(self.script_file, imports, self.script_ctx.is_clone)
|
||||
result = default_robot(self.script_file, imports)
|
||||
|
||||
method on_begin_move*(self: Bot, direction: Vector3, steps: float, moving_mode: int): Callback =
|
||||
# move_mode param is ignored
|
||||
|
@ -24,7 +24,8 @@ method on_begin_move*(self: Bot, direction: Vector3, steps: float, moving_mode:
|
|||
else:
|
||||
self.velocity.touch(moving * self.speed)
|
||||
return true
|
||||
active_ctx().start_advance_timer()
|
||||
# TODO?
|
||||
# active_ctx().start_advance_timer()
|
||||
|
||||
method on_begin_turn*(self: Bot, axis: Vector3, degrees: float, move_mode: int): Callback =
|
||||
# move mode param is ignored
|
||||
|
@ -39,24 +40,25 @@ method on_begin_turn*(self: Bot, axis: Vector3, degrees: float, move_mode: int):
|
|||
else:
|
||||
self.transform.basis = final_basis
|
||||
false
|
||||
active_ctx().start_advance_timer()
|
||||
# TODO?
|
||||
# active_ctx().start_advance_timer()
|
||||
|
||||
method load_vars*(self: Bot) =
|
||||
let old_speed = self.speed
|
||||
let ctx = self.script_ctx
|
||||
self.speed = ctx.engine.get_float("speed", ctx.engine.module_name)
|
||||
let scale = ctx.engine.get_float("scale", ctx.engine.module_name)
|
||||
if scale != self.scale:
|
||||
var basis = self.transform.basis
|
||||
basis.set_scale(vec3(scale, scale, scale))
|
||||
self.transform.basis = basis
|
||||
self.scale = scale
|
||||
# method load_vars*(self: Bot) =
|
||||
# let old_speed = self.speed
|
||||
# let ctx = self.script_ctx
|
||||
# self.speed = ctx.engine.get_float("speed", ctx.engine.module_name)
|
||||
# let scale = ctx.engine.get_float("scale", ctx.engine.module_name)
|
||||
# if scale != self.scale:
|
||||
# var basis = self.transform.basis
|
||||
# basis.set_scale(vec3(scale, scale, scale))
|
||||
# self.transform.basis = basis
|
||||
# self.scale = scale
|
||||
|
||||
method on_script_loaded*(self: Bot) =
|
||||
let e = self.script_ctx.engine
|
||||
e.expose "play", proc(a: VmArgs): bool =
|
||||
self.animation.value = get_string(a, 0)
|
||||
return false
|
||||
# method on_script_loaded*(self: Bot) =
|
||||
# let e = self.script_ctx.engine
|
||||
# e.expose "play", proc(a: VmArgs): bool =
|
||||
# self.animation.value = get_string(a, 0)
|
||||
# return false
|
||||
|
||||
proc bot_at*(state: GameState, position: Vector3): Bot =
|
||||
for unit in state.units:
|
||||
|
@ -64,6 +66,7 @@ proc bot_at*(state: GameState, position: Vector3): Bot =
|
|||
return Bot(unit)
|
||||
|
||||
method reset*(self: Bot) =
|
||||
self.transform.value = self.start_transform
|
||||
self.animation.value = ""
|
||||
self.units.clear()
|
||||
|
||||
|
@ -79,7 +82,8 @@ proc init*(_: type Bot, transform = Transform.init, clone_of: Bot = nil, global
|
|||
animation: ZenValue[string].init,
|
||||
energy: ZenValue[float].init,
|
||||
speed: 1.0,
|
||||
clone_of: clone_of
|
||||
clone_of: clone_of,
|
||||
frame_delta: ZenValue[float].init
|
||||
)
|
||||
if global: self.flags += Global
|
||||
|
||||
|
@ -108,7 +112,7 @@ proc init*(_: type Bot, transform = Transform.init, clone_of: Bot = nil, global
|
|||
|
||||
result = self
|
||||
|
||||
method clone*(self: Bot, clone_to: Unit, ctx: ScriptCtx): Unit =
|
||||
method clone*(self: Bot, clone_to: Unit): Unit =
|
||||
var transform = clone_to.transform.value
|
||||
result = Bot.init(transform = transform, clone_of = self)
|
||||
result.parent = clone_to
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import std / [hashes, tables, sets, options, sequtils, math, wrapnils, monotimes, sugar]
|
||||
import pkg / [model_citizen, print]
|
||||
import core, models / [types, states, bots, colors, units, scripts], engine / engine
|
||||
import core, models / [types, states, bots, colors, units]
|
||||
const BufferSize = vec3(16, 16, 16)
|
||||
|
||||
include "default_builder.nim.nimf"
|
||||
|
@ -213,7 +213,7 @@ method on_begin_move*(self: Build, direction: Vector3, steps: float, move_mode:
|
|||
self.voxels_remaining_this_frame -= 1
|
||||
self.drop_block()
|
||||
result = count.float < steps
|
||||
active_ctx().start_advance_timer()
|
||||
#active_ctx().start_advance_timer()
|
||||
|
||||
method on_begin_turn*(self: Build, axis: Vector3, degrees: float, move_mode: int): Callback =
|
||||
let map = {LEFT: UP, RIGHT: DOWN, UP: RIGHT, DOWN: LEFT}.to_table
|
||||
|
@ -235,7 +235,7 @@ method on_begin_turn*(self: Build, axis: Vector3, degrees: float, move_mode: int
|
|||
# TODO?
|
||||
self.transform.value = final_transform
|
||||
false
|
||||
active_ctx().start_advance_timer()
|
||||
#active_ctx().start_advance_timer()
|
||||
else:
|
||||
let axis = self.draw_transform.basis.xform(axis)
|
||||
self.draw_transform.basis = self.draw_transform.basis.rotated(axis, deg_to_rad(degrees))
|
||||
|
@ -245,6 +245,7 @@ proc reset_state(self: Build) =
|
|||
self.draw_transform = Transform.init
|
||||
|
||||
method reset*(self: Build) =
|
||||
self.transform.value = self.start_transform
|
||||
self.reset_state()
|
||||
let chunks = self.chunks.value
|
||||
for chunk_id, chunk in chunks:
|
||||
|
@ -256,65 +257,65 @@ method reset*(self: Build) =
|
|||
self.chunks.del(chunk_id)
|
||||
self.units.clear()
|
||||
|
||||
proc set_vars*(self: Build) =
|
||||
let engine = self.script_ctx.engine
|
||||
let module_name = engine.module_name
|
||||
# proc set_vars*(self: Build) =
|
||||
# let engine = self.script_ctx.engine
|
||||
# let module_name = engine.module_name
|
||||
#
|
||||
# engine.call_proc("set_vars", module_name = module_name, action_index(self.color).int,
|
||||
# self.drawing, self.speed, self.scale, self.energy.value)
|
||||
#
|
||||
# method load_vars*(self: Build) =
|
||||
# let old_speed = self.speed
|
||||
# let ctx = self.script_ctx
|
||||
# self.speed = ctx.engine.get_float("speed", ctx.engine.module_name)
|
||||
#
|
||||
# let
|
||||
# e = ctx.engine
|
||||
# scale_factor = ctx.engine.get_float("scale", e.module_name).round(3)
|
||||
# self.color = action_colors[Colors(ctx.engine.get_int("color", e.module_name))]
|
||||
# self.drawing = ctx.engine.get_bool("drawing", e.module_name)
|
||||
# self.voxels_per_frame = if self.speed == 0:
|
||||
# float.high
|
||||
# else:
|
||||
# self.speed
|
||||
# if self.speed != old_speed:
|
||||
# self.voxels_remaining_this_frame = 0
|
||||
# if scale_factor != self.scale.round(3):
|
||||
# self.scale = scale_factor
|
||||
# var basis = self.transform.basis
|
||||
# basis.set_scale(vec3(scale_factor, scale_factor, scale_factor))
|
||||
# self.transform.basis = basis
|
||||
# self.energy.value = ctx.engine.get_float("energy", e.module_name).round(3)
|
||||
#
|
||||
# self.set_vars()
|
||||
|
||||
engine.call_proc("set_vars", module_name = module_name, action_index(self.color).int,
|
||||
self.drawing, self.speed, self.scale, self.energy.value)
|
||||
|
||||
method load_vars*(self: Build) =
|
||||
let old_speed = self.speed
|
||||
let ctx = self.script_ctx
|
||||
self.speed = ctx.engine.get_float("speed", ctx.engine.module_name)
|
||||
|
||||
let
|
||||
e = ctx.engine
|
||||
scale_factor = ctx.engine.get_float("scale", e.module_name).round(3)
|
||||
self.color = action_colors[Colors(ctx.engine.get_int("color", e.module_name))]
|
||||
self.drawing = ctx.engine.get_bool("drawing", e.module_name)
|
||||
self.voxels_per_frame = if self.speed == 0:
|
||||
float.high
|
||||
else:
|
||||
self.speed
|
||||
if self.speed != old_speed:
|
||||
self.voxels_remaining_this_frame = 0
|
||||
if scale_factor != self.scale.round(3):
|
||||
self.scale = scale_factor
|
||||
var basis = self.transform.basis
|
||||
basis.set_scale(vec3(scale_factor, scale_factor, scale_factor))
|
||||
self.transform.basis = basis
|
||||
self.energy.value = ctx.engine.get_float("energy", e.module_name).round(3)
|
||||
|
||||
self.set_vars()
|
||||
|
||||
method on_script_loaded*(self: Build) =
|
||||
var save_points: Table[string, tuple[transform: Transform, color: Color, drawing: bool]]
|
||||
let e = self.script_ctx.engine
|
||||
self.voxels_remaining_this_frame = 0
|
||||
e.expose "set_energy", proc(a: VmArgs): bool =
|
||||
self.energy.value = get_float(a, 0)
|
||||
false
|
||||
e.expose "save", proc(a: VmArgs): bool =
|
||||
self.load_vars()
|
||||
let name = get_string(a, 0)
|
||||
save_points[name] = (self.transform.value, self.color, self.drawing)
|
||||
false
|
||||
e.expose "restore", proc(a: VmArgs): bool =
|
||||
let name = get_string(a, 0)
|
||||
(self.transform.value, self.color, self.drawing) = save_points[name]
|
||||
self.set_vars()
|
||||
false
|
||||
e.expose "reset", proc(a: VmArgs): bool =
|
||||
let clear = get_bool(a, 0)
|
||||
if clear:
|
||||
self.reset()
|
||||
else:
|
||||
self.reset_state()
|
||||
false
|
||||
e.expose "load_defaults", proc(a: VmArgs): bool =
|
||||
self.set_vars()
|
||||
false
|
||||
# method on_script_loaded*(self: Build) =
|
||||
# var save_points: Table[string, tuple[transform: Transform, color: Color, drawing: bool]]
|
||||
# let e = self.script_ctx.engine
|
||||
# self.voxels_remaining_this_frame = 0
|
||||
# e.expose "set_energy", proc(a: VmArgs): bool =
|
||||
# self.energy.value = get_float(a, 0)
|
||||
# false
|
||||
# e.expose "save", proc(a: VmArgs): bool =
|
||||
# self.load_vars()
|
||||
# let name = get_string(a, 0)
|
||||
# save_points[name] = (self.transform.value, self.color, self.drawing)
|
||||
# false
|
||||
# e.expose "restore", proc(a: VmArgs): bool =
|
||||
# let name = get_string(a, 0)
|
||||
# (self.transform.value, self.color, self.drawing) = save_points[name]
|
||||
# self.set_vars()
|
||||
# false
|
||||
# e.expose "reset", proc(a: VmArgs): bool =
|
||||
# let clear = get_bool(a, 0)
|
||||
# if clear:
|
||||
# self.reset()
|
||||
# else:
|
||||
# self.reset_state()
|
||||
# false
|
||||
# e.expose "load_defaults", proc(a: VmArgs): bool =
|
||||
# self.set_vars()
|
||||
# false
|
||||
|
||||
proc init*(_: type Build, transform = Transform.init, color = default_color,
|
||||
clone_of: Unit = nil, global = true, bot_collisions = true): Build =
|
||||
|
@ -335,7 +336,8 @@ proc init*(_: type Build, transform = Transform.init, color = default_color,
|
|||
bounds: Zen.init(init_aabb(vec3(), vec3(-1, -1, -1))),
|
||||
speed: 1.0,
|
||||
clone_of: clone_of,
|
||||
bot_collisions: bot_collisions
|
||||
bot_collisions: bot_collisions,
|
||||
frame_delta: ZenValue[float].init
|
||||
)
|
||||
if global: self.flags += Global
|
||||
|
||||
|
@ -385,7 +387,7 @@ method off_collision*(self: Build, partner: Model) =
|
|||
if self.script_ctx:
|
||||
self.script_ctx.timer = get_mono_time()
|
||||
|
||||
method clone*(self: Build, clone_to: Unit, ctx: ScriptCtx): Unit =
|
||||
method clone*(self: Build, clone_to: Unit): Unit =
|
||||
var transform = clone_to.transform.value
|
||||
var global = true
|
||||
if clone_to of Build:
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
#? stdtmpl
|
||||
#proc default_robot(file_name, imports: string, is_clone: bool): string =
|
||||
import types, class_macros, players
|
||||
const is_clone = ${is_clone}
|
||||
#proc default_robot(file_name, imports: string): string =
|
||||
import system except echo
|
||||
import types, class_macros, players, state_machine
|
||||
|
||||
let global_default = true
|
||||
${imports}
|
||||
|
||||
load_enu_script "${file_name}", "robot", ${is_clone}
|
||||
{.experimental: "overloadableEnums".}
|
||||
load_enu_script "${file_name}", "robot"
|
||||
|
||||
quit()
|
||||
me.quit()
|
||||
|
|
|
@ -1,14 +0,0 @@
|
|||
import std / [monotimes]
|
||||
import models / [types], engine / engine
|
||||
import core
|
||||
|
||||
const ADVANCE_STEP* = 0.5.seconds
|
||||
|
||||
var ctxs*: Table[Engine, ScriptCtx]
|
||||
var unit_ctxs*: Table[Engine, Unit]
|
||||
|
||||
proc active_unit*(): Unit = unit_ctxs[active_engine()]
|
||||
proc active_ctx*(): ScriptCtx = ctxs[active_engine()]
|
||||
|
||||
proc start_advance_timer*(ctx: ScriptCtx) =
|
||||
ctx.timer = get_mono_time() + ADVANCE_STEP
|
|
@ -1,6 +1,6 @@
|
|||
import std / [json, jsonutils, sugar, tables, os, strutils]
|
||||
import pkg / print
|
||||
import core, models, engine / contexts
|
||||
import core, models
|
||||
|
||||
let state = GameState.active
|
||||
|
||||
|
@ -130,8 +130,8 @@ proc load_units(parent: Unit) =
|
|||
|
||||
proc load_world*() =
|
||||
dont_join = true
|
||||
retry_failures = true
|
||||
#retry_failures = true
|
||||
load_units(nil)
|
||||
retry_failed_scripts()
|
||||
retry_failures = false
|
||||
#retry_failed_scripts()
|
||||
#retry_failures = false
|
||||
dont_join = false
|
||||
|
|
|
@ -3,11 +3,11 @@ import godotapi/node
|
|||
import pkg/model_citizen
|
||||
import pkg/core/godotcoretypes except Color
|
||||
import pkg / core / [vector3, basis, aabb, godotbase]
|
||||
|
||||
import core, models/colors, engine/engine, utils/transforms
|
||||
import core, models/colors, utils/transforms, libs/eval
|
||||
|
||||
export Vector3, Transform, vector3, transforms, basis, AABB, aabb
|
||||
export godotbase except print
|
||||
export Interpreter
|
||||
|
||||
type
|
||||
TargetFlags* = enum
|
||||
|
@ -51,7 +51,6 @@ type
|
|||
paused*: bool
|
||||
|
||||
Model* = ref object of RootObj
|
||||
|
||||
target_point*: Vector3
|
||||
target_normal*: Vector3
|
||||
flags*: ZenSet[ModelFlags]
|
||||
|
@ -82,6 +81,7 @@ type
|
|||
energy*: ZenValue[float]
|
||||
clone_of*: Unit
|
||||
collisions*: seq[tuple[model: Model, normal: Vector3]]
|
||||
frame_delta*: ZenValue[float]
|
||||
|
||||
Bot* = ref object of Unit
|
||||
animation*: ZenValue[string]
|
||||
|
@ -107,16 +107,6 @@ type
|
|||
bounds*: ZenValue[AABB]
|
||||
bot_collisions*: bool
|
||||
|
||||
Callback* = proc(delta: float): bool
|
||||
ScriptCtx* = ref object
|
||||
script*: string
|
||||
engine*: Engine
|
||||
timer*: MonoTime
|
||||
load_vars*: proc()
|
||||
is_clone*: bool
|
||||
speed*: float
|
||||
retry_on_nil*: bool
|
||||
|
||||
Config* = ref object
|
||||
font_size*: int
|
||||
dock_icon_size*: float
|
||||
|
@ -129,6 +119,39 @@ type
|
|||
scene*: string
|
||||
lib_dir*: string
|
||||
|
||||
ScriptCtx* = ref object
|
||||
script*: string
|
||||
timer*: MonoTime
|
||||
load_vars*: proc()
|
||||
is_clone*: bool
|
||||
ctx: PCtx
|
||||
pc: int
|
||||
tos: PStackFrame
|
||||
line_changed*: proc(current, previous: TLineInfo)
|
||||
current_line*: TLineInfo
|
||||
previous_line: TLineInfo
|
||||
pause_requested: bool
|
||||
module_name*: string
|
||||
file_name: string
|
||||
exit_code*: Option[int]
|
||||
errors*: seq[tuple[msg: string, info: TLineInfo]]
|
||||
callback*: Callback
|
||||
saved_callback*: Callback
|
||||
action_running*: bool
|
||||
running*: bool
|
||||
interpreter*: Interpreter
|
||||
code*: string
|
||||
|
||||
VMError* = object of CatchableError
|
||||
|
||||
VMQuit* = object of VMError
|
||||
info*: TLineInfo
|
||||
|
||||
VMPause* = object of CatchableError
|
||||
|
||||
Callback* = proc(delta: float): bool
|
||||
|
||||
# TODO: this shouldn't be here
|
||||
proc local_to*(self: Vector3, unit: Unit): Vector3 =
|
||||
result = self
|
||||
var unit = unit
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import std / [os, sugar]
|
||||
import pkg / model_citizen
|
||||
import godotapi / node
|
||||
import core, models / [types, states], engine / engine
|
||||
import core, models / [types, states], libs / interpreters
|
||||
|
||||
proc init*(_: type Model, node: Node): Model =
|
||||
result = Model(flags: ZenSet[ModelFlags].init, node: node)
|
||||
|
@ -50,7 +50,7 @@ method on_begin_move*(self: Unit, direction: Vector3, steps: float, move_mode: i
|
|||
method on_begin_turn*(self: Unit, direction: Vector3, degrees: float, move_mode: int): Callback {.base.} =
|
||||
quit "override me"
|
||||
|
||||
method clone*(self: Unit, clone_to: Unit, ctx: ScriptCtx): Unit {.base.} =
|
||||
method clone*(self: Unit, clone_to: Unit): Unit {.base.} =
|
||||
quit "override me"
|
||||
|
||||
method code_template*(self: Unit, imports: string): string {.base.} =
|
||||
|
|
|
@ -5,7 +5,7 @@ import godotapi / [kinematic_body, spatial, input, input_event,
|
|||
input_event_mouse_motion, input_event_joypad_motion,
|
||||
ray_cast, scene_tree, input_event_pan_gesture, viewport, camera, global_constants,
|
||||
collision_shape, kinematic_collision]
|
||||
import core, globals, game, engine/engine, engine/contexts, models / [units, player_model], world / nodes
|
||||
import core, globals, game, models / [units, player_model], world / nodes
|
||||
import aim_target, models
|
||||
|
||||
proc handle_collisions(self: PlayerModel, collisions: seq[KinematicCollision]) {.inline.} =
|
||||
|
@ -107,7 +107,8 @@ gdobj Player of KinematicBody:
|
|||
|
||||
self.position_start = self.camera_rig.translation
|
||||
state.nodes.player = self
|
||||
self.load_script()
|
||||
# TODO
|
||||
# self.load_script()
|
||||
state.target_flags.changes:
|
||||
if MouseCaptured.removed:
|
||||
self.skip_next_mouse_move = true
|
||||
|
@ -148,28 +149,28 @@ gdobj Player of KinematicBody:
|
|||
self.aim_ray.cast_to = vec3(0, 0, -100)
|
||||
self.aim_target.update(self.aim_ray)
|
||||
|
||||
proc load_script() =
|
||||
let ctx = ScriptCtx.init
|
||||
ctx.script = config.lib_dir & "/enu/players.nim"
|
||||
let code = read_file ctx.script
|
||||
ctx.engine.load(config.script_dir, ctx.script, code, config.lib_dir, "")
|
||||
ctx.engine.expose "quit", proc(a: VmArgs): bool =
|
||||
engine.pause(ctx.engine)
|
||||
ctx.engine.running = false
|
||||
result = false
|
||||
ctx.engine.expose "get_position", proc(a: VmArgs): bool =
|
||||
let n = self.global_transform.origin.to_node
|
||||
a.set_result(n)
|
||||
return false
|
||||
ctx.engine.expose "get_rotation", proc(a: VmArgs): bool =
|
||||
a.set_result(self.rotation_degrees.to_node)
|
||||
return false
|
||||
ctx.engine.expose "set_velocity", proc(a: VmArgs): bool =
|
||||
let v = a.get_vec3(0)
|
||||
self.velocity = v
|
||||
ctx.engine.expose "get_velocity", proc(a: VmArgs): bool =
|
||||
a.set_result(self.velocity.to_node)
|
||||
discard ctx.engine.run()
|
||||
# proc load_script() =
|
||||
# let ctx = ScriptCtx.init
|
||||
# ctx.script = config.lib_dir & "/enu/players.nim"
|
||||
# let code = read_file ctx.script
|
||||
# ctx.engine.load(config.script_dir, ctx.script, code, config.lib_dir, "")
|
||||
# ctx.engine.expose "quit", proc(a: VmArgs): bool =
|
||||
# engine.pause(ctx.engine)
|
||||
# ctx.engine.running = false
|
||||
# result = false
|
||||
# ctx.engine.expose "get_position", proc(a: VmArgs): bool =
|
||||
# let n = self.global_transform.origin.to_node
|
||||
# a.set_result(n)
|
||||
# return false
|
||||
# ctx.engine.expose "get_rotation", proc(a: VmArgs): bool =
|
||||
# a.set_result(self.rotation_degrees.to_node)
|
||||
# return false
|
||||
# ctx.engine.expose "set_velocity", proc(a: VmArgs): bool =
|
||||
# let v = a.get_vec3(0)
|
||||
# self.velocity = v
|
||||
# ctx.engine.expose "get_velocity", proc(a: VmArgs): bool =
|
||||
# a.set_result(self.velocity.to_node)
|
||||
# discard ctx.engine.run()
|
||||
|
||||
method physics_process*(delta: float) =
|
||||
trace:
|
||||
|
|
|
@ -3,7 +3,7 @@ import pkg / [godot, model_citizen]
|
|||
import pkg / compiler / [lineinfos]
|
||||
import godotapi / [text_edit, scene_tree, node, input_event, global_constants,
|
||||
input_event_key, style_box_flat]
|
||||
import core, globals, engine / engine
|
||||
import core, globals
|
||||
import models except Color
|
||||
|
||||
let state = GameState.active
|
||||
|
@ -14,22 +14,22 @@ gdobj Editor of TextEdit:
|
|||
mouse_was_captured = false
|
||||
og_bg_color: Color
|
||||
dirty = false
|
||||
open_engine: Engine
|
||||
open_script_ctx: ScriptCtx
|
||||
|
||||
proc set_open_engine() =
|
||||
proc set_open_script_ctx() =
|
||||
# TODO: yuck
|
||||
var current = self.open_engine
|
||||
var current = self.open_script_ctx
|
||||
if not state.open_unit.value.is_nil and state.open_unit.value.script_ctx:
|
||||
current = state.open_unit.value.script_ctx.engine
|
||||
if self.open_engine != current:
|
||||
if self.open_engine:
|
||||
self.open_engine.line_changed = nil
|
||||
current = state.open_unit.value.script_ctx
|
||||
if self.open_script_ctx != current:
|
||||
if self.open_script_ctx:
|
||||
self.open_script_ctx.line_changed = nil
|
||||
|
||||
if not state.open_unit.value.is_nil and not state.open_unit.value.script_ctx.is_nil:
|
||||
self.open_engine = state.open_unit.value.script_ctx.engine
|
||||
if self.open_engine:
|
||||
self.executing_line = int self.open_engine.current_line.line - 1
|
||||
self.open_engine.line_changed = proc(current: TLineInfo, previous: TLineInfo) =
|
||||
self.open_script_ctx = state.open_unit.value.script_ctx
|
||||
if self.open_script_ctx:
|
||||
self.executing_line = int self.open_script_ctx.current_line.line - 1
|
||||
self.open_script_ctx.line_changed = proc(current: TLineInfo, previous: TLineInfo) =
|
||||
self.executing_line = int current.line - 1
|
||||
|
||||
proc indent_new_line() =
|
||||
|
@ -82,9 +82,9 @@ gdobj Editor of TextEdit:
|
|||
|
||||
proc highlight_errors =
|
||||
self.clear_executing_line()
|
||||
self.set_open_engine()
|
||||
if not self.open_engine.is_nil:
|
||||
for err in self.open_engine.errors:
|
||||
self.set_open_script_ctx()
|
||||
if not self.open_script_ctx.is_nil:
|
||||
for err in self.open_script_ctx.errors:
|
||||
self.set_line_as_marked(int64(err.info.line - 1), true)
|
||||
|
||||
proc `executing_line=`*(line: int) =
|
||||
|
@ -124,7 +124,7 @@ gdobj Editor of TextEdit:
|
|||
|
||||
elif Editing.added:
|
||||
self.visible = true
|
||||
self.set_open_engine()
|
||||
self.set_open_script_ctx()
|
||||
self.text = state.open_unit.value.code.value
|
||||
self.grab_focus()
|
||||
self.clear_errors()
|
||||
|
@ -133,8 +133,8 @@ gdobj Editor of TextEdit:
|
|||
elif Editing.removed:
|
||||
self.release_focus()
|
||||
self.visible = false
|
||||
if self.open_engine:
|
||||
self.open_engine.line_changed = nil
|
||||
self.open_engine = nil
|
||||
if self.open_script_ctx:
|
||||
self.open_script_ctx.line_changed = nil
|
||||
self.open_script_ctx = nil
|
||||
|
||||
self.configure_highlighting()
|
||||
|
|
|
@ -4,7 +4,7 @@ import pkg/model_citizen
|
|||
import godotapi / [scene_tree, kinematic_body, material, mesh_instance, spatial,
|
||||
input_event, animation_player, resource_loader, packed_scene]
|
||||
import globals, core, print
|
||||
import engine / [contexts, engine], models / [types, bots, units]
|
||||
import models / [types, bots, units]
|
||||
|
||||
gdobj BotNode of KinematicBody:
|
||||
var
|
||||
|
@ -77,9 +77,7 @@ gdobj BotNode of KinematicBody:
|
|||
self.unit.transform.pause self.transform_zid:
|
||||
self.unit.transform.value = self.transform
|
||||
|
||||
if self.unit.script_ctx:
|
||||
if self.unit.script_ctx.engine.running:
|
||||
self.unit.advance(delta)
|
||||
self.unit.frame_delta.touch delta
|
||||
|
||||
let bot_scene = load("res://components/BotNode.tscn") as PackedScene
|
||||
proc init*(_: type BotNode): BotNode =
|
||||
|
|
|
@ -4,7 +4,6 @@ import pkg / [print, model_citizen]
|
|||
import godotapi / [node, voxel_terrain, voxel_mesher_blocky, voxel_tool, voxel_library, shader_material,
|
||||
resource_loader, packed_scene]
|
||||
import models / [types, builds, colors, units], globals
|
||||
import engine / contexts
|
||||
|
||||
const
|
||||
highlight_energy = 1.0
|
||||
|
@ -100,13 +99,11 @@ gdobj BuildNode of VoxelTerrain:
|
|||
|
||||
method process(delta: float) =
|
||||
if self.unit:
|
||||
if self.unit.script_ctx:
|
||||
if self.unit.script_ctx.engine.running:
|
||||
self.unit.advance(delta)
|
||||
|
||||
# self.unit.transform.pause self.transform_zid:
|
||||
# self.unit.transform.value = self.transform
|
||||
|
||||
self.unit.frame_delta.touch delta
|
||||
|
||||
proc setup*(unit: Build) =
|
||||
let was_skipping_join = dont_join
|
||||
dont_join = true
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
This isn't a test suite. These are tests that I found useful for whatever reason during development. They don't
|
||||
validate much of anything, and many will fail. Eventually this will be fixed.
|
|
@ -4,3 +4,4 @@ switch("path", "$projectDir/../../vmlib")
|
|||
switch("path", this_dir())
|
||||
--define:vmExecHooks
|
||||
--define:useRealtimeGC
|
||||
--experimental:dynamicBindSym
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
import enu/types, enu/class_macros
|
||||
import macros except name
|
||||
import pkg / print
|
||||
const is_clone = false
|
||||
import enu/base_api
|
||||
import enu/state_machine
|
||||
|
||||
load_enu_script "potato_code.nim", "robot", false
|
||||
load_enu_script "potato_code.nim", "robot"
|
||||
|
||||
var clone_obj*: PotatoType
|
||||
me.ctrl.create_new = proc() =
|
||||
potato_cradle = clone_obj
|
||||
|
||||
|
|
|
@ -1,10 +0,0 @@
|
|||
import enu/types, enu/class_macros
|
||||
import macros except name
|
||||
import pkg / print
|
||||
|
||||
import potato_class
|
||||
|
||||
const is_clone = true
|
||||
load_enu_script "potato_code.nim", "robot", true
|
||||
|
||||
clone_obj = me
|
|
@ -1,12 +1,7 @@
|
|||
name potato(length = 5, width = 2, color = red, label = "hi", friendly = true)
|
||||
|
||||
assert length == 5
|
||||
assert me.length == 5
|
||||
when not is_clone:
|
||||
assert potato.length == 5
|
||||
assert potato.length == 5
|
||||
me.length = 10
|
||||
assert length == 10
|
||||
potato.label = "red"
|
||||
when not is_clone:
|
||||
assert label == "red"
|
||||
assert me.label == "red"
|
||||
assert me.label == "red"
|
||||
|
|
|
@ -1,3 +1,10 @@
|
|||
name bot1(named_property = "myprop")
|
||||
|
||||
echo "from bot1"
|
||||
|
||||
var b = bot1
|
||||
forward 1
|
||||
move me
|
||||
back 1
|
||||
|
||||
register_active b
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
#name bot2
|
||||
#var b = bot1.new(global = false)
|
||||
|
||||
echo "from bot2"
|
||||
var b = bot1.new(global = false)
|
||||
|
||||
echo "from bot2 ", b.speed
|
||||
assert b.named_property == "myprop"
|
||||
|
||||
echo b.named_property
|
||||
b = bot1.new(named_property = "testing")
|
||||
# TODO: verify this works:
|
||||
# assert b.named_property == "testing"
|
||||
assert bot1_cradle.named_property == "testing"
|
||||
|
||||
echo "passed"
|
||||
assert b.named_property == "testing"
|
||||
echo b.named_property
|
||||
#
|
||||
# echo "passed"
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
import std / [sugar, os]
|
||||
import engine / [engine, contexts], core, models
|
||||
import controllers/script_controllers, core, models
|
||||
|
||||
#import pkg / compiler / [vm, vmdef, options, lineinfos, ast]
|
||||
import libs / [interpreters, eval]
|
||||
|
||||
var state = GameState.active
|
||||
|
||||
|
@ -8,21 +11,21 @@ state.logger = proc(level, msg: string) =
|
|||
|
||||
state.config.script_dir = current_source_path().parent_dir / "scripts" / "instancing"
|
||||
state.config.lib_dir = current_source_path().parent_dir / ".." / ".." / "vmlib"
|
||||
# state.config.lib_dir = current_source_path().parent_dir / ".." / ".." / "vmlib"
|
||||
# var b = Bot.init
|
||||
let controller = ScriptController.init
|
||||
|
||||
proc create(id: string): Bot =
|
||||
result = Bot.init()
|
||||
result.id = id
|
||||
|
||||
result.script_ctx = ScriptCtx.init
|
||||
unit_ctxs[result.script_ctx.engine] = result
|
||||
result.script_ctx.script = result.script_file
|
||||
result.load_script()
|
||||
|
||||
let bot1 = create("bot_script_1")
|
||||
state.units.add bot1
|
||||
let bot2 = create("bot_script_2")
|
||||
|
||||
bot2.units[0].load_script
|
||||
|
||||
bot2.advance(0.1)
|
||||
bot2.units[1].load_script
|
||||
bot2.advance(0.1)
|
||||
state.units.add bot2
|
||||
#
|
||||
# bot2.units[0].load_script
|
||||
#
|
||||
# bot2.advance(0.1)
|
||||
# bot2.units[1].load_script
|
||||
# bot2.advance(0.1)
|
||||
|
|
|
@ -1,6 +1,13 @@
|
|||
import potato_class, potato_clone, enu/types
|
||||
|
||||
import potato_class, enu/types, pkg/print
|
||||
import enu/base_api, enu/state_machine
|
||||
var move_mode = 1
|
||||
var me = ScriptNode()
|
||||
let p = potato.new(label = "orange", color = green)
|
||||
var target = p
|
||||
forward 10
|
||||
turn right
|
||||
p.turn right
|
||||
|
||||
assert p.color == green
|
||||
assert not p.is_nil
|
||||
assert p of PotatoType
|
||||
|
|
|
@ -1,89 +1,151 @@
|
|||
import random, types
|
||||
import std / [random, strutils, math]
|
||||
import types, state_machine
|
||||
|
||||
proc register_active*(self: ScriptNode) = discard
|
||||
proc new_instance*(src, dest: ScriptNode) = discard
|
||||
# API
|
||||
proc quit*(exit_code = 0) = discard
|
||||
proc sleep*(seconds = 1.0, ctx: Context = nil) = discard
|
||||
proc create_new() = discard
|
||||
proc stash() = discard
|
||||
proc add_stashed() = discard
|
||||
proc get_position(): Vector3 = discard
|
||||
proc set_position(position: Vector3) = discard
|
||||
proc get_rotation(): Vector3 = discard
|
||||
proc collision(node: ScriptNode): Vector3 = discard
|
||||
proc quit*(self: ScriptNode, exit_code = 0) = discard
|
||||
proc sleep*(self: ScriptNode, seconds = 1.0, ctx: Context = nil) = discard
|
||||
proc create_new*(self: ScriptNode) = discard
|
||||
proc position*(self: ScriptNode): Vector3 = discard
|
||||
proc `position=`*(self: ScriptNode, position: Vector3) = discard
|
||||
proc rotation*(self: ScriptNode): Vector3 = discard
|
||||
proc collision*(self: ScriptNode, node: ScriptNode): Vector3 = discard
|
||||
|
||||
var target: ScriptNode = me
|
||||
proc action_running(self: ScriptNode): bool = discard
|
||||
proc `action_running=`(self: ScriptNode, value: bool) = discard
|
||||
|
||||
proc add(node: ScriptNode) =
|
||||
node.stash()
|
||||
add_stashed()
|
||||
proc yield_script(self: ScriptNode) = discard
|
||||
|
||||
proc distance(node: ScriptNode): float =
|
||||
node.get_position().distance_to(get_position())
|
||||
|
||||
proc near(node: ScriptNode, less_than = 5.0): bool =
|
||||
result = node.distance < less_than
|
||||
|
||||
proc far(node: ScriptNode, greater_than = 100.0): bool =
|
||||
result = node.distance > greater_than
|
||||
proc begin_move(self: ScriptNode, direction: Vector3, steps: float, move_mode: int) = discard
|
||||
proc begin_turn(self: ScriptNode, axis: Vector3, steps: float, move_mode: int) = discard
|
||||
|
||||
proc echo_console(msg: string) = discard
|
||||
proc echo(msg: varargs[string, `$`]) = echo_console msg.join
|
||||
proc echo*(msg: varargs[string, `$`]) = echo_console msg.join
|
||||
|
||||
proc begin_move(direction: Vector3, steps: float, moving: int) = discard
|
||||
proc begin_turn(axis: Vector3, steps: float, moving: int) = discard
|
||||
#
|
||||
# var target: ScriptNode = me
|
||||
#
|
||||
# proc add(node: ScriptNode) =
|
||||
# node.stash()
|
||||
# add_stashed()
|
||||
#
|
||||
# proc distance(node: ScriptNode): float =
|
||||
# node.get_position().distance_to(get_position())
|
||||
#
|
||||
# proc near(node: ScriptNode, less_than = 5.0): bool =
|
||||
# result = node.distance < less_than
|
||||
#
|
||||
# proc far(node: ScriptNode, greater_than = 100.0): bool =
|
||||
# result = node.distance > greater_than
|
||||
#
|
||||
# proc echo_console(msg: string) = discard
|
||||
# proc echo(msg: varargs[string, `$`]) = echo_console msg.join
|
||||
#
|
||||
|
||||
proc forward(steps = 1.0, ctx: Context = nil) = target.ctrl.begin_move(FORWARD, steps, me, move_mode)
|
||||
proc back(steps = 1.0, ctx: Context = nil) = target.ctrl.begin_move(BACK, steps, me, move_mode)
|
||||
proc left(steps = 1.0, ctx: Context = nil): Direction {.discardable.} = target.ctrl.begin_move(LEFT, steps, me, move_mode)
|
||||
proc right(steps = 1.0, ctx: Context = nil): Direction {.discardable.} = target.ctrl.begin_move(RIGHT, steps, me, move_mode)
|
||||
proc l(steps = 1.0, ctx: Context = nil): Direction {.discardable.} = left(steps)
|
||||
proc r(steps = 1.0, ctx: Context = nil): Direction {.discardable.} = right(steps)
|
||||
proc up(steps = 1.0, ctx: Context = nil): Direction {.discardable.} = target.ctrl.begin_move(UP, steps, me, move_mode)
|
||||
proc u(steps = 1.0, ctx: Context = nil): Direction {.discardable.} = up(steps)
|
||||
proc down(steps = 1.0, ctx: Context = nil): Direction {.discardable.} = target.ctrl.begin_move(DOWN, steps, me, move_mode)
|
||||
proc d(steps = 1.0, ctx: Context = nil): Direction {.discardable.} = down(steps)
|
||||
template wait(self: ScriptNode, body: untyped) =
|
||||
mixin action_running, `action_running=`, yield_script
|
||||
`action_running=`(self, true)
|
||||
body
|
||||
while self.action_running and self.advance_state_machine():
|
||||
self.yield_script()
|
||||
|
||||
proc set_global(global: bool) = discard
|
||||
proc get_global(): bool = discard
|
||||
template forward*(self: ScriptNode, steps = 1.0) =
|
||||
mixin begin_move, wait
|
||||
me.wait self.begin_move(FORWARD, steps, move_mode)
|
||||
|
||||
proc turn(direction: proc(steps = 1.0, ctx: Context = nil): Direction, degrees = 90.0) =
|
||||
var axis = if direction == r: RIGHT
|
||||
elif direction == right: RIGHT
|
||||
elif direction == l: LEFT
|
||||
elif direction == left: LEFT
|
||||
else: Vector3()
|
||||
template back*(self: ScriptNode, steps = 1.0) =
|
||||
mixin begin_move, wait
|
||||
me.wait self.begin_move(BACK, steps, move_mode)
|
||||
|
||||
if axis == Vector3():
|
||||
axis = if direction == u: UP
|
||||
elif direction == up: UP
|
||||
elif direction == d: DOWN
|
||||
elif direction == down: DOWN
|
||||
else: Vector3()
|
||||
template left*(self: ScriptNode, steps = 1.0) =
|
||||
mixin begin_move, wait
|
||||
me.wait self.begin_move(LEFT, steps, move_mode)
|
||||
|
||||
assert axis != Vector3(), "Invalid direction"
|
||||
target.ctrl.begin_turn(axis, degrees, me, move_mode)
|
||||
template right*(self: ScriptNode, steps = 1.0) =
|
||||
mixin begin_move, wait
|
||||
me.wait self.begin_move(RIGHT, steps, move_mode)
|
||||
|
||||
proc turn(degrees: float, ctx: Context = nil) =
|
||||
template up*(self: ScriptNode, steps = 1.0) =
|
||||
mixin begin_move, wait
|
||||
me.wait self.begin_move(UP, steps, move_mode)
|
||||
|
||||
template down*(self: ScriptNode, steps = 1.0) =
|
||||
mixin begin_move, wait
|
||||
me.wait self.begin_move(DOWN, steps, move_mode)
|
||||
|
||||
template l*(self: ScriptNode, steps = 1.0) = self.left(steps)
|
||||
template r*(self: ScriptNode, steps = 1.0) = self.right(steps)
|
||||
template u*(self: ScriptNode, steps = 1.0) = self.up(steps)
|
||||
template d*(self: ScriptNode, steps = 1.0) = self.down(steps)
|
||||
template f*(self: ScriptNode, steps = 1.0) = self.forward(steps)
|
||||
template b*(self: ScriptNode, steps = 1.0) = self.back(steps)
|
||||
|
||||
# proc set_global(global: bool) = discard
|
||||
# proc get_global(): bool = discard
|
||||
#
|
||||
proc turn(self: ScriptNode, direction: Directions, degrees = 90.0, move_mode: int) =
|
||||
let dir = case direction:
|
||||
of Directions.forward, Directions.f: FORWARD
|
||||
of Directions.back, Directions.b: BACK
|
||||
of Directions.left, Directions.l: LEFT
|
||||
of Directions.right, Directions.r: RIGHT
|
||||
of Directions.up, Directions.u: UP
|
||||
of Directions.down, Directions.d: DOWN
|
||||
|
||||
self.begin_turn(dir, degrees, move_mode)
|
||||
|
||||
proc turn(self: ScriptNode, degrees: float, move_mode: int) =
|
||||
let degrees = floor_mod(degrees, 360)
|
||||
if degrees <= 180:
|
||||
turn right, degrees
|
||||
self.turn right, degrees, move_mode
|
||||
else:
|
||||
let d = 180 - (degrees - 180)
|
||||
turn left, 180 - (degrees - 180)
|
||||
self.turn left, 180 - (degrees - 180), move_mode
|
||||
|
||||
proc t(direction: proc(steps = 1.0, ctx: Context = nil): Direction, degrees = 90.0) =
|
||||
turn(direction, degrees)
|
||||
template turn*(self: ScriptNode, direction: Directions, degrees = 90.0) =
|
||||
mixin wait
|
||||
me.wait turn(self, direction, degrees, move_mode)
|
||||
|
||||
proc f(steps = 1.0, ctx: Context = nil) = forward(steps)
|
||||
proc b(steps = 1.0, ctx: Context = nil) = back(steps)
|
||||
template forward*(steps = 1.0) = target.forward(steps)
|
||||
template back*(steps = 1.0) = target.back(steps)
|
||||
template left*(steps = 1.0) = target.left(steps)
|
||||
template right*(steps = 1.0) = target.right(steps)
|
||||
template up*(steps = 1.0) = target.up(steps)
|
||||
template down*(steps = 1.0) = target.down(steps)
|
||||
|
||||
proc look_at(node: ScriptNode) =
|
||||
let
|
||||
p1 = get_position()
|
||||
p2 = node.get_position()
|
||||
d = (p1 - p2).normalized()
|
||||
let n = arctan2(d.x, d.z).rad_to_deg
|
||||
let rot = get_rotation()
|
||||
turn(left, n - rot.y)
|
||||
template l*(steps = 1.0) = target.left(steps)
|
||||
template r*(steps = 1.0) = target.right(steps)
|
||||
template u*(steps = 1.0) = target.up(steps)
|
||||
template d*(steps = 1.0) = target.down(steps)
|
||||
template f*(steps = 1.0) = target.forward(steps)
|
||||
template b*(steps = 1.0) = target.back(steps)
|
||||
|
||||
proc la(node: ScriptNode) = look_at(node)
|
||||
template turn*(direction: Directions, degrees = 90.0) =
|
||||
mixin wait
|
||||
me.wait target.turn(direction, degrees, move_mode)
|
||||
|
||||
template turn*(degrees: float) =
|
||||
mixin wait
|
||||
me.wait target.turn(degrees, move_mode)
|
||||
|
||||
template move*[T: ScriptNode](new_target: T) =
|
||||
target = new_target
|
||||
|
||||
#
|
||||
# proc t(direction: proc(steps = 1.0, ctx: Context = nil): Direction, degrees = 90.0) =
|
||||
# turn(direction, degrees)
|
||||
#
|
||||
# proc f(steps = 1.0, ctx: Context = nil) = forward(steps)
|
||||
# proc b(steps = 1.0, ctx: Context = nil) = back(steps)
|
||||
#
|
||||
# proc look_at(node: ScriptNode) =
|
||||
# let
|
||||
# p1 = get_position()
|
||||
# p2 = node.get_position()
|
||||
# d = (p1 - p2).normalized()
|
||||
# let n = arctan2(d.x, d.z).rad_to_deg
|
||||
# let rot = get_rotation()
|
||||
# turn(left, n - rot.y)
|
||||
#
|
||||
# proc la(node: ScriptNode) = look_at(node)
|
||||
|
|
|
@ -1,82 +1,72 @@
|
|||
import std / [macros, strformat, strutils, sugar, sequtils, genasts]
|
||||
import types
|
||||
import types, base_api
|
||||
|
||||
proc params_to_vars(nodes: seq[NimNode]): NimNode =
|
||||
proc params_to_assignments(target: NimNode, nodes: seq[NimNode]): NimNode =
|
||||
result = new_stmt_list()
|
||||
let empty = new_empty_node()
|
||||
var vars = nnkVarSection.new_nim_node
|
||||
var assign = new_stmt_list()
|
||||
for node in nodes:
|
||||
let prop = node[0]
|
||||
let value = node[1]
|
||||
result.add quote do:
|
||||
`target`.`prop` = `value`
|
||||
|
||||
proc params_to_ident_defs(nodes: seq[NimNode]): seq[NimNode] =
|
||||
for node in nodes:
|
||||
let node = node.copy_nim_tree
|
||||
let prop = node[0]
|
||||
if prop.str_val notin ["global", "speed", "color"]:
|
||||
if node.kind == nnkExprEqExpr:
|
||||
vars.add nnkIdentDefs.new_tree(node[0], empty, node[1])
|
||||
result.add nnkIdentDefs.new_tree(node[0], new_empty_node(), node[1])
|
||||
elif node.kind == nnkExprColonExpr:
|
||||
vars.add nnkIdentDefs.new_tree(node[0], node[1], empty)
|
||||
result.add nnkIdentDefs.new_tree(node[0], node[1], new_empty_node())
|
||||
else:
|
||||
error("expected `my_param = 1`, `my_param: int` kind: " & $node.kind, node)
|
||||
|
||||
else:
|
||||
proc params_to_properties(nodes: seq[NimNode]): NimNode =
|
||||
result = new_nim_node(kind = nnkRecList)
|
||||
let empty = new_empty_node()
|
||||
for node in nodes:
|
||||
let node = node.copy_nim_tree
|
||||
let prop = node[0]
|
||||
if prop.str_val notin ["global", "speed", "color"]:
|
||||
if node.kind == nnkExprEqExpr:
|
||||
result.add nnkIdentDefs.new_tree(node[0].postfix("*"), new_call(ident"type", node[1]), empty)
|
||||
elif node.kind == nnkExprColonExpr:
|
||||
result.add nnkIdentDefs.new_tree(node[0].postfix("*"), node[1], empty)
|
||||
else:
|
||||
error("expected `my_param = 1`, `my_param: int` kind: " & $node.kind, node)
|
||||
|
||||
assign.add new_assignment(prop.copy_nim_node, node[1].copy_nim_node)
|
||||
result.add vars
|
||||
result.add assign
|
||||
|
||||
proc var_types(vars: NimNode): seq[tuple[name, typ: string]] =
|
||||
for sect in vars:
|
||||
if sect.kind == nnkVarSection:
|
||||
for node in sect:
|
||||
let t = node[2]
|
||||
let typ = if t.kind in nnkLiterals:
|
||||
if t.kind in nnkStrLit..nnkTripleStrLit:
|
||||
"string"
|
||||
else:
|
||||
($t.kind)[3..^4].to_lower_ascii
|
||||
elif t == ident"true" or t == ident"false":
|
||||
"bool"
|
||||
elif t.kind == nnkEmpty:
|
||||
node[1].str_val
|
||||
else:
|
||||
error("Don't know how to create getter/setter for " & t.repr, t)
|
||||
return
|
||||
result.add (node[0].str_val, typ)
|
||||
|
||||
proc build_ctors(name_str: string, type_name, cradle_name: NimNode, params: seq[NimNode]): NimNode =
|
||||
proc build_ctors(name_str: string, type_name: NimNode, params: seq[NimNode]): NimNode =
|
||||
var ctor_body = quote do:
|
||||
instance.ctrl.create_new()
|
||||
result = `cradle_name`
|
||||
result = `type_name`()
|
||||
new_instance(instance, result)
|
||||
|
||||
# TODO: ident normalization
|
||||
let vars = params_to_vars(params)
|
||||
let var_names = var_types(vars).map_it it.name
|
||||
for name in var_names:
|
||||
let setter = ident("set_" & name)
|
||||
let named_var = ident(name)
|
||||
let stmt = quote do:
|
||||
result.user_ctrl.`setter`(`named_var`)
|
||||
ctor_body.add(stmt)
|
||||
for param in params:
|
||||
let prop = param[0]
|
||||
ctor_body.add quote do:
|
||||
result.`prop` = `prop`
|
||||
|
||||
let vars = params_to_ident_defs(params)
|
||||
let var_names = vars.map_it $it[0]
|
||||
let instance_def = new_ident_defs("instance".ident, type_name)
|
||||
var params = @[type_name] & instance_def & vars[0][0..^1]
|
||||
var params = @[type_name] & instance_def & vars
|
||||
|
||||
var global = "global".ident
|
||||
if "global" notin var_names:
|
||||
params &= new_ident_defs(global, new_empty_node(), ident("global_default"))
|
||||
ctor_body.add quote do:
|
||||
result.ctrl.set_global(`global`)
|
||||
result.global = `global`
|
||||
|
||||
var speed = "speed".ident
|
||||
if "speed" notin var_names:
|
||||
params &= new_ident_defs(speed, new_empty_node(), new_float_lit_node(1.0))
|
||||
ctor_body.add quote do:
|
||||
result.ctrl.set("speed", `speed`)
|
||||
result.speed = `speed`
|
||||
|
||||
var color = "color".ident
|
||||
if "color" notin var_names:
|
||||
params &= new_ident_defs(color, new_empty_node(), bind_sym"eraser")
|
||||
ctor_body.add quote do:
|
||||
result.ctrl.set_color(`color`)
|
||||
result.color = `color`
|
||||
|
||||
# add baked in constructor params for speed, color, etc.
|
||||
# probably shouldn't be here.
|
||||
|
@ -87,62 +77,6 @@ proc build_ctors(name_str: string, type_name, cradle_name: NimNode, params: seq[
|
|||
body = ctor_body
|
||||
)
|
||||
|
||||
proc build_accessors(vars: NimNode): NimNode =
|
||||
result = new_stmt_list()
|
||||
for (name, typ) in var_types(vars):
|
||||
let var_name = name.ident
|
||||
let typ = typ.ident
|
||||
let setter_name = ("set_" & name).ident
|
||||
let getter_name = ("get_" & name).ident
|
||||
result.add quote do:
|
||||
me.user_ctrl.`getter_name` = proc(): `typ` =
|
||||
`var_name`
|
||||
me.user_ctrl.`setter_name` = proc(val: `typ`) =
|
||||
`var_name` = val
|
||||
|
||||
proc build_public_interface(vars, type_name: NimNode): NimNode =
|
||||
result = new_stmt_list()
|
||||
for (name, typ) in var_types(vars):
|
||||
let
|
||||
getter_name = name.ident
|
||||
setter_name = ident(name & "=")
|
||||
getter_accessor = ident("get_" & name)
|
||||
setter_accessor = ident("set_" & name)
|
||||
typ = typ.ident
|
||||
result.add quote do:
|
||||
proc `getter_name`*(self: `type_name`): `typ` =
|
||||
self.user_ctrl.`getter_accessor`()
|
||||
|
||||
proc `setter_name`*(self: `type_name`, val: `typ`) =
|
||||
self.user_ctrl.`setter_accessor`(val)
|
||||
|
||||
proc build_controller(name_str: string, type_name, vars: NimNode): NimNode =
|
||||
result = quote do:
|
||||
type
|
||||
`type_name`* = ref object
|
||||
getter*: proc():int
|
||||
setter*: proc(val {.inject.}: int)
|
||||
var fields = result[0][2][0][2]
|
||||
var getter = fields[0].copy_nim_tree
|
||||
var setter = fields[1].copy_nim_tree
|
||||
fields.del(0)
|
||||
fields.del(0)
|
||||
|
||||
for (name, typ) in var_types(vars):
|
||||
var getter = getter.copy_nim_tree
|
||||
var setter = setter.copy_nim_tree
|
||||
|
||||
echo "NAME: ", name, " ", typ.ident
|
||||
|
||||
getter[0][1] = ident("get_" & name)
|
||||
getter[1][0][0] = typ.ident
|
||||
|
||||
setter[0][1] = ident("set_" & name)
|
||||
setter[1][0][1][1] = typ.ident
|
||||
|
||||
fields.add getter
|
||||
fields.add setter
|
||||
|
||||
proc extract_class_info(name_node: NimNode): tuple[name: string, params: seq[NimNode]] =
|
||||
result = if name_node.kind == nnkIdent:
|
||||
(name_node.str_val, @[])
|
||||
|
@ -153,49 +87,30 @@ proc extract_class_info(name_node: NimNode): tuple[name: string, params: seq[Nim
|
|||
error("expected `name my_name` or `name my_name(my_param1 = 1, my_param2 = 2, ...)`", name_node)
|
||||
return
|
||||
|
||||
proc build_class(name_node: NimNode, is_clone: bool): NimNode =
|
||||
proc build_class(name_node: NimNode): NimNode =
|
||||
let base_class = ident"ScriptNode"
|
||||
let (name, params) = extract_class_info(name_node)
|
||||
|
||||
let
|
||||
type_name = (name & "Type").to_upper_ascii.nim_ident_normalize.ident
|
||||
var_name = name.ident
|
||||
cradle_name = (name & "_cradle").to_lower_ascii.nim_ident_normalize.ident
|
||||
clone_name = name & "_clone"
|
||||
vars = params_to_vars(params)
|
||||
ctors = build_ctors(name, type_name, cradle_name, params)
|
||||
ctors = build_ctors(name, type_name, params)
|
||||
controller_type = (name & "Controller").to_upper_ascii.nim_ident_normalize.ident
|
||||
controller = build_controller(name, controller_type, vars)
|
||||
iface = build_public_interface(vars, type_name)
|
||||
|
||||
result = new_stmt_list()
|
||||
if is_clone:
|
||||
result.add quote do:
|
||||
let me {.inject.} = `type_name`(name: `clone_name`, ctrl: Controller(), user_ctrl: `controller_type`())
|
||||
`cradle_name` = me
|
||||
else:
|
||||
let name_str = name
|
||||
result.add quote do:
|
||||
`controller`
|
||||
type
|
||||
`type_name`* = ref object of `base_class`
|
||||
create_new*: proc()
|
||||
user_ctrl*: `controller_type`
|
||||
`iface`
|
||||
let me {.inject.} = `type_name`(name: `name_str`, user_ctrl: `controller_type`(), ctrl: Controller())
|
||||
let `var_name`* {.inject.} = me
|
||||
var `cradle_name`*: `type_name`
|
||||
`ctors`
|
||||
|
||||
proc build_vars_and_accessors(name_node: NimNode): NimNode =
|
||||
let
|
||||
(name, params) = extract_class_info(name_node)
|
||||
vars = params_to_vars(params)
|
||||
accessors = build_accessors(vars)
|
||||
let name_str = name
|
||||
var type_def = quote do:
|
||||
type `type_name`* = ref object of `base_class`
|
||||
|
||||
result = gen_ast(vars, accessors):
|
||||
vars
|
||||
accessors
|
||||
type_def[0][2][0][2] = params_to_properties(params)
|
||||
result.add quote do:
|
||||
`type_def`
|
||||
|
||||
let me {.inject.} = `type_name`(name: `name_str`)
|
||||
register_active(me)
|
||||
let `var_name`* {.inject.} = me
|
||||
`ctors`
|
||||
|
||||
proc pop_name_node(ast: NimNode): NimNode =
|
||||
let ident_name = "name"
|
||||
|
@ -206,10 +121,8 @@ proc pop_name_node(ast: NimNode): NimNode =
|
|||
ast.del(i)
|
||||
break
|
||||
|
||||
macro load_enu_script*(file_name, include_name: string, is_clone: bool): untyped =
|
||||
let
|
||||
file_name = file_name.str_val
|
||||
is_clone: bool = is_clone.bool_val
|
||||
macro load_enu_script*(file_name, include_name: string): untyped =
|
||||
let file_name = file_name.str_val
|
||||
let ast = parse_stmt(file_name.static_read, file_name)
|
||||
let name_node = pop_name_node(ast)
|
||||
let include_file = quote do:
|
||||
|
@ -217,14 +130,25 @@ macro load_enu_script*(file_name, include_name: string, is_clone: bool): untyped
|
|||
result = new_stmt_list()
|
||||
var inner = new_stmt_list()
|
||||
if name_node.kind != nnkNilLit:
|
||||
result.add build_class(name_node, is_clone)
|
||||
let (name, params) = extract_class_info(name_node)
|
||||
result.add build_class(name_node)
|
||||
result.add include_file
|
||||
inner.add build_vars_and_accessors(name_node)
|
||||
inner.add params_to_assignments(ident"me", params)
|
||||
|
||||
else:
|
||||
result.add quote do:
|
||||
let me {.inject.} = ScriptNode(ctrl: Controller())
|
||||
let me {.inject.} = ScriptNode()
|
||||
register_active(me)
|
||||
|
||||
result.add include_file
|
||||
|
||||
inner.add ast
|
||||
result.add new_block_stmt(inner)
|
||||
result.add quote do:
|
||||
#proc run_script*(me {.inject.}: me.type) =
|
||||
var target {.inject.}: ScriptNode = me
|
||||
include loops
|
||||
`inner`
|
||||
#run_script(me)
|
||||
|
||||
system.echo "code: "
|
||||
system.echo result.repr
|
||||
|
|
|
@ -1,39 +1,11 @@
|
|||
import state_machine, types
|
||||
var context: Context
|
||||
|
||||
var
|
||||
context: Context
|
||||
|
||||
proc yield_script = discard
|
||||
|
||||
var load_values: proc()
|
||||
|
||||
proc advance_state_machine(): bool =
|
||||
me.advance_state_machine = proc(): bool =
|
||||
result = if not context.is_nil:
|
||||
let val = context.advance()
|
||||
if load_values != nil:
|
||||
load_values()
|
||||
val
|
||||
context.advance()
|
||||
else:
|
||||
true
|
||||
|
||||
proc set_action_running*(running: bool) =
|
||||
me.ctrl.action_running = running
|
||||
|
||||
template wait(node: ScriptNode, body: untyped) =
|
||||
node.ctrl.action_running = true
|
||||
when defined(nimscript):
|
||||
body
|
||||
while node.ctrl.action_running and node.ctrl.advance_state_machine():
|
||||
node.ctrl.yield_script()
|
||||
if load_values != nil:
|
||||
load_values()
|
||||
else:
|
||||
# only for tests
|
||||
var counter = 0
|
||||
while counter < 3 and advance_state_machine():
|
||||
inc counter
|
||||
body
|
||||
|
||||
proc loop_started(ctx: Context, main_loop: bool) =
|
||||
if main_loop:
|
||||
context = ctx
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
import base_api
|
||||
echo "IMPORTED!!!"
|
|
@ -1,25 +1,24 @@
|
|||
import types
|
||||
|
||||
let player* = PlayerType(ctrl: Controller())
|
||||
let player* = PlayerType()
|
||||
let me = player
|
||||
|
||||
proc quit*(exit_code = 0) = discard
|
||||
proc get_position(): Vector3 = discard
|
||||
proc get_rotation(): Vector3 = discard
|
||||
proc set_velocity(v: Vector3) = discard
|
||||
proc get_velocity(): Vector3 = discard
|
||||
|
||||
me.ctrl.get_position = proc(): Vector3 =
|
||||
get_position()
|
||||
|
||||
me.ctrl.get_rotation = proc(): Vector3 =
|
||||
get_rotation()
|
||||
|
||||
me.ctrl.get_velocity = proc(): Vector3 =
|
||||
get_velocity()
|
||||
|
||||
me.ctrl.set_velocity = proc(v: Vector3) =
|
||||
set_velocity(v)
|
||||
# me.ctrl.get_position = proc(): Vector3 =
|
||||
# get_position()
|
||||
#
|
||||
# me.ctrl.get_rotation = proc(): Vector3 =
|
||||
# get_rotation()
|
||||
#
|
||||
# me.ctrl.get_velocity = proc(): Vector3 =
|
||||
# get_velocity()
|
||||
#
|
||||
# me.ctrl.set_velocity = proc(v: Vector3) =
|
||||
# set_velocity(v)
|
||||
|
||||
proc bounce*(me: PlayerType, power = 1.0) =
|
||||
me.velocity = me.velocity + UP * power * 30
|
||||
|
|
|
@ -1,77 +1,12 @@
|
|||
import helpers, strutils, types, math
|
||||
export helpers
|
||||
|
||||
include loops
|
||||
|
||||
let skip_3d = true
|
||||
|
||||
var
|
||||
speed* = 1.0
|
||||
scale* = 1.0
|
||||
color*: ColorIndex
|
||||
height* = 0.0
|
||||
position* = vec3(0, 0, 0)
|
||||
move_mode = 0
|
||||
|
||||
include base_api
|
||||
|
||||
load_values = proc() =
|
||||
position = me.position
|
||||
height = position.y
|
||||
|
||||
me.ctrl.begin_move = proc(direction: Vector3, steps: float, self: ScriptNode, moving: int) =
|
||||
self.wait begin_move(direction, steps, 0)
|
||||
|
||||
me.ctrl.begin_turn = proc(axis: Vector3, degrees: float, self: ScriptNode, moving: int) =
|
||||
self.wait begin_turn(axis, degrees, 0)
|
||||
|
||||
me.ctrl.advance_state_machine = proc(): bool = advance_state_machine()
|
||||
me.ctrl.yield_script = proc() = yield_script()
|
||||
|
||||
me.ctrl.set_global = proc(global: bool) =
|
||||
set_global(global)
|
||||
|
||||
me.ctrl.get_global = proc(): bool =
|
||||
get_global()
|
||||
|
||||
me.ctrl.set = proc(name: string, new_speed:float) =
|
||||
speed = new_speed
|
||||
me.ctrl.get = proc(name: string): float = speed
|
||||
|
||||
me.ctrl.stash = proc() =
|
||||
stash()
|
||||
|
||||
me.ctrl.get_position = proc(): Vector3 =
|
||||
get_position()
|
||||
|
||||
me.ctrl.set_position = proc(position: Vector3) =
|
||||
set_position(position)
|
||||
|
||||
me.ctrl.get_rotation = proc(): Vector3 =
|
||||
get_rotation()
|
||||
|
||||
me.ctrl.look_at = proc(target: ScriptNode) =
|
||||
look_at(target)
|
||||
|
||||
me.ctrl.add_stashed = proc() =
|
||||
add_stashed()
|
||||
|
||||
me.ctrl.create_new = proc() =
|
||||
create_new()
|
||||
|
||||
me.ctrl.get_color = proc(): ColorIndex = color
|
||||
me.ctrl.set_color = proc(value: ColorIndex) = color = value
|
||||
|
||||
proc play*(animation_name: string) = discard
|
||||
proc set_speed*(spd: float) = speed = spd
|
||||
var move_mode = 1
|
||||
import base_api
|
||||
|
||||
proc walk*() =
|
||||
speed = 1.0
|
||||
play("walk")
|
||||
me.speed = 1.0
|
||||
#me.play("walk")
|
||||
|
||||
proc run*() =
|
||||
speed = 5.0
|
||||
play("run")
|
||||
me.speed = 5.0
|
||||
#me.play("run")
|
||||
|
||||
proc move*[T: ScriptNode](new_target: T) =
|
||||
target = new_target
|
||||
|
|
|
@ -1,15 +1,5 @@
|
|||
import macros, strformat, strutils, helpers, sequtils, tables
|
||||
|
||||
type
|
||||
Context* = ref object
|
||||
stack: seq[Frame]
|
||||
Frame = ref object
|
||||
manager: proc(active: bool):bool
|
||||
action: proc()
|
||||
Halt = object of CatchableError
|
||||
Loop = ref object
|
||||
states: Table[string, NimNode]
|
||||
from_states: seq[(string, NimNode)]
|
||||
import std / [macros, strformat, strutils, sequtils, tables]
|
||||
import types, helpers
|
||||
|
||||
proc current_loop(value: Loop = nil): Loop =
|
||||
var loop {.global.}: Loop
|
||||
|
|
|
@ -11,30 +11,37 @@ type
|
|||
id: int
|
||||
name*: string
|
||||
|
||||
Controller* = object
|
||||
action_running*: bool
|
||||
advance_state_machine*: proc(): bool
|
||||
yield_script*: proc()
|
||||
begin_move*: proc(direction: Vector3, steps: float, self: ScriptNode, moving: int)
|
||||
begin_turn*: proc(axis: Vector3, degrees: float, self: ScriptNode, moving: int)
|
||||
look_at*: proc(target: ScriptNode)
|
||||
set*: proc(var_name: string, value: float)
|
||||
get*: proc(var_name: string): float
|
||||
create_new*: proc()
|
||||
set_color*: proc(value: ColorIndex)
|
||||
get_color*: proc(): ColorIndex
|
||||
get_position*: proc(): Vector3
|
||||
set_position*: proc(position: Vector3)
|
||||
get_rotation*: proc(): Vector3
|
||||
set_velocity*: proc(velocity: Vector3)
|
||||
get_velocity*: proc(): Vector3
|
||||
set_global*: proc(global: bool)
|
||||
get_global*: proc(): bool
|
||||
stash*: proc()
|
||||
add_stashed*: proc()
|
||||
Directions* = enum
|
||||
up, u, down, d, left, l, right, r, forward, f, back, b
|
||||
|
||||
# Controller* = object
|
||||
# action_running*: bool
|
||||
# advance_state_machine*: proc(): bool
|
||||
# yield_script*: proc()
|
||||
# begin_move*: proc(direction: Vector3, steps: float, self: ScriptNode, moving: int)
|
||||
# begin_turn*: proc(axis: Vector3, degrees: float, self: ScriptNode, moving: int)
|
||||
# look_at*: proc(target: ScriptNode)
|
||||
# set*: proc(var_name: string, value: float)
|
||||
# get*: proc(var_name: string): float
|
||||
# create_new*: proc()
|
||||
# set_color*: proc(value: ColorIndex)
|
||||
# get_color*: proc(): ColorIndex
|
||||
# get_position*: proc(): Vector3
|
||||
# set_position*: proc(position: Vector3)
|
||||
# get_rotation*: proc(): Vector3
|
||||
# set_velocity*: proc(velocity: Vector3)
|
||||
# get_velocity*: proc(): Vector3
|
||||
# set_global*: proc(global: bool)
|
||||
# get_global*: proc(): bool
|
||||
# stash*: proc()
|
||||
# add_stashed*: proc()
|
||||
|
||||
ScriptNode* = ref object of Node
|
||||
ctrl*: Controller
|
||||
color*: ColorIndex
|
||||
speed*: float
|
||||
global*: bool
|
||||
velocity*: Vector3
|
||||
advance_state_machine*: proc(): bool
|
||||
|
||||
ColorIndex* = enum
|
||||
eraser = 0,
|
||||
|
@ -47,10 +54,21 @@ type
|
|||
|
||||
Energy* = range[0.0..100.0]
|
||||
|
||||
Direction* = object
|
||||
|
||||
PlayerType* = ref object of ScriptNode
|
||||
|
||||
Context* = ref object
|
||||
stack*: seq[Frame]
|
||||
|
||||
Frame* = ref object
|
||||
manager*: proc(active: bool):bool
|
||||
action*: proc()
|
||||
|
||||
Halt* = object of CatchableError
|
||||
|
||||
Loop* = ref object
|
||||
states*: Table[string, NimNode]
|
||||
from_states*: seq[(string, NimNode)]
|
||||
|
||||
proc vec3*(x, y, z: float): Vector3 {.inline.} =
|
||||
Vector3(x:x, y:y, z:z)
|
||||
|
||||
|
@ -312,84 +330,66 @@ proc moveToward*(vFrom, to: Vector3, delta: float32): Vector3 =
|
|||
converter vec3_to_bool*(v: Vector3): bool =
|
||||
v != vec3(0, 0, 0)
|
||||
|
||||
template forward*(target: ScriptNode, steps = 1.0) =
|
||||
target.ctrl.begin_move(FORWARD, steps, self)
|
||||
|
||||
template back*(target: ScriptNode, steps = 1.0) =
|
||||
target.ctrl.begin_move(BACK, steps, self)
|
||||
|
||||
template left*(target: ScriptNode, steps = 1.0) =
|
||||
target.ctrl.begin_move(LEFT, steps, self)
|
||||
|
||||
template right*(target: ScriptNode, steps = 1.0) =
|
||||
target.ctrl.begin_move(RIGHT, steps, self)
|
||||
|
||||
template turn_left*(target: ScriptNode, degrees = 90.0) =
|
||||
target.ctrl.begin_turn(LEFT, degrees, self)
|
||||
|
||||
template turn_right*(target: ScriptNode, degrees = 90.0) =
|
||||
target.ctrl.begin_turn(RIGHT, degrees, self)
|
||||
|
||||
proc `speed=`*(self: ScriptNode, speed: float) =
|
||||
self.ctrl.set("speed", speed)
|
||||
|
||||
proc speed*(self: ScriptNode): float =
|
||||
self.ctrl.get("speed")
|
||||
|
||||
proc `color=`*(self: ScriptNode, color: ColorIndex) =
|
||||
self.ctrl.set_color(color)
|
||||
|
||||
proc color*(self: ScriptNode): ColorIndex =
|
||||
self.ctrl.get_color()
|
||||
|
||||
proc `global=`*(self: ScriptNode, global: bool) =
|
||||
self.ctrl.set_global(global)
|
||||
|
||||
proc global*(self: ScriptNode): bool =
|
||||
self.ctrl.get_global()
|
||||
|
||||
proc `velocity=`*(self: PlayerType, v: Vector3) =
|
||||
self.ctrl.set_velocity(v)
|
||||
|
||||
proc velocity*(self: PlayerType): Vector3 =
|
||||
self.ctrl.get_velocity()
|
||||
|
||||
proc position*(self: ScriptNode): Vector3 =
|
||||
self.ctrl.get_position()
|
||||
|
||||
proc `position=`*(self: ScriptNode, position: Vector3) =
|
||||
self.ctrl.set_position(position)
|
||||
|
||||
template up*(target: ScriptNode, steps = 1.0) =
|
||||
target.ctrl.begin_move(UP, steps, me)
|
||||
|
||||
template down*(target: ScriptNode, steps = 1.0) =
|
||||
target.ctrl.begin_move(DOWN, steps, me)
|
||||
|
||||
template turn_up*(target: ScriptNode, degrees = 90.0) =
|
||||
target.ctrl.begin_turn(UP, degrees, me)
|
||||
|
||||
template turn_down*(target: ScriptNode, degrees = 90.0) =
|
||||
target.ctrl.begin_turn(DOWN, degrees, me)
|
||||
|
||||
proc look_at*(actor: ScriptNode) =
|
||||
actor.ctrl.look_at(actor)
|
||||
|
||||
proc near*(actor, target: ScriptNode, less_than = 5.0): bool =
|
||||
let distance = actor.ctrl.get_position().distance_to(target.ctrl.get_position())
|
||||
result = distance < less_than
|
||||
|
||||
proc get_position*(actor: ScriptNode): Vector3 =
|
||||
actor.ctrl.get_position()
|
||||
|
||||
proc set_position*(actor: ScriptNode, position: Vector3) =
|
||||
actor.ctrl.set_position(position)
|
||||
|
||||
proc get_rotation*(actor: ScriptNode): Vector3 =
|
||||
actor.ctrl.get_rotation()
|
||||
|
||||
proc stash*(actor: ScriptNode) =
|
||||
actor.ctrl.stash()
|
||||
|
||||
proc add_stashed*(actor: ScriptNode) =
|
||||
actor.ctrl.add_stashed()
|
||||
# proc `speed=`*(self: ScriptNode, speed: float) =
|
||||
# self.ctrl.set("speed", speed)
|
||||
#
|
||||
# proc speed*(self: ScriptNode): float =
|
||||
# self.ctrl.get("speed")
|
||||
#
|
||||
# proc `color=`*(self: ScriptNode, color: ColorIndex) =
|
||||
# self.ctrl.set_color(color)
|
||||
#
|
||||
# proc color*(self: ScriptNode): ColorIndex =
|
||||
# self.ctrl.get_color()
|
||||
#
|
||||
# proc `global=`*(self: ScriptNode, global: bool) =
|
||||
# self.ctrl.set_global(global)
|
||||
#
|
||||
# proc global*(self: ScriptNode): bool =
|
||||
# self.ctrl.get_global()
|
||||
#
|
||||
# proc `velocity=`*(self: PlayerType, v: Vector3) =
|
||||
# self.ctrl.set_velocity(v)
|
||||
#
|
||||
# proc velocity*(self: PlayerType): Vector3 =
|
||||
# self.ctrl.get_velocity()
|
||||
#
|
||||
# proc position*(self: ScriptNode): Vector3 =
|
||||
# self.ctrl.get_position()
|
||||
#
|
||||
# proc `position=`*(self: ScriptNode, position: Vector3) =
|
||||
# self.ctrl.set_position(position)
|
||||
#
|
||||
# template up*(target: ScriptNode, steps = 1.0) =
|
||||
# target.ctrl.begin_move(UP, steps, me)
|
||||
#
|
||||
# template down*(target: ScriptNode, steps = 1.0) =
|
||||
# target.ctrl.begin_move(DOWN, steps, me)
|
||||
#
|
||||
# template turn_up*(target: ScriptNode, degrees = 90.0) =
|
||||
# target.ctrl.begin_turn(UP, degrees, me)
|
||||
#
|
||||
# template turn_down*(target: ScriptNode, degrees = 90.0) =
|
||||
# target.ctrl.begin_turn(DOWN, degrees, me)
|
||||
#
|
||||
# proc look_at*(actor: ScriptNode) =
|
||||
# actor.ctrl.look_at(actor)
|
||||
#
|
||||
# proc near*(actor, target: ScriptNode, less_than = 5.0): bool =
|
||||
# let distance = actor.ctrl.get_position().distance_to(target.ctrl.get_position())
|
||||
# result = distance < less_than
|
||||
#
|
||||
# proc get_position*(actor: ScriptNode): Vector3 =
|
||||
# actor.ctrl.get_position()
|
||||
#
|
||||
# proc set_position*(actor: ScriptNode, position: Vector3) =
|
||||
# actor.ctrl.set_position(position)
|
||||
#
|
||||
# proc get_rotation*(actor: ScriptNode): Vector3 =
|
||||
# actor.ctrl.get_rotation()
|
||||
#
|
||||
# proc stash*(actor: ScriptNode) =
|
||||
# actor.ctrl.stash()
|
||||
#
|
||||
# proc add_stashed*(actor: ScriptNode) =
|
||||
# actor.ctrl.add_stashed()
|
||||
|
|
Loading…
Reference in New Issue