From ffb9693a4f88f7293ffd9f5429f2ebc126620e38 Mon Sep 17 00:00:00 2001 From: Scott Wadden Date: Tue, 14 Nov 2023 19:51:15 -0400 Subject: [PATCH] Revised world/level structure --- .../script_controllers/host_bridge.nim | 14 +++-- .../script_controllers/scripting.nim | 2 +- src/controllers/script_controllers/worker.nim | 26 ++++----- src/game.nim | 28 ++++----- src/models/serializers.nim | 58 +++++++++---------- src/models/states.nim | 8 ++- src/nodes/player_node.nim | 17 +++--- src/types.nim | 12 ++-- vmlib/enu/base_bridge.nim | 2 +- vmlib/enu/players.nim | 3 + .../tutorial-1/{world.json => level.json} | 0 .../tutorial-1/scripts/bot_aqslupunw4ndq.nim | 2 +- .../tutorial-2/{world.json => level.json} | 0 13 files changed, 93 insertions(+), 79 deletions(-) rename vmlib/projects/tutorial-1/{world.json => level.json} (100%) rename vmlib/projects/tutorial-2/{world.json => level.json} (100%) diff --git a/src/controllers/script_controllers/host_bridge.nim b/src/controllers/script_controllers/host_bridge.nim index cf0c2061..9670964c 100644 --- a/src/controllers/script_controllers/host_bridge.nim +++ b/src/controllers/script_controllers/host_bridge.nim @@ -80,8 +80,8 @@ proc to_node(self: Worker, unit: Unit): PNode = proc press_action(self: Worker, name: string) = state.queued_action = name -proc load_world(name: string) = - change_loaded_world(name) +proc load_level(name: string) = + change_loaded_level(name) proc register_active(self: Worker, pnode: PNode) = assert not self.active_unit.is_nil @@ -401,6 +401,12 @@ proc flying(self: Unit): bool = proc `flying=`*(self: Unit, value: bool) = state.set_flag Flying, value +proc running(self: Unit): bool = + AltWalkSpeed in state.local_flags + +proc `running=`*(self: Unit, value: bool) = + state.set_flag AltWalkSpeed, value + proc tool(self: Unit): int = int(state.tool) @@ -481,7 +487,7 @@ proc bridge_to_vm*(worker: Worker) = glow, `glow=`, speed, `speed=`, scale, `scale=`, velocity, `velocity=`, active_unit, color, `color=`, sees, start_position, wake, frame_count, write_stack_trace, show, `show=`, frame_created, lock, `lock=`, reset, - press_action, load_world + press_action, load_level result.bridged_from_vm "base_bridge_private", link_dependency, action_running, `action_running=`, yield_script, @@ -500,4 +506,4 @@ proc bridge_to_vm*(worker: Worker) = result.bridged_from_vm "players", playing, `playing=`, god, `god=`, flying, `flying=`, tool, `tool=`, - coding, `coding=` + coding, `coding=`, running, `running=` diff --git a/src/controllers/script_controllers/scripting.nim b/src/controllers/script_controllers/scripting.nim index 8b6d75f2..c1dc4c6e 100644 --- a/src/controllers/script_controllers/scripting.nim +++ b/src/controllers/script_controllers/scripting.nim @@ -56,7 +56,7 @@ proc init_interpreter*[T](self: Worker, _: T) {.gcsafe.} = else: "???" - if file_exists(file_name): + if file_exists(file_name) and ?ctx.file_name: if file_name.get_file_info != ctx.file_name.get_file_info: (file_name, info) = extract_file_info msg # msg = msg.replace(re"unhandled exception:.*\) Error\: ", "") diff --git a/src/controllers/script_controllers/worker.nim b/src/controllers/script_controllers/worker.nim index 07b1fb5b..0fb1986b 100644 --- a/src/controllers/script_controllers/worker.nim +++ b/src/controllers/script_controllers/worker.nim @@ -97,7 +97,7 @@ proc watch_code(self: Worker, unit: Unit) = unit.code_value.changes: if added or touched: if change.item.owner == "" or change.item.owner == Zen.thread_ctx.id: - save_world(state.config.world_dir) + save_level(state.config.level_dir) self.change_code(unit, change.item) elif Server in state.local_flags: if change.item.nim == "": @@ -209,27 +209,27 @@ proc worker_thread(params: (ZenContext, GameState)) {.gcsafe.} = worker.bridge_to_vm if Server in state.local_flags: - var world_dir = state.config.world_dir + var level_dir = state.config.level_dir player.script_ctx.interpreter = worker.interpreter worker.load_script_and_dependents(player) - worker.load_world(world_dir) - state.world_name = state.config.world + worker.load_level(level_dir) + state.level_name = state.config.world & "/" & state.config.level state.config_value.changes: if added: - if change.item.world_dir != world_dir: + if change.item.level_dir != level_dir: let full_reset = ResettingVM in state.local_flags - if world_dir != "": - save_world(world_dir, save_all = full_reset) - worker.unload_world() + if level_dir != "": + save_level(level_dir, save_all = full_reset) + worker.unload_level() if full_reset: worker.init_interpreter("") worker.bridge_to_vm player.script_ctx.interpreter = worker.interpreter worker.load_script_and_dependents(player) - world_dir = change.item.world_dir - if world_dir != "": - worker.load_world(world_dir) + level_dir = change.item.level_dir + if level_dir != "": + worker.load_level(level_dir) else: Zen.thread_ctx.subscribe(connect_address) state.units.add player @@ -252,7 +252,7 @@ proc worker_thread(params: (ZenContext, GameState)) {.gcsafe.} = state.local_flags.changes: if Quitting.added: - save_world(state.config.world_dir) + save_level(state.config.level_dir) state.pop_flag Quitting running = false @@ -299,7 +299,7 @@ proc worker_thread(params: (ZenContext, GameState)) {.gcsafe.} = unit.apply_changes if get_mono_time() > save_at: - save_world(state.config.world_dir) + save_level(state.config.level_dir) save_at = get_mono_time() + auto_save_interval let frame_end = get_mono_time() diff --git a/src/game.nim b/src/game.nim index 6a46e8b7..0fe70fdc 100644 --- a/src/game.nim +++ b/src/game.nim @@ -53,7 +53,7 @@ scale_factor: {state.scale_factor} vram: {vram} units: {unit_count} zen objects: {Zen.thread_ctx.len} -world: {state.world_name} +level: {state.level_name} """ @@ -126,8 +126,8 @@ world: {state.world_name} work_dir = get_user_data_dir() font_size = uc.font_size ||= (20 * screen_scale).int dock_icon_size = uc.dock_icon_size ||= 100 * screen_scale - world_prefix = uc.world_prefix ||= "tutorial" - world = uc.world ||= value.world_prefix & "-1" + world = uc.world ||= "tutorial" + level = uc.level ||= value.world & "-1" show_stats = uc.show_stats ||= false mega_pixels = uc.mega_pixels ||= 2.0 start_full_screen = uc.start_full_screen ||= true @@ -138,7 +138,7 @@ world: {state.world_name} connect_address = connect_address listen_address = listen_address player_color = uc.player_color ||= color(rand(1.0), rand(1.0), rand(1.0)) - world_dir = join_path(value.work_dir, value.world) + level_dir = join_path(value.work_dir, value.world, value.level) walk_speed = uc.walk_speed ||= 500 fly_speed = uc.fly_speed ||= 1500 alt_walk_speed = uc.alt_walk_speed ||= 1000 @@ -251,20 +251,20 @@ world: {state.world_name} proc switch_world(diff: int) = var config = state.config if diff != 0: - var world = config.world - let prefix = config.world_prefix & "-" - world.remove_prefix(prefix) + var level = config.level + let prefix = config.world & "-" + level.remove_prefix(prefix) var num = try: - world.parse_int + level.parse_int except ValueError: 1 num += diff - change_loaded_world(prefix & $num) + change_loaded_level(prefix & $num) else: # force a reload of the current world - let current_world = state.config.world_dir - state.config_value.value: world_dir = "" - state.config_value.value: world_dir = current_world + let current_level = state.config.level_dir + state.config_value.value: level_dir = "" + state.config_value.value: level_dir = current_level method unhandled_input*(event: InputEvent) = if EditorVisible in state.local_flags or ConsoleVisible in state.local_flags: @@ -286,9 +286,9 @@ world: {state.world_name} event.as(InputEventKey).scancode == KEY_ENTER): set_window_fullscreen not is_window_fullscreen() - elif event.is_action_pressed("next_world"): + elif event.is_action_pressed("next_level"): self.switch_world(+1) - elif event.is_action_pressed("prev_world"): + elif event.is_action_pressed("prev_level"): self.switch_world(-1) elif event.is_action_pressed("command_mode"): state.push_flag CommandMode diff --git a/src/models/serializers.nim b/src/models/serializers.nim index d27cc3e0..cba5c368 100644 --- a/src/models/serializers.nim +++ b/src/models/serializers.nim @@ -5,7 +5,7 @@ import controllers / script_controllers / scripting var load_chunks {.threadvar.}: bool -type WorldInfo = object +type LevelInfo = object enu_version, format_version: string proc to_json_hook(self: Color): JsonNode = @@ -152,12 +152,12 @@ proc save*(unit: Unit) = for unit in unit.units: unit.save -proc save_world*(world_dir: string, save_all = false) = +proc save_level*(level_dir: string, save_all = false) = if Server in state.local_flags: - debug "saving world" - let world = WorldInfo(enu_version: enu_version, format_version: "v0.9.2") - write_file world_dir / "world.json", - jsonutils.to_json(world).pretty + debug "saving level" + let level = LevelInfo(enu_version: enu_version, format_version: "v0.9.2") + write_file level_dir / "level.json", + jsonutils.to_json(level).pretty for unit in state.units: if save_all or Dirty in unit.global_flags: @@ -218,49 +218,49 @@ proc save_user_config*(config: UserConfig) = config_file = join_path(work_dir, "config.json") write_file(config_file, jsonutils.to_json(config).pretty) -proc change_loaded_world*(world: string) = +proc change_loaded_level*(level: string) = var config = state.config var user_config = load_user_config() - config.world = world - state.world_name = config.world - user_config.world = some(config.world) + config.level = level + state.level_name = config.world & "/" & config.level + user_config.level = some(config.level) save_user_config(user_config) - config.world_dir = join_path(config.work_dir, config.world) + config.level_dir = join_path(config.work_dir, config.world, config.level) state.config = config -proc unload_world*(worker: Worker) = - state.global_flags += LoadingWorld +proc unload_level*(worker: Worker) = + state.global_flags += LoadingLevel state.push_flag LoadingScript state.pop_flag Playing state.units.clear_all state.pop_flag LoadingScript - state.global_flags -= LoadingWorld + state.global_flags -= LoadingLevel -proc load_world*(worker: Worker, world_dir: string) = - state.global_flags += LoadingWorld +proc load_level*(worker: Worker, level_dir: string) = + state.global_flags += LoadingLevel state.push_flag LoadingScript var config = state.config - config.world_dir = world_dir - config.data_dir = join_path(config.world_dir, "data") - config.script_dir = join_path(config.world_dir, "scripts") + config.level_dir = level_dir + config.data_dir = join_path(config.level_dir, "data") + config.script_dir = join_path(config.level_dir, "scripts") - if not file_exists(config.world_dir / "world.json"): + if not file_exists(config.level_dir / "level.json"): for file in walk_dir(config.lib_dir / "projects"): - if config.world.ends_with file.path.split_file.name: - file.path.copy_dir(config.world_dir) + if config.level.ends_with file.path.split_file.name: + file.path.copy_dir(config.level_dir) create_dir(config.data_dir) create_dir(config.script_dir) state.config = config - let world_file = world_dir / "world.json" - debug "loading ", world_file - if file_exists(world_file): - let world_json = read_file(world_file) - let world = world_json.parse_json.json_to(WorldInfo) - load_chunks = world.format_version == "v0.9" + let level_file = level_dir / "level.json" + debug "loading ", evel_file + if file_exists(level_file): + let level_json = read_file(level_file) + let level = level_json.parse_json.json_to(LevelInfo) + load_chunks = level.format_version == "v0.9" dont_join = true worker.retry_failures = true @@ -271,4 +271,4 @@ proc load_world*(worker: Worker, world_dir: string) = for unit in state.units: unit.global_flags -= Dirty state.pop_flag LoadingScript - state.global_flags -= LoadingWorld + state.global_flags -= LoadingLevel diff --git a/src/models/states.nim b/src/models/states.nim index 8b20ff9c..4b4b9aa2 100644 --- a/src/models/states.nim +++ b/src/models/states.nim @@ -86,6 +86,12 @@ proc set_flag*(self: GameState, flag: LocalStateFlags, value: bool) = else: self.pop_flag flag +proc toggle_flag*(self: GameState, flag: LocalStateFlags) = + if flag notin self.local_flags: + self.push_flag flag + else: + self.pop_flag flag + proc `+=`*(self: ZenSet[LocalStateFlags], flag: LocalStateFlags) {.error: "Use `push_flag`, `pop_flag` and `replace_flag`".} @@ -126,7 +132,7 @@ proc init*(_: type GameState): GameState = console: ConsoleModel(log: ~(seq[string], flags)), open_sign_value: ~(Sign, flags), wants: ~(seq[LocalStateFlags], flags), - world_name_value: ~("", id = "world_name"), + level_name_value: ~("", id = "level_name"), queued_action_value: ~("", flags) ) result = self diff --git a/src/nodes/player_node.nim b/src/nodes/player_node.nim index 7a0ce254..956c3c00 100644 --- a/src/nodes/player_node.nim +++ b/src/nodes/player_node.nim @@ -41,8 +41,7 @@ var # :( Most of this needs to be moved into player model gdobj PlayerNode of KinematicBody: var - alt_speed, alt_walk_speed_locked, alt_fly_speed_locked, skip_release, - skip_next_mouse_move, jump_down: bool + alt_speed, skip_release, skip_next_mouse_move, jump_down: bool aim_ray, world_ray, down_ray: RayCast jump_time, run_time: Option[MonoTime] @@ -87,11 +86,11 @@ gdobj PlayerNode of KinematicBody: proc calculate_velocity(velocity_current: Vector3, move_direction: Vector3, delta: float, flying, alt_speed: bool): Vector3 = let speed = - if not flying and not (alt_speed xor self.alt_walk_speed_locked): + if not flying and not (alt_speed xor AltWalkSpeed in state.local_flags): vec3(state.config.walk_speed) - elif not flying and (alt_speed xor self.alt_walk_speed_locked): + elif not flying and (alt_speed xor AltWalkSpeed in state.local_flags): vec3(state.config.alt_walk_speed) - elif flying and not (alt_speed xor self.alt_fly_speed_locked): + elif flying and not (alt_speed xor AltFlySpeed in state.local_flags): vec3(state.config.fly_speed) else: vec3(state.config.alt_fly_speed) @@ -135,7 +134,7 @@ gdobj PlayerNode of KinematicBody: self.skip_next_mouse_move = true state.global_flags.watch: - if LoadingWorld.added: + if LoadingLevel.added: self.model.colliders.clear self.model.transform_value.watch: @@ -178,7 +177,7 @@ gdobj PlayerNode of KinematicBody: self.model.rotation_value.pause(self.rotation_zid): self.model.rotation = rad_to_deg r.y - if LoadingWorld notin state.global_flags: + if LoadingLevel notin state.global_flags: let ray_length = if state.tool == CodeMode: 200.0 else: 100.0 if MouseCaptured notin state.local_flags: let @@ -318,9 +317,9 @@ gdobj PlayerNode of KinematicBody: if toggle: self.run_time = nil_time if self.flying: - self.alt_fly_speed_locked = not self.alt_fly_speed_locked + state.toggle_flag(AltFlySpeed) else: - self.alt_walk_speed_locked = not self.alt_walk_speed_locked + state.toggle_flag(AltWalkSpeed) else: self.run_time = some time self.alt_speed = true diff --git a/src/types.nim b/src/types.nim index 87d2aa06..b3b6306b 100644 --- a/src/types.nim +++ b/src/types.nim @@ -19,11 +19,11 @@ type CommandMode, EditorVisible, ConsoleVisible, BlockTargetVisible, ReticleVisible, DocsVisible, MouseCaptured, PrimaryDown, SecondaryDown, EditorFocused, ConsoleFocused, DocsFocused, - Playing, Flying, God, + Playing, Flying, God, AltWalkSpeed, AltFlySpeed, LoadingScript, Server, Quitting, ResettingVM GlobalStateFlags* = enum - LoadingWorld + LoadingLevel LocalModelFlags* = enum Hover, TargetMoved, Highlight, Hide @@ -66,7 +66,7 @@ type queued_action_value*: ZenValue[string] scale_factor*: float worker_ctx_name*: string - world_name_value*: ZenValue[string] + level_name_value*: ZenValue[string] Model* = ref object of RootObj id*: string @@ -157,17 +157,17 @@ type Config* = object font_size*: int world*: string + level*: string dock_icon_size*: float show_stats*: bool mega_pixels*: float - world_dir*: string + level_dir*: string data_dir*: string script_dir*: string scene*: string lib_dir*: string start_full_screen*: bool semicolon_as_colon*: bool - world_prefix*: string listen_address*: string connect_address*: string player_color*: Color @@ -183,8 +183,8 @@ type UserConfig* = object font_size*: Option[int] dock_icon_size*: Option[float] - world_prefix*: Option[string] world*: Option[string] + level*: Option[string] show_stats*: Option[bool] god_mode*: Option[bool] mega_pixels*: Option[float] diff --git a/vmlib/enu/base_bridge.nim b/vmlib/enu/base_bridge.nim index fb15d64c..9fe81b8e 100644 --- a/vmlib/enu/base_bridge.nim +++ b/vmlib/enu/base_bridge.nim @@ -38,7 +38,7 @@ bridged_to_host: proc `lock=`*(self: Unit, value: bool) proc reset*(self: Unit, clear = false) proc press_action*(name: string) - proc load_world*(name: string) + proc load_level*(name: string) # TODO: These should be in base_bridge_private, but are currently needed outside of base_api. proc echo_console*(msg: string) diff --git a/vmlib/enu/players.nim b/vmlib/enu/players.nim index b1f3de53..fdb00fa9 100644 --- a/vmlib/enu/players.nim +++ b/vmlib/enu/players.nim @@ -13,6 +13,9 @@ bridged_to_host: proc flying*(self: PlayerType): bool = discard proc `flying=`*(self: PlayerType, value: bool) = discard + proc running*(self: PlayerType): bool = discard + proc `running=`*(self: PlayerType, value: bool) = discard + proc god*(self: PlayerType): bool = discard proc `god=`*(self: PlayerType, value: bool) = discard diff --git a/vmlib/projects/tutorial-1/world.json b/vmlib/projects/tutorial-1/level.json similarity index 100% rename from vmlib/projects/tutorial-1/world.json rename to vmlib/projects/tutorial-1/level.json diff --git a/vmlib/projects/tutorial-1/scripts/bot_aqslupunw4ndq.nim b/vmlib/projects/tutorial-1/scripts/bot_aqslupunw4ndq.nim index 421adcfd..842fd097 100644 --- a/vmlib/projects/tutorial-1/scripts/bot_aqslupunw4ndq.nim +++ b/vmlib/projects/tutorial-1/scripts/bot_aqslupunw4ndq.nim @@ -262,7 +262,7 @@ This is supposed to be where you move to the next tutorial, but it hasn't been written yet. For now, click [HERE]() to turn on `God Mode`, which will let you see and modify the code for this tutorial. It's a bit of a mess, but some folks might find it interesting. Or -click [HERE]() to load `Inky: Isolation`, a +click [HERE]() to load `Inky: Isolation`, a simple game written in Enu that's loosley inspired by **Alien: Isolation**, but features Inky, the blue ghost from Pac-Man. diff --git a/vmlib/projects/tutorial-2/world.json b/vmlib/projects/tutorial-2/level.json similarity index 100% rename from vmlib/projects/tutorial-2/world.json rename to vmlib/projects/tutorial-2/level.json