diff options
| author | tpart <tpart120@proton.me> | 2026-02-28 22:31:33 +0100 |
|---|---|---|
| committer | tpart <tpart120@proton.me> | 2026-02-28 22:31:38 +0100 |
| commit | 94cda50771a7f24f507029751ad3139ca8034801 (patch) | |
| tree | 17c89bd95f3cd1bd3e255d4293ec78e6cc528e9e /client | |
| parent | 50ebcafc17f8f0a29f59dfb86cc7a27180c8e9b8 (diff) | |
| download | hurrycurry-94cda50771a7f24f507029751ad3139ca8034801.tar hurrycurry-94cda50771a7f24f507029751ad3139ca8034801.tar.bz2 hurrycurry-94cda50771a7f24f507029751ad3139ca8034801.tar.zst | |
Rewrite old item system to work with tile stacks
Diffstat (limited to 'client')
| -rw-r--r-- | client/game.gd | 72 | ||||
| -rw-r--r-- | client/gui/menus/main/background.gd | 20 | ||||
| -rw-r--r-- | client/map/map.gd | 70 | ||||
| -rw-r--r-- | client/map/tile_factory.gd | 6 | ||||
| -rw-r--r-- | client/map/tiles/active_interact_counter.gd | 5 | ||||
| -rw-r--r-- | client/map/tiles/book.tscn | 7 | ||||
| -rw-r--r-- | client/map/tiles/exterior_tree.gd | 2 | ||||
| -rw-r--r-- | client/map/tiles/tile.gd | 2 | ||||
| -rw-r--r-- | client/player/controllable_player.gd | 7 |
9 files changed, 102 insertions, 89 deletions
diff --git a/client/game.gd b/client/game.gd index 8d2a33a0..d82ccad3 100644 --- a/client/game.gd +++ b/client/game.gd @@ -43,12 +43,11 @@ enum JoinState { var my_player_id: float = -1 var item_names: Array = [] -var item_index_by_name: Dictionary = {} var tile_names: Array = [] -var tile_index_by_name: Dictionary = {} -var tile_collide: Dictionary = {} -var tile_placeable_items: Dictionary = {} -var tile_interactable_empty: Dictionary = {} +var tile_collide: Array[String] = [] +var tile_placeable_any: Array[String] = [] +var tile_placeable_items: Dictionary[String, Array] = {} # Dictionary[String, Array[String]] +var tile_interactable_empty: Array[String] = [] var maps: Array = [] var bot_algos: Array var text_message_history: Array[TextMessage] = [] @@ -93,26 +92,21 @@ func handle_packet(p): "data": item_names = p["data"]["item_names"] tile_names = p["data"]["tile_names"] - tile_collide = {} - for tile in p["data"]["tile_collide"]: tile_collide[int(tile)] = true - tile_interactable_empty = {} - for tile in p["data"]["tile_interactable_empty"]: tile_interactable_empty[int(tile)] = true + tile_collide = [] + tile_interactable_empty = [] + tile_placeable_any = [] tile_placeable_items = {} + for tile in p["data"]["tile_collide"]: tile_collide.append(tile_names[int(tile)]) + for tile in p["data"]["tile_interactable_empty"]: tile_interactable_empty.append(tile_names[int(tile)]) + for tile in p["data"]["tile_placeable_any"]: tile_placeable_any.append(tile_names[int(tile)]) + print(tile_placeable_any) for tile in p["data"]["tile_placeable_items"]: - tile_placeable_items[int(tile)] = p["data"]["tile_placeable_items"][tile].map(func(x): return int(x)) + tile_placeable_items[tile_names[int(tile)]] = p["data"]["tile_placeable_items"][tile].map(func(x): return item_names[int(x)]) maps = p["data"]["maps"] bot_algos = p["data"]["bot_algos"] Global.hand_count = p["data"]["hand_count"] Global.hand_count_change.emit(Global.hand_count) - tile_index_by_name.clear() - for id in tile_names.size(): - tile_index_by_name[tile_names[id]] = id - - item_index_by_name.clear() - for i in range(item_names.size()): - item_index_by_name[item_names[i]] = i - Global.last_map_name = Global.current_map_name Global.current_map_name = p["data"]["current_map"] @@ -165,18 +159,18 @@ func handle_packet(p): if "player" in p.from and "player" in p.to: players[p.from.player[0]].pass_to(players[p.to.player[0]], int(p.from.player[1]), int(p.to.player[1])) elif "tile" in p.from and "player" in p.to: - var t: Tile = map.get_tile_instance(p.from.tile) + var t: Tile = map.get_topmost_instance(p.from.tile) players[p.to.player[0]].take_item(t, int(p.to.player[1])) elif "player" in p.from and "tile" in p.to: - var t: Tile = map.get_tile_instance(p.to.tile) + var t: Tile = map.get_topmost_instance(p.to.tile) players[p.from.player[0]].put_item(t, int(p.from.player[1])) elif "tile" in p.from and "tile" in p.to: - var from_tile2: Tile = map.get_tile_instance(p.from.tile) - var to_tile2: Tile = map.get_tile_instance(p.to.tile) + var from_tile2: Tile = map.get_topmost_instance(p.from.tile) + var to_tile2: Tile = map.get_topmost_instance(p.to.tile) from_tile2.pass_to(to_tile2) "set_progress": if "tile" in p.item: - var t: Tile = map.get_tile_instance(p.item.tile) + var t: Tile = map.get_topmost_instance(p.item.tile) var acting_players: Array[Player] = [] for id: float in p.players: if !players.has(id): continue @@ -186,7 +180,7 @@ func handle_packet(p): players[p.item.player[0]].progress(p.position, p.speed, p.warn, int(p.item.player[1])) "clear_progress": if "tile" in p.item: - var t: Tile = map.get_tile_instance(p.item.tile) + var t: Tile = map.get_topmost_instance(p.item.tile) t.finish() else: players[p.item.player[0]].finish(int(p.item.player[1])) @@ -194,7 +188,7 @@ func handle_packet(p): var location: Dictionary = p["location"] if p.item != null: if "tile" in p.location: - var t: Tile = map.get_tile_instance(p.location.tile) + var t: Tile = map.get_topmost_instance(p.location.tile) var i = ItemFactory.produce(item_names[p.item], t.item_base) i.animate_spawn() i.position = t.item_base.global_position @@ -218,7 +212,7 @@ func handle_packet(p): pl.set_item(i, h) else: if "tile" in p.location: - var t: Tile = map.get_tile_instance(p.location.tile) + var t: Tile = map.get_topmost_instance(p.location.tile) t.finish() t.set_item(null) else: @@ -437,21 +431,23 @@ func _process(delta): mp.send_replay_tick(delta * float(Cli.opts.get("timescale", "1"))) func get_tile_collision(pos: Vector2i) -> bool: - var t = map.get_tile_name(pos) + var t = map.get_tiles_at(pos) if t == null: return true - else: return tile_collide.has(tile_index_by_name[t]) + else: return G.has_one(t, tile_collide) func is_tile_interactive(pos: Vector2i, hands: Array) -> bool: - var tile_name = map.get_tile_name(pos) - if tile_name == null: return false - var tile = tile_index_by_name[tile_name] - if map.get_tile_instance(pos).item != null: return true - for hand in hands: - if hand == null: - if tile_interactable_empty.has(tile): return true - else: - if not tile_placeable_items.has(tile): return true - if item_index_by_name[hand.item_name] in tile_placeable_items[tile]: return true + var tiles = map.get_tiles_at(pos) + if tiles == null: return false + if map.get_tile_item(pos) != null: return true # We can pick up this item with our empty hand! + for i in range(tiles.size() - 1, -1, -1): + var tile: String = tiles[i] + for hand in hands: + if hand == null: + if tile_interactable_empty.has(tile): return true + else: + if tile_placeable_any.has(tile): return true + if tile_placeable_items.has(tile): + return tile_placeable_items[tile].has(hand.item_name) return false func reset_camera(): diff --git a/client/gui/menus/main/background.gd b/client/gui/menus/main/background.gd index e45fdaaa..7a2adef4 100644 --- a/client/gui/menus/main/background.gd +++ b/client/gui/menus/main/background.gd @@ -26,25 +26,25 @@ func _ready(): if !Global.on_vulkan(): environment.environment.tonemap_exposure = 0.25 - var tiles: Dictionary[Vector2i, Array] = {} # : Dictionary[Vector2i, Array[String]] + var tiles_dict: Dictionary[Vector2i, Array] = {} # : Dictionary[Vector2i, Array[String]] var item_counters := [] for x in range(-10, 11): for y in range(-10, 11): var w = exp(-Vector2(x, y).length() * 0.15) var k = randf() * w - var tile = null # : String? - if k > 0.25: tile = "floor" - if k > 0.4: tile = choose(CRATES) if randf() > 0.7 else "counter" - if k > 0.6: tile = choose(TOOLS) - if tile != null: - tiles[Vector2i(x,y)] = [tile] - if tile == "counter" and randf() > 0.5 and w > 0.45: + var tiles: Array = [] + if k > 0.25: tiles = ["floor"] + if k > 0.4: tiles = ["floor"] + [choose(CRATES)] if randf() > 0.7 else ["floor", "counter"] + if k > 0.6: tiles = ["floor"] + [choose(TOOLS)] + if not tiles.is_empty(): + tiles_dict[Vector2i(x,y)] = tiles + if tiles.has("counter") and randf() > 0.5 and w > 0.45: item_counters.push_back(Vector2i(x, y)) - map.set_all_tiles(tiles) + map.set_all_tiles(tiles_dict) map.flush() for v: Vector2i in item_counters: - var t: Tile = map.get_tile_instance(v) + var t = map.get_topmost_instance(v) var item := ItemFactory.produce(choose(ITEMS), t) add_child(item) item.position = t.item_base.global_position diff --git a/client/map/map.gd b/client/map/map.gd index acf7c1a4..d2467fd6 100644 --- a/client/map/map.gd +++ b/client/map/map.gd @@ -17,12 +17,13 @@ class_name Map extends Node3D class TileInfo: - func _init(position_, name_, tile_, neighbours_) -> void: - position = position_; name = name_; tile = tile_; neighbours = neighbours_ + func _init(position_, tiles_, tile_instances_, tile_parent_) -> void: + position = position_; tiles = tiles_; tile_instances = tile_instances_; tile_parent = tile_parent_ var position: Vector2i - var name: String - var tile: Tile - var neighbours: Array + var tiles: Array # Array[String] + var tile_instances: Array[Tile] + var tile_parent: Node3D + var interact_tile: Tile const NEIGHBOR_OFFSETS: Array[Vector2i] = [Vector2i.UP, Vector2i.LEFT, Vector2i.DOWN, Vector2i.RIGHT] @@ -32,26 +33,30 @@ var currently_baked = false var floor_node := MeshInstance3D.new() var tile_factory := TileFactory.new() -func get_tile_name(pos: Vector2i): # -> String? +func get_tiles_at(pos: Vector2i): # -> Array[String]? var e = tile_by_pos.get(pos) - if e != null: return e.name - else: return null -func get_tile_instance(pos: Vector2i) -> Tile: + if e == null: return null + return e.tiles +func get_topmost_instance(pos: Vector2i): # -> Tile? var e = tile_by_pos.get(pos) - if e != null: return e.tile - else: return null + if e == null: return null + return e.tile_instances[-1] +func get_tile_item(pos: Vector2i): # -> Item? + var e = get_topmost_instance(pos) + if e == null: return null + return e.item func set_all_tiles(changes: Dictionary[Vector2i, Array]): for pos: Vector2i in changes: set_tiles(Vector2i(pos.x, pos.y), changes[pos], changes) func set_tiles(pos: Vector2i, tiles: Array = [], pending_changes: Dictionary[Vector2i, Array] = {}): # tiles: Array[String] - var inst = get_tile_instance(pos) - if inst != null and not tiles.is_empty(): - for tile: String in tiles: - # TODO: Don't return, but handle changes which weren't handled by the instance below. - if inst.change(tile): - return # Instance handled change itself! + var tile_info = tile_by_pos.get(pos) + if tile_info != null: + for inst: Tile in tile_info.tile_instances: + for tile: String in tiles: + # TODO: Don't return, but handle changes which weren't handled by the instance below. + if inst.change(tile): return # Instance handled change itself! _remove_tile(pos) if not tiles.is_empty(): _add_tiles(pos, tiles, pending_changes) if autoflush: flush() @@ -67,23 +72,32 @@ func _add_tiles(pos: Vector2i, tiles: Array, pending_changes: Dictionary[Vector2 neighbors.append(tile_by_pos[neighbor_pos]) else: neighbors.append([]) + var tiles_parent = Node3D.new() + tiles_parent.name = str(pos) + add_child(tiles_parent) + var tile_instances: Array[Tile] = [] for tile_name: String in tiles: var tile := tile_factory.produce(tile_name, pos, neighbors) - add_child(tile) + tile_instances.append(tile) tile.position = Vector3(pos.x, 0, pos.y) - tile_by_pos[pos] = TileInfo.new(pos, tile_name, tile, neighbors) + tiles_parent.add_child(tile) + tile_by_pos[pos] = TileInfo.new(pos, tiles, tile_instances, tiles_parent) func _remove_tile(pos: Vector2i): - var tile := get_tile_instance(pos) - if tile == null: return - if tile.item != null: tile.item.queue_free() - if tile is FloorLike: - var floor_mesher = tile_factory.floor_meshers.get(tile.fm_id()) - if floor_mesher != null: - floor_mesher.remove_tile(pos) - tile.queue_free() + var tile_info = tile_by_pos.get(pos) + if tile_info == null: return + + var topmost_instance = get_topmost_instance(pos) + if topmost_instance.item != null: + topmost_instance.item.queue_free() + + for instance: Tile in tile_info.tile_instances: + if instance is FloorLike: + var floor_mesher = tile_factory.floor_meshers.get(instance.fm_id()) + if floor_mesher != null: + floor_mesher.remove_tile(pos) + instance.queue_free() tile_by_pos.erase(pos) - tile.name += "_queued_free" @onready var voxelgi: VoxelGI = $VoxelGI diff --git a/client/map/tile_factory.gd b/client/map/tile_factory.gd index 1640e512..dc108392 100644 --- a/client/map/tile_factory.gd +++ b/client/map/tile_factory.gd @@ -20,8 +20,10 @@ extends Object class TileName: var name# : String var variant #: String? - func _init(raw_name: String): - var c = Array(raw_name.split(":")) + var raw_name: String + func _init(raw_name_: String): + raw_name = raw_name_ + var c = Array(raw_name_.split(":")) name = c[0]; variant = c[1] if c.size() >= 2 else null # TODO Array.get throws errors class TileCC: diff --git a/client/map/tiles/active_interact_counter.gd b/client/map/tiles/active_interact_counter.gd index 742f147f..11ab9d5a 100644 --- a/client/map/tiles/active_interact_counter.gd +++ b/client/map/tiles/active_interact_counter.gd @@ -15,7 +15,7 @@ # @abstract class_name ActiveInteractCounter -extends CounterBase +extends Tile var interact_sound: AudioStreamPlayer3D = AudioStreamPlayer3D.new() var interact_tool: Node3D @@ -23,7 +23,8 @@ var acting_players: Array[Player] = [] var play_character_animation: Callable func _init(ctx: TileFactory.TileCC, station_model_: PackedScene, interact_tool_path: NodePath, play_character_animation_: Callable, audio_stream_: AudioStream): - super(ctx, station_model_) + super(ctx) + base.add_child(station_model_.instantiate()) interact_sound.stream = audio_stream_ add_child(interact_sound) interact_tool = base.get_node(interact_tool_path) diff --git a/client/map/tiles/book.tscn b/client/map/tiles/book.tscn index 9e1b144c..c7e9d141 100644 --- a/client/map/tiles/book.tscn +++ b/client/map/tiles/book.tscn @@ -1,10 +1,9 @@ -[gd_scene load_steps=2 format=3 uid="uid://c7fjfp5ygxsjc"] +[gd_scene format=3 uid="uid://c7fjfp5ygxsjc"] [ext_resource type="ArrayMesh" uid="uid://cgvow28wkwesp" path="res://map/tiles/book.res" id="1_vxs3d"] -[node name="Book" type="Node3D"] +[node name="Book" type="Node3D" unique_id=517586832] -[node name="Mesh" type="MeshInstance3D" parent="."] +[node name="Mesh" type="MeshInstance3D" parent="." unique_id=664640069] transform = Transform3D(1.19249e-08, 0, -1, 0, 1, 0, 1, 0, 1.19249e-08, 0, 0.5, 0) mesh = ExtResource("1_vxs3d") -skeleton = NodePath("") diff --git a/client/map/tiles/exterior_tree.gd b/client/map/tiles/exterior_tree.gd index 7db57cd7..faaede1c 100644 --- a/client/map/tiles/exterior_tree.gd +++ b/client/map/tiles/exterior_tree.gd @@ -14,7 +14,7 @@ # along with this program. If not, see <https://www.gnu.org/licenses/>. # class_name ExteriorTree -extends Grass +extends Tile const SCALE: Vector3 = Vector3(100., 100., 100.) const ROT: Vector3 = Vector3(1.5 * PI, 0., 0.) diff --git a/client/map/tiles/tile.gd b/client/map/tiles/tile.gd index b4928aa1..7473ff78 100644 --- a/client/map/tiles/tile.gd +++ b/client/map/tiles/tile.gd @@ -32,7 +32,7 @@ func _init(ctx: TileFactory.TileCC): base.name = "Base" base.position += Vector3(0.5, 0, 0.5) add_child(base) - self.name = str(ctx.position) + self.name = ctx.tile_name.raw_name var item_base_ = Node3D.new() # this method is supposed to be overriden @warning_ignore("static_called_on_instance") diff --git a/client/player/controllable_player.gd b/client/player/controllable_player.gd index 15567d65..cd96a0ff 100644 --- a/client/player/controllable_player.gd +++ b/client/player/controllable_player.gd @@ -221,7 +221,7 @@ func get_interact_target_fps() -> InteractTarget: if target is PlayerTarget and target.distance < 1.25: best_interact_target = target - var tile = game.map.get_tile_instance(target_tile) + var tile = game.map.get_topmost_instance(target_tile) if game.is_tile_interactive(target_tile, hand): var target_rot: float = tile.item.rotation.y if tile.item != null and not tile.item.is_round() else 0. best_interact_target = TileTarget.new(target_tile, tile, tile.item_base.global_position, target_rot) @@ -255,8 +255,9 @@ func get_interact_target() -> InteractTarget: var self_target_distance := movement_base_2d.distance_to(tile_center) if self_target_distance < MAX_PLAYER_INTERACT_DIST && distance < best_distance: best_distance = distance - var tile := game.map.get_tile_instance(offset_cursor) - var target_rot := tile.item.rotation.y if tile.item != null and not tile.item.is_round() else 0. + var tile = game.map.get_topmost_instance(offset_cursor) + var tile_item = game.map.get_tile_item(offset_cursor) + var target_rot: float = tile_item.rotation.y if tile_item != null and not tile_item.is_round() else 0. best_interact_target = TileTarget.new(offset_cursor, tile, tile.item_base.global_position, target_rot) return best_interact_target |