Server connect/listen support. Doesn't work.

Formatting fixes.
Changed {.cast(gcsafe}.} to {.gcsafe.} to keep the jetbrains nim plugin happy
This commit is contained in:
Scott Wadden 2023-03-02 00:47:18 -04:00
parent 38c271cafb
commit 57be8e5628
8 changed files with 59 additions and 33 deletions

View File

@ -39,7 +39,8 @@ requires "nim >= 1.6.10",
"chroma",
"markdown",
"chronicles",
"zippy"
"zippy",
"dotenv"
proc gen: string =
if generator_path == "":

View File

@ -1,19 +1,21 @@
--define:vm_exec_hooks
--threads:on
--define:nim_preview_hash_ref
--define:nim_type_names
--experimental:dynamic_bind_sym
--mm:orc
--panics:on
--warning:"LockLevel:off"
--warning:"UseBase:off"
--experimental:"dynamic_bind_sym"
--define:"vm_exec_hooks"
--define:"nim_preview_hash_ref"
--define:"nim_type_names"
--define:"chronicles_enabled=on"
--define:"chronicles_log_level=INFO"
--define:"chronicles_disabled_topics=model_citizen,scripting"
--define:"chronicles_sinks=textlines[dynamic]"
# --define:zen_trace
# --define:"chronicles_timestamps=None" # disable timestamps for better diffs
# --define:"zen_trace"
if defined(release):
--define:"chronicles_colors=None"

View File

@ -89,8 +89,6 @@ proc find_nested_changes(parent: Change[Unit]) =
proc watch*(self: NodeController, state: GameState) =
state.units.changes:
if ?change.item:
debug "Unit added", unit = change.item.id, changes = change.changes
if added:
change.item.add_to_scene()
elif modified:

View File

@ -59,7 +59,7 @@ proc link_dependency_impl(self: Worker, dep: Unit) =
proc write_stack_trace(self: Worker) =
let ctx = self.active_unit.script_ctx
{.cast(gcsafe).}:
{.gcsafe.}:
msg_writeln(ctx.ctx.config, "stack trace: (most recent call last)",
{msg_no_unit_sep})
stack_trace_aux(ctx.ctx, ctx.tos, ctx.pc)
@ -67,7 +67,7 @@ proc write_stack_trace(self: Worker) =
proc get_unit(self: Worker, a: VmArgs, pos: int): Unit {.gcsafe.} =
let pnode = a.get_node(pos)
assert pnode in self.unit_map
{.cast(gcsafe).}:
{.gcsafe.}:
result = self.unit_map[pnode]
proc get_bot(self: Worker, a: VmArgs, pos: int): Bot =
@ -717,6 +717,9 @@ proc launch_worker(params: (ZenContext, GameState)) {.gcsafe.} =
Zen.thread_ctx = worker_ctx
Zen.thread_ctx.subscribe(ctx)
let server_address = main_thread_state.config.server_address
if not listen and server_address != "":
Zen.thread_ctx.subscribe(server_address)
Zen.thread_ctx.recv
assert Zen.thread_ctx.len == ctx.len
@ -787,8 +790,8 @@ proc launch_worker(params: (ZenContext, GameState)) {.gcsafe.} =
proc extract_file_info(msg: string): tuple[name: string, info: TLineInfo] =
if msg =~ re"unhandled exception: (.*)\((\d+), (\d+)\)":
result = (matches[0], TLineInfo(line: matches[1].parse_int.uint16,
col: matches[2].parse_int.int16))
result = (matches[0], TLineInfo(line: matches[1].parse_int.uint16, col:
matches[2].parse_int.int16))
proc eval*(self: Worker, code: string) =
let active = self.active_unit

View File

@ -1,10 +1,11 @@
import std / [monotimes, os, jsonutils, json, math, locks]
import pkg / [godot, zippy / ziparchives]
import godotapi / [input, input_event, gd_os, node, scene_tree,
packed_scene, sprite, control, viewport, viewport_texture,
performance, label, theme, dynamic_font, resource_loader, main_loop,
project_settings, input_map, input_event_action, input_event_key, global_constants,
scroll_container]
from dotenv import nil
import godotapi / [input, input_event, gd_os, node, scene_tree, packed_scene,
sprite, control, viewport, viewport_texture, performance, label, theme,
dynamic_font, resource_loader, main_loop, project_settings, input_map,
input_event_action, input_event_key, global_constants, scroll_container]
import core, types, globals, controllers, models / serializers
type
@ -18,8 +19,14 @@ type
start_full_screen: Option[bool]
semicolon_as_colon: Option[bool]
world_prefix: Option[string]
listen: Option[bool]
server_address: Option[string]
const auto_save_interval = 30.seconds
if file_exists(".env"):
dotenv.overload()
Zen.thread_ctx = ZenContext.init(name = "main", chan_size = 1000)
state = GameState.init
@ -38,14 +45,15 @@ gdobj Game of Node:
script_controller: ScriptController
method process*(delta: float) =
Zen.thread_ctx.recv(duration = (1.0 / 60.0).seconds)
Zen.thread_ctx.recv(max_duration = (1.0 / 60.0).seconds)
inc state.frame_count
let time = get_mono_time()
if state.config.show_stats:
let fps = get_monitor(TIME_FPS)
let vram = get_monitor(RENDER_VIDEO_MEM_USED)
self.stats.text = &"FPS: {fps}\nscale_factor: {state.scale_factor}\nvram: {vram}"
self.stats.text =
&"FPS: {fps}\nscale_factor: {state.scale_factor}\nvram: {vram}"
if time > self.rescale_at:
self.rescale_at = MonoTime.high
@ -64,7 +72,9 @@ gdobj Game of Node:
proc rescale*() =
let vp = self.get_viewport().size
state.scale_factor = sqrt(state.config.mega_pixels * 1_000_000.0 / (vp.x * vp.y))
state.scale_factor = sqrt(state.config.mega_pixels *
1_000_000.0 / (vp.x * vp.y))
self.scaled_viewport.size = vp * state.scale_factor
method notification*(what: int) =
@ -134,6 +144,7 @@ gdobj Game of Node:
assert not state.config.is_nil
state.config.font_size.value = uc.font_size ||= (20 * screen_scale).int
let env_listen = get_env("ENU_LISTEN").to_lower() == "true"
with state.config:
dock_icon_size = uc.dock_icon_size ||= 100 * screen_scale
world_prefix = uc.world_prefix ||= "tutorial"
@ -142,7 +153,10 @@ gdobj Game of Node:
mega_pixels = uc.mega_pixels ||= 2.0
start_full_screen = uc.start_full_screen ||= true
semicolon_as_colon = uc.semicolon_as_colon ||= false
lib_dir = join_path(get_executable_path().parent_dir(), "..", "..", "..", "vmlib")
lib_dir = join_path(get_executable_path().parent_dir(), "..", "..", "..",
"vmlib")
server_address = uc.server_address ||= ""
listen = env_listen or (uc.listen ||= false)
state.set_flag(God, uc.god_mode ||= false)
@ -153,7 +167,9 @@ gdobj Game of Node:
when defined(dist):
let exe_dir = parent_dir get_executable_path()
if host_os == "macosx":
state.config.lib_dir = join_path(exe_dir.parent_dir, "Resources", "vmlib")
state.config.lib_dir = join_path(exe_dir.parent_dir, "Resources",
"vmlib")
elif host_os == "windows":
state.config.lib_dir = join_path(exe_dir, "vmlib")
elif host_os == "linux":
@ -186,7 +202,9 @@ gdobj Game of Node:
method ready* =
state.nodes.data = state.nodes.game.find_node("Level").get_node("data")
assert not state.nodes.data.is_nil
self.scaled_viewport = self.get_node("ViewportContainer/Viewport") as Viewport
self.scaled_viewport =
self.get_node("ViewportContainer/Viewport") as Viewport
self.bind_signals(self.get_viewport(), "size_changed")
assert not self.scaled_viewport.is_nil
if state.config.mega_pixels >= 1.0:
@ -253,10 +271,12 @@ gdobj Game of Node:
if event.is_action_pressed("previous"):
state.update_action_index(-1)
# NOTE: alt+enter isn't being picked up on windows if the editor is open. Needs investigation.
# NOTE: alt+enter isn't being picked up on windows if the editor is
# open. Needs investigation.
if event.is_action_pressed("toggle_fullscreen") or (host_os == "windows" and
CommandMode in state.flags and EditorVisible in state.flags and
event of InputEventKey and event.as(InputEventKey).scancode == KEY_ENTER):
CommandMode in state.flags and EditorVisible in state.flags and
event of InputEventKey and
event.as(InputEventKey).scancode == KEY_ENTER):
set_window_fullscreen not is_window_fullscreen()
elif event.is_action_pressed("next_world"):

View File

@ -200,7 +200,7 @@ proc select_routine*(i: Interpreter; name: string, module_name: string): PSym =
## Selects a declared routine (proc/func/etc) from the main module.
## The routine needs to have the export marker ``*``. The only matching
## routine is returned and ``nil`` if it is overloaded.
{.cast(gcsafe).}:
{.gcsafe.}:
result = select_unique_symbol(i, name, {sk_template, sk_macro, sk_func,
sk_method, sk_proc, sk_converter}, module_name)
@ -225,7 +225,7 @@ proc load_module*(i: Interpreter, file_name, code: string,
break
if module.is_nil:
{.cast(gcsafe).}:
{.gcsafe.}:
module = i.graph.make_module(file_name)
init_str_tables(i.graph, module)
@ -236,7 +236,7 @@ proc load_module*(i: Interpreter, file_name, code: string,
# which causes "cannot evaluate at compile time" issues with some variables.
# Force things back to em_repl.
PCtx(i.graph.vm).mode = em_repl
{.cast(gcsafe).}:
{.gcsafe.}:
discard process_module(i.graph, module, i.idgen, stream, a)
# adapted from

View File

@ -16,7 +16,7 @@ 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") & @[script_dir]
{.cast(gcsafe).}:
{.gcsafe.}:
result = create_interpreter("base_api.nim", source_paths)
proc pause*(ctx: ScriptCtx) =
@ -70,7 +70,7 @@ proc call_proc*(self: ScriptCtx, proc_name: string, args: varargs[PNode, `to_nod
if foreign_proc == nil:
raise new_exception(VMError, &"script does not export a proc of the name: '{proc_name}'")
result = try:
{.cast(gcsafe).}:
{.gcsafe.}:
(false, self.interpreter.call_routine(foreign_proc, args))
except VMPause:
(self.exit_code.is_none, nil)
@ -90,7 +90,7 @@ proc resume*(self: ScriptCtx): bool =
debug "resuming", script = self.file_name, module = self.module_name
result = try:
{.cast(gcsafe).}:
{.gcsafe.}:
discard exec_from_ctx(self.ctx, self.pc, self.tos)
false
except VMPause:

View File

@ -143,6 +143,8 @@ type
start_full_screen*: bool
semicolon_as_colon*: bool
world_prefix*: string
listen*: bool
server_address*: string
ScriptCtx* = ref object
script*: string