diff --git a/enu.nimble b/enu.nimble index bb8f2d5d..6aaf7edf 100644 --- a/enu.nimble +++ b/enu.nimble @@ -30,7 +30,7 @@ else: requires "nim >= 1.6.10", "https://github.com/dsrw/godot-nim#892c482", - "https://github.com/dsrw/model_citizen 0.17.7", + "https://github.com/dsrw/model_citizen 0.18.3", "https://github.com/dsrw/nanoid.nim 0.2.1", "cligen 1.6.0", "https://github.com/treeform/pretty", diff --git a/src/controllers/script_controllers/host_bridge.nim b/src/controllers/script_controllers/host_bridge.nim index 91e1b800..4e69ea34 100644 --- a/src/controllers/script_controllers/host_bridge.nim +++ b/src/controllers/script_controllers/host_bridge.nim @@ -11,7 +11,7 @@ import core, models / [states, bots, builds, units, colors, signs] import libs / [interpreters, eval] import shared / errors -import ./ [defs, scripting] +import ./ [vars, scripting] include ./ host_bridge_utils proc get_last_error(self: Worker): ErrorData = diff --git a/src/controllers/script_controllers/scripting.nim b/src/controllers/script_controllers/scripting.nim index 50b5b68b..cce6feab 100644 --- a/src/controllers/script_controllers/scripting.nim +++ b/src/controllers/script_controllers/scripting.nim @@ -6,7 +6,7 @@ import pkg / compiler / [lineinfos, renderer, msgs, vmdef] import godotapi / [spatial, ray_cast, voxel_terrain] import core, models / [states, bots, builds, units, signs, players] import libs / [interpreters, eval] -import ./ defs +import ./ vars proc init*(_: type ScriptCtx, owner: Unit, clone_of: Unit = nil, interpreter: Interpreter): ScriptCtx = diff --git a/src/controllers/script_controllers/defs.nim b/src/controllers/script_controllers/vars.nim similarity index 100% rename from src/controllers/script_controllers/defs.nim rename to src/controllers/script_controllers/vars.nim diff --git a/src/controllers/script_controllers/worker.nim b/src/controllers/script_controllers/worker.nim index 2807e59b..5aae87c3 100644 --- a/src/controllers/script_controllers/worker.nim +++ b/src/controllers/script_controllers/worker.nim @@ -1,7 +1,7 @@ import std / [locks, os, random] import std / times except seconds import core, models, models / [serializers], libs / [interpreters, eval] -import ./ [defs, host_bridge, scripting] +import ./ [vars, host_bridge, scripting] var worker_lock: locks.Lock @@ -254,7 +254,7 @@ proc worker_thread(params: (ZenContext, GameState)) {.gcsafe.} = let timeout = frame_start + max_time let wait_until = frame_start + min_time - Zen.thread_ctx.recv + Zen.thread_ctx.boop inc state.frame_count for ctx_name in Zen.thread_ctx.unsubscribed: var i = 0 @@ -272,14 +272,21 @@ proc worker_thread(params: (ZenContext, GameState)) {.gcsafe.} = state.units.value.walk_tree proc(unit: Unit) = to_process.add unit to_process.shuffle + var batched: HashSet[Unit] + while to_process.len > 0 and get_mono_time() < timeout: let units = to_process to_process = @[] for unit in units: if Ready in unit.global_flags: + if unit.batch_changes: + batched.incl unit if worker.advance_unit(unit, timeout): to_process.add(unit) + for unit in batched: + unit.apply_changes + if get_mono_time() > save_at: save_world(state.config.world_dir) save_at = get_mono_time() + auto_save_interval diff --git a/src/game.nim b/src/game.nim index aeb9c3f7..7e762d20 100644 --- a/src/game.nim +++ b/src/game.nim @@ -41,7 +41,7 @@ gdobj Game of Node: script_controller: ScriptController method process*(delta: float) = - Zen.thread_ctx.recv(max_duration = (1.0 / 60.0).seconds) + Zen.thread_ctx.boop(max_duration = (1.0 / 60.0).seconds) inc state.frame_count let time = get_mono_time() if state.config.show_stats: diff --git a/src/models/builds.nim b/src/models/builds.nim index ed446396..445afd22 100644 --- a/src/models/builds.nim +++ b/src/models/builds.nim @@ -117,7 +117,15 @@ proc add_voxel(self: Build, position: Vector3, voxel: VoxelInfo) = self.chunks[buffer] = Chunk.init self.expand_bounds_to_chunk(buffer) - self.chunks[buffer][position] = voxel + if self.batching: + if position notin self.chunks[buffer] or + self.chunks[buffer][position] != voxel: + + if buffer notin self.batched_voxels: + self.batched_voxels[buffer] = init_table[Vector3, VoxelInfo]() + self.batched_voxels[buffer][position] = voxel + else: + self.chunks[buffer][position] = voxel proc del_voxel(self: Build, position: Vector3) = let buffer = position.buffer @@ -126,7 +134,7 @@ proc del_voxel(self: Build, position: Vector3) = proc restore_edits*(self: Build) = if self.id in self.shared.edits: for loc, info in self.shared.edits[self.id]: - ensure info.kind in [Manual, Hole] + ensure info.kind in {Manual, Hole} if info.kind != Hole: self.add_voxel(loc, info) else: @@ -167,7 +175,7 @@ proc draw*(self: Build, position: Vector3, voxel: VoxelInfo) {.gcsafe.} = else: self.global_flags += Dirty if self.id notin self.shared.edits: - self.shared.edits[self.id] = init_table[Vector3, VoxelInfo]() + self.shared.edits[self.id] = ~Table[Vector3, VoxelInfo] var voxel = voxel if voxel.kind == Hole and position in self: voxel.color = self.voxel_info(position).color @@ -230,8 +238,20 @@ proc fire(self: Build) = proc is_moving(self: Build, move_mode: int): bool = move_mode == 2 +method batch_changes*(self: Build): bool = + if not self.batching: + self.batching = true + result = true + +method apply_changes*(self: Build) = + if self.batching: + for buffer, chunk in self.batched_voxels: + self.chunks[buffer] += chunk + self.batched_voxels.clear + self.batching = false + method on_begin_move*(self: Build, - direction: Vector3, steps: float, move_mode: int): Callback = + direction: Vector3, steps: float, move_mode: int): Callback = let move = self.is_moving(move_mode) if move: @@ -363,7 +383,7 @@ proc init*(_: type Build, id: id, chunks: ~(Table[Vector3, Chunk], {SyncLocal, SyncRemote}), start_transform: transform, - draw_transform_value: ~Transform.init, + draw_transform_value: ~(Transform.init, flags = {}), start_color: color, drawing: true, bounds_value: ~init_aabb(vec3(), vec3(-1, -1, -1)), diff --git a/src/models/serializers.nim b/src/models/serializers.nim index fd3cc4ac..8eba8776 100644 --- a/src/models/serializers.nim +++ b/src/models/serializers.nim @@ -42,7 +42,7 @@ proc from_json_hook(self: var Vector3, json: JsonNode) = self.y = json[1].get_float self.z = json[2].get_float -proc to_json_hook(shared_edits: ZenTable[string, Table[Vector3, VoxelInfo]]): +proc to_json_hook(shared_edits: ZenTable[string, ZenTable[Vector3, VoxelInfo]]): JsonNode = let edits = collect: @@ -55,24 +55,25 @@ proc to_json_hook(shared_edits: ZenTable[string, Table[Vector3, VoxelInfo]]): result = jsonutils.to_json(edits) -proc from_json_hook(self: var Table[Vector3, VoxelInfo], +proc from_json_hook(self: var ZenTable[Vector3, VoxelInfo], json: JsonNode) {.gcsafe.} = ensure load_chunks + self = ~Table[Vector3, VoxelInfo] for chunks in json: for chunk in chunks[1]: let location = chunk[0].json_to(Vector3) let info = chunk[1].json_to(VoxelInfo) self[location] = info -proc from_json_hook(self: var ZenTable[string, Table[Vector3, VoxelInfo]], +proc from_json_hook(self: var ZenTable[string, ZenTable[Vector3, VoxelInfo]], json: JsonNode) = ensure not load_chunks for id, edits in json: for edit in edits: if id notin self: - self[id] = init_table[Vector3, VoxelInfo]() + self[id] = ~Table[Vector3, VoxelInfo] let location = edit[0].json_to(Vector3) let info = edit[1].json_to(VoxelInfo) var locations = self[id] @@ -93,7 +94,7 @@ proc from_json_hook(self: var Build, json: JsonNode) = json["start_transform"].json_to(Transform), color = color) if load_chunks: - var edit = init_table[Vector3, VoxelInfo]() + var edit = ~Table[Vector3, VoxelInfo]() edit.from_json(json["chunks"]) self.shared.edits[self.id] = edit else: diff --git a/src/models/units.nim b/src/models/units.nim index b2acced6..5cf158c9 100644 --- a/src/models/units.nim +++ b/src/models/units.nim @@ -14,7 +14,7 @@ proc init_shared*(self: Unit) = self.shared = shared if self.id notin self.shared.edits: - let table = init_table[Vector3, VoxelInfo]() + let table = ~Table[Vector3, VoxelInfo] self.shared.edits[self.id] = table proc init_unit*[T: Unit](self: T) = @@ -79,6 +79,10 @@ method main_thread_joined*(self: Unit) {.base, gcsafe.} = discard method worker_thread_joined*(self: Unit) {.base, gcsafe.} = discard +method batch_changes*(self: Unit): bool {.base, gcsafe.} = discard + +method apply_changes*(self: Unit) {.base, gcsafe.} = discard + method on_begin_move*(self: Unit, direction: Vector3, steps: float, move_mode: int): Callback {.base, gcsafe.} = @@ -99,20 +103,16 @@ method reset*(self: Unit) {.base, gcsafe.} = discard method collect_garbage*(self: Unit) {.base, gcsafe.} = - var edits = self.shared.edits - for id, edit in self.shared.edits: - for loc, voxel in edit: + for id, chunk in self.shared.edits.value: + var cleaned_chunk = chunk + for loc, voxel in chunk.value: if voxel.kind == Hole and voxel.color == action_colors[eraser]: - var locations = edits[id] - locations.del(loc) - edits[id] = locations + cleaned_chunk.del(loc) elif voxel.kind == Hole: var voxel = voxel voxel.color = action_colors[eraser] - var locations = edits[id] - locations[loc] = voxel - edits[id] = locations - self.shared.edits = edits + cleaned_chunk[loc] = voxel + self.shared.edits[id] = cleaned_chunk method ensure_visible*(self: Unit) {.base, gcsafe.} = discard diff --git a/src/types.nim b/src/types.nim index 5ab71c3c..54e02d56 100644 --- a/src/types.nim +++ b/src/types.nim @@ -81,7 +81,7 @@ type Shared* = ref object of RootObj id*: string materials*: seq[ShaderMaterial] - edits*: ZenTable[string, Table[Vector3, VoxelInfo]] + edits*: ZenTable[string, ZenTable[Vector3, VoxelInfo]] ScriptErrors* = ZenSeq[tuple[msg: string, info: TLineInfo, location: string]] @@ -151,6 +151,8 @@ type Table[string, tuple[position: Transform, color: Color, drawing: bool]] bounds_value*: ZenValue[AABB] bot_collisions*: bool + batching*: bool + batched_voxels*: Table[Vector3, Table[Vector3, VoxelInfo]] Config* = object font_size*: int