From 2850c266571e803a6bdea55067d85e9e44679c28 Mon Sep 17 00:00:00 2001 From: Zeeshaun Date: Fri, 6 Mar 2026 12:04:02 -0600 Subject: [PATCH 01/19] Adding location based tiling --- game/scenes/Levels/location_level.gd | 230 ++++++++++++++++++++++++++- game/scenes/UI/login_screen.gd | 33 ++-- 2 files changed, 246 insertions(+), 17 deletions(-) diff --git a/game/scenes/Levels/location_level.gd b/game/scenes/Levels/location_level.gd index fa67264..a6c979e 100644 --- a/game/scenes/Levels/location_level.gd +++ b/game/scenes/Levels/location_level.gd @@ -1,15 +1,235 @@ extends Node3D +const LOCATIONS_API_URL := "https://ploc.ranaze.com/api/Locations" + @export var tile_size := 4.0 @export var block_height := 1.0 +@export_range(1, 8, 1) var tile_radius := 3 +@export var tracked_node_path: NodePath +@export var border_color: Color = Color(0.05, 0.05, 0.05, 1.0) +@export var border_height_bias := 0.005 +@export var show_tile_labels := true +@export var tile_label_height := 0.01 +@export var tile_label_color: Color = Color(1, 1, 1, 1) @onready var _block: MeshInstance3D = $TerrainBlock @onready var _camera: Camera3D = $Camera3D +var _center_coord := Vector2i.ZERO +var _tiles_root: Node3D +var _tracked_node: Node3D +var _tile_nodes: Dictionary = {} +var _camera_start_offset := Vector3(0.0, 6.0, 10.0) +var _border_material: StandardMaterial3D +var _known_location_coords: Dictionary = {} +var _locations_loaded := false + func _ready() -> void: - var coord := SelectedCharacter.get_coord() - var block_pos := Vector3(coord.x * tile_size, block_height * 0.5, coord.y * tile_size) - _block.position = block_pos - _block.scale = Vector3(tile_size, block_height, tile_size) + _tiles_root = Node3D.new() + _tiles_root.name = "GeneratedTiles" + add_child(_tiles_root) + if _camera: - _camera.look_at(block_pos, Vector3.UP) + _camera_start_offset = _camera.global_position + + _tracked_node = get_node_or_null(tracked_node_path) as Node3D + if _tracked_node == null: + _tracked_node = get_node_or_null("Player") as Node3D + + var start_coord := SelectedCharacter.get_coord() + _center_coord = Vector2i(roundi(start_coord.x), roundi(start_coord.y)) + + _block.visible = false + await _load_existing_locations() + _rebuild_tiles(_center_coord) + _snap_camera_to_coord(_center_coord) + + +func _process(_delta: float) -> void: + if not _locations_loaded: + return + var target_world_pos := _get_stream_position() + var target_coord := _world_to_coord(target_world_pos) + if target_coord == _center_coord: + return + _center_coord = target_coord + _rebuild_tiles(_center_coord) + + +func _get_stream_position() -> Vector3: + if _tracked_node: + return _tracked_node.global_position + if _camera: + return _camera.global_position + return _coord_to_world(_center_coord) + + +func _world_to_coord(world_pos: Vector3) -> Vector2i: + return Vector2i( + roundi(world_pos.x / tile_size), + roundi(world_pos.z / tile_size) + ) + + +func _coord_to_world(coord: Vector2i) -> Vector3: + return Vector3(coord.x * tile_size, block_height * 0.5, coord.y * tile_size) + + +func _snap_camera_to_coord(coord: Vector2i) -> void: + if _camera == null: + return + var center_world := _coord_to_world(coord) + _camera.global_position = center_world + _camera_start_offset + _camera.look_at(center_world, Vector3.UP) + + +func _rebuild_tiles(center: Vector2i) -> void: + var wanted_keys: Dictionary = {} + for x in range(center.x - tile_radius, center.x + tile_radius + 1): + for y in range(center.y - tile_radius, center.y + tile_radius + 1): + var coord := Vector2i(x, y) + if not _known_location_coords.has(coord): + continue + wanted_keys[coord] = true + if _tile_nodes.has(coord): + continue + _spawn_tile(coord) + + var keys_to_remove: Array = _tile_nodes.keys() + for key in keys_to_remove: + if wanted_keys.has(key): + continue + var tile_node := _tile_nodes[key] as Node3D + if tile_node: + tile_node.queue_free() + _tile_nodes.erase(key) + + +func _spawn_tile(coord: Vector2i) -> void: + var tile_root := Node3D.new() + tile_root.name = "Tile_%d_%d" % [coord.x, coord.y] + tile_root.position = _coord_to_world(coord) + _tiles_root.add_child(tile_root) + + var tile := _block.duplicate() as MeshInstance3D + tile.name = "TileMesh" + tile.visible = true + tile.scale = Vector3(tile_size, block_height, tile_size) + tile_root.add_child(tile) + + tile.add_child(_create_tile_border()) + if show_tile_labels: + tile_root.add_child(_create_tile_label(coord)) + + var anchor := Marker3D.new() + anchor.name = "NpcAnchor" + anchor.position = Vector3(0.0, (block_height * 0.5) + 0.5, 0.0) + tile_root.add_child(anchor) + + _tile_nodes[coord] = tile_root + + +func _create_tile_border() -> MeshInstance3D: + var top_y := 0.5 + border_height_bias + var corners := [ + Vector3(-0.5, top_y, -0.5), + Vector3(0.5, top_y, -0.5), + Vector3(0.5, top_y, 0.5), + Vector3(-0.5, top_y, 0.5), + ] + + var border_mesh := ImmediateMesh.new() + border_mesh.surface_begin(Mesh.PRIMITIVE_LINES, _get_border_material()) + for idx in range(corners.size()): + var current: Vector3 = corners[idx] + var next: Vector3 = corners[(idx + 1) % corners.size()] + border_mesh.surface_add_vertex(current) + border_mesh.surface_add_vertex(next) + border_mesh.surface_end() + + var border := MeshInstance3D.new() + border.name = "TileBorder" + border.mesh = border_mesh + return border + + +func _get_border_material() -> StandardMaterial3D: + if _border_material: + return _border_material + + var material := StandardMaterial3D.new() + material.albedo_color = border_color + material.shading_mode = BaseMaterial3D.SHADING_MODE_UNSHADED + material.disable_receive_shadows = true + material.no_depth_test = true + _border_material = material + return _border_material + + +func _create_tile_label(coord: Vector2i) -> Label3D: + var label := Label3D.new() + label.name = "LocationIdLabel" + label.text = _location_id_for_coord(coord) + label.position = Vector3(0.0, (block_height * 0.5) + border_height_bias + tile_label_height, 0.0) + label.rotation_degrees = Vector3(-90.0, 0.0, 0.0) + label.billboard = BaseMaterial3D.BILLBOARD_DISABLED + label.modulate = tile_label_color + label.pixel_size = 0.01 + label.outline_size = 12 + label.no_depth_test = false + return label + + +func _location_id_for_coord(coord: Vector2i) -> String: + return "%d,%d" % [coord.x, coord.y] + + +func _load_existing_locations() -> void: + _locations_loaded = false + _known_location_coords.clear() + + var request := HTTPRequest.new() + add_child(request) + + var headers := PackedStringArray() + if not AuthState.access_token.is_empty(): + headers.append("Authorization: Bearer %s" % AuthState.access_token) + + var err := request.request(LOCATIONS_API_URL, headers, HTTPClient.METHOD_GET) + if err != OK: + push_warning("Failed to request locations: %s" % err) + request.queue_free() + _locations_loaded = true + return + + var result: Array = await request.request_completed + request.queue_free() + + var result_code: int = result[0] + var response_code: int = result[1] + var response_bytes: PackedByteArray = result[3] + var response_body: String = response_bytes.get_string_from_utf8() + if result_code != HTTPRequest.RESULT_SUCCESS or response_code < 200 or response_code >= 300: + push_warning("Failed to load locations (%s/%s): %s" % [result_code, response_code, response_body]) + _locations_loaded = true + return + + var parsed: Variant = JSON.parse_string(response_body) + if typeof(parsed) != TYPE_ARRAY: + push_warning("Locations response was not an array.") + _locations_loaded = true + return + + for item in parsed: + if typeof(item) != TYPE_DICTIONARY: + continue + var location: Dictionary = item + var coord_variant: Variant = location.get("coord", {}) + if typeof(coord_variant) != TYPE_DICTIONARY: + continue + var coord_dict: Dictionary = coord_variant + var x := int(coord_dict.get("x", 0)) + var y := int(coord_dict.get("y", 0)) + _known_location_coords[Vector2i(x, y)] = true + + _locations_loaded = true diff --git a/game/scenes/UI/login_screen.gd b/game/scenes/UI/login_screen.gd index 0d5f699..4008e41 100644 --- a/game/scenes/UI/login_screen.gd +++ b/game/scenes/UI/login_screen.gd @@ -2,16 +2,22 @@ extends Control const AUTH_LOGIN_URL := "https://pauth.ranaze.com/api/Auth/login" -@onready var _username_input: LineEdit = %UsernameInput -@onready var _password_input: LineEdit = %PasswordInput -@onready var _login_request: HTTPRequest = %LoginRequest -@onready var _error_label: Label = %ErrorLabel - -func _on_log_in_button_pressed() -> void: - var username := _username_input.text.strip_edges() - var password := _password_input.text - if username.is_empty() or password.is_empty(): - _show_error("Username and password required.") +@onready var _username_input: LineEdit = %UsernameInput +@onready var _password_input: LineEdit = %PasswordInput +@onready var _login_request: HTTPRequest = %LoginRequest +@onready var _error_label: Label = %ErrorLabel + +func _ready() -> void: + if not _username_input.is_connected("text_submitted", Callable(self, "_on_input_text_submitted")): + _username_input.text_submitted.connect(_on_input_text_submitted) + if not _password_input.is_connected("text_submitted", Callable(self, "_on_input_text_submitted")): + _password_input.text_submitted.connect(_on_input_text_submitted) + +func _on_log_in_button_pressed() -> void: + var username := _username_input.text.strip_edges() + var password := _password_input.text + if username.is_empty() or password.is_empty(): + _show_error("Username and password required.") return var payload := { @@ -44,5 +50,8 @@ func _on_login_request_completed(result: int, response_code: int, _headers: Pack func _on_back_button_pressed() -> void: get_tree().change_scene_to_file("res://scenes/UI/start_screen.tscn") -func _show_error(message: String) -> void: - _error_label.text = message +func _show_error(message: String) -> void: + _error_label.text = message + +func _on_input_text_submitted(_new_text: String) -> void: + _on_log_in_button_pressed() From 0a8cf20de98ffabbcd2f71d20803d0a475cb902d Mon Sep 17 00:00:00 2001 From: Zeeshaun Date: Fri, 6 Mar 2026 12:34:59 -0600 Subject: [PATCH 02/19] Adding scene teleporter --- game/scenes/Interaction/scene_teleporter.gd | 39 +++ .../Interaction/scene_teleporter.gd.uid | 1 + game/scenes/Interaction/scene_teleporter.tscn | 32 +++ game/scenes/Levels/level.gd | 75 ++++-- game/scenes/Levels/level.tscn | 7 +- game/scenes/Levels/location_level.gd | 235 ------------------ game/scenes/Levels/location_level.gd.uid | 1 - game/scenes/Levels/location_level.tscn | 23 -- game/scenes/Levels/transportation_level.gd | 37 +++ .../scenes/Levels/transportation_level.gd.uid | 1 + game/scenes/Levels/transportation_level.tscn | 62 +++++ game/scenes/UI/character_screen.gd | 2 +- 12 files changed, 229 insertions(+), 286 deletions(-) create mode 100644 game/scenes/Interaction/scene_teleporter.gd create mode 100644 game/scenes/Interaction/scene_teleporter.gd.uid create mode 100644 game/scenes/Interaction/scene_teleporter.tscn delete mode 100644 game/scenes/Levels/location_level.gd delete mode 100644 game/scenes/Levels/location_level.gd.uid delete mode 100644 game/scenes/Levels/location_level.tscn create mode 100644 game/scenes/Levels/transportation_level.gd create mode 100644 game/scenes/Levels/transportation_level.gd.uid create mode 100644 game/scenes/Levels/transportation_level.tscn diff --git a/game/scenes/Interaction/scene_teleporter.gd b/game/scenes/Interaction/scene_teleporter.gd new file mode 100644 index 0000000..692d43b --- /dev/null +++ b/game/scenes/Interaction/scene_teleporter.gd @@ -0,0 +1,39 @@ +extends Area3D + +@export_file("*.tscn") var target_scene_path := "res://scenes/Levels/transportation_level.tscn" +@export var target_group: StringName = &"player" +@export var one_shot := true + +var _is_transitioning := false + + +func _ready() -> void: + body_entered.connect(_on_body_entered) + + +func _on_body_entered(body: Node) -> void: + if _is_transitioning: + return + if target_group != StringName() and not body.is_in_group(target_group): + return + if target_scene_path.strip_edges() == "": + push_warning("Teleporter target scene is empty.") + return + if not ResourceLoader.exists(target_scene_path): + push_warning("Teleporter target scene does not exist: %s" % target_scene_path) + return + + _is_transitioning = true + if one_shot: + set_deferred("monitoring", false) + call_deferred("_deferred_change_scene") + + +func _deferred_change_scene() -> void: + var err := get_tree().change_scene_to_file(target_scene_path) + if err == OK: + return + push_warning("Failed to change scene to '%s' (%s)." % [target_scene_path, err]) + _is_transitioning = false + if one_shot: + set_deferred("monitoring", true) diff --git a/game/scenes/Interaction/scene_teleporter.gd.uid b/game/scenes/Interaction/scene_teleporter.gd.uid new file mode 100644 index 0000000..6f3537b --- /dev/null +++ b/game/scenes/Interaction/scene_teleporter.gd.uid @@ -0,0 +1 @@ +uid://dyvldjfan2beq diff --git a/game/scenes/Interaction/scene_teleporter.tscn b/game/scenes/Interaction/scene_teleporter.tscn new file mode 100644 index 0000000..8aa2de6 --- /dev/null +++ b/game/scenes/Interaction/scene_teleporter.tscn @@ -0,0 +1,32 @@ +[gd_scene load_steps=4 format=3] + +[ext_resource type="Script" path="res://scenes/Interaction/scene_teleporter.gd" id="1_tele"] + +[sub_resource type="CylinderShape3D" id="CylinderShape3D_tele"] +height = 3.0 +radius = 1.5 + +[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_tele"] +transparency = 1 +shading_mode = 0 +albedo_color = Color(0.15, 0.95, 1, 0.25) +emission_enabled = true +emission = Color(0.1, 0.9, 1, 1) +emission_energy_multiplier = 1.5 + +[sub_resource type="CylinderMesh" id="CylinderMesh_tele"] +material = SubResource("StandardMaterial3D_tele") +top_radius = 1.6 +bottom_radius = 1.6 +height = 3.0 + +[node name="SceneTeleporter" type="Area3D"] +collision_layer = 2 +collision_mask = 1 +script = ExtResource("1_tele") + +[node name="CollisionShape3D" type="CollisionShape3D" parent="."] +shape = SubResource("CylinderShape3D_tele") + +[node name="Visual" type="MeshInstance3D" parent="."] +mesh = SubResource("CylinderMesh_tele") diff --git a/game/scenes/Levels/level.gd b/game/scenes/Levels/level.gd index 6d2b901..d3ebef6 100644 --- a/game/scenes/Levels/level.gd +++ b/game/scenes/Levels/level.gd @@ -13,10 +13,12 @@ var time := 0.0 @onready var _player: Node = $Player @onready var _quest_text: RichTextLabel = $PhoneUI/Control/PhoneFrame/QuestText -const FIRST_QUEST_ID := "first_drive" -const FIRST_QUEST := { - "id": FIRST_QUEST_ID, - "title": "RepoBot's First Task", +const FIRST_QUEST_ID := "first_drive" +const QUEST_PROMPT_META_PREFIX := "quest_intro_prompt_shown_" +const SPAWN_DIALOG_META_KEY := "level_spawn_dialog_shown" +const FIRST_QUEST := { + "id": FIRST_QUEST_ID, + "title": "RepoBot's First Task", "description": "Get familiar with movement and vehicles.", "steps": [ { @@ -32,16 +34,17 @@ const FIRST_QUEST := { ], } -func _ready() -> void: - _setup_quests() - if show_spawn_dialog and DialogSystem and DialogSystem.has_method("show_text"): - await get_tree().process_frame - DialogSystem.show_text(spawn_dialog_text) - if spawn_dialog_auto_close_seconds > 0.0: - await get_tree().create_timer(spawn_dialog_auto_close_seconds).timeout - if DialogSystem and DialogSystem.has_method("close_if_text"): - DialogSystem.close_if_text(spawn_dialog_text) - _show_quest_intro_dialog() +func _ready() -> void: + _setup_quests() + if _should_show_spawn_dialog() and DialogSystem and DialogSystem.has_method("show_text"): + await get_tree().process_frame + DialogSystem.show_text(spawn_dialog_text) + _mark_spawn_dialog_shown() + if spawn_dialog_auto_close_seconds > 0.0: + await get_tree().create_timer(spawn_dialog_auto_close_seconds).timeout + if DialogSystem and DialogSystem.has_method("close_if_text"): + DialogSystem.close_if_text(spawn_dialog_text) + _show_quest_intro_dialog() func _process(delta): time = fmod((time + delta), day_length) @@ -94,14 +97,36 @@ func _refresh_quest_ui() -> void: _quest_text.text = "[b]%s[/b]\nStep %d/%d\n%s" % [title, step_index + 1, total_steps, step_text] -func _show_quest_intro_dialog() -> void: - if QuestManager == null: - return - var state: Dictionary = QuestManager.get_active_quest_state() - if not bool(state.get("active", false)) or bool(state.get("completed", false)): - return - var step_text := String(state.get("current_step_text", "")) - if step_text.is_empty(): - return - if DialogSystem and DialogSystem.has_method("show_text"): - DialogSystem.show_text("RepoBot: New task assigned.\n\n%s" % step_text) +func _show_quest_intro_dialog() -> void: + if QuestManager == null: + return + var state: Dictionary = QuestManager.get_active_quest_state() + if not bool(state.get("active", false)) or bool(state.get("completed", false)): + return + var quest_id := String(state.get("quest_id", "")).strip_edges() + var step_id := String(state.get("current_step_id", "")).strip_edges() + var step_text := String(state.get("current_step_text", "")) + if quest_id.is_empty() or step_id.is_empty() or step_text.is_empty(): + return + var prompt_key := "%s%s_%s" % [QUEST_PROMPT_META_PREFIX, quest_id, step_id] + if QuestManager.has_meta(prompt_key) and bool(QuestManager.get_meta(prompt_key)): + return + if DialogSystem and DialogSystem.has_method("show_text"): + DialogSystem.show_text("RepoBot: New task assigned.\n\n%s" % step_text) + QuestManager.set_meta(prompt_key, true) + + +func _should_show_spawn_dialog() -> bool: + if not show_spawn_dialog: + return false + if QuestManager == null: + return true + if not QuestManager.has_meta(SPAWN_DIALOG_META_KEY): + return true + return not bool(QuestManager.get_meta(SPAWN_DIALOG_META_KEY)) + + +func _mark_spawn_dialog_shown() -> void: + if QuestManager == null: + return + QuestManager.set_meta(SPAWN_DIALOG_META_KEY, true) diff --git a/game/scenes/Levels/level.tscn b/game/scenes/Levels/level.tscn index 67848c3..6d56063 100644 --- a/game/scenes/Levels/level.tscn +++ b/game/scenes/Levels/level.tscn @@ -1,4 +1,4 @@ -[gd_scene load_steps=81 format=3 uid="uid://dchj6g2i8ebph"] +[gd_scene load_steps=82 format=3 uid="uid://dchj6g2i8ebph"] [ext_resource type="Script" uid="uid://brgmxhhhtakja" path="res://scenes/Levels/level.gd" id="1_a4mo8"] [ext_resource type="PackedScene" uid="uid://bb6hj6l23043x" path="res://assets/models/human.blend" id="1_eg4yq"] @@ -10,6 +10,7 @@ [ext_resource type="PackedScene" uid="uid://bnqaqbgynoyys" path="res://assets/models/TestCharAnimated.glb" id="5_fi66n"] [ext_resource type="Script" uid="uid://bk53njt7i3kmv" path="res://scenes/Interaction/dialog_trigger_area.gd" id="6_dialog"] [ext_resource type="Script" uid="uid://cshtdpjp4xy2f" path="res://scenes/Quests/quest_trigger_area.gd" id="7_qtrigger"] +[ext_resource type="PackedScene" path="res://scenes/Interaction/scene_teleporter.tscn" id="8_teleporter"] [sub_resource type="PhysicsMaterial" id="PhysicsMaterial_2q6dc"] bounce = 0.5 @@ -609,6 +610,10 @@ scroll_active = false [node name="WorldEnvironment" type="WorldEnvironment" parent="."] environment = SubResource("Environment_a4mo8") +[node name="LevelExitTeleporter" parent="." instance=ExtResource("8_teleporter")] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 5.5, 0.5, 0) +target_scene_path = "res://scenes/Levels/transportation_level.tscn" + [connection signal="pressed" from="Menu/Control/VBoxContainer/ContinueButton" to="Menu" method="_on_continue_button_pressed"] [connection signal="pressed" from="Menu/Control/VBoxContainer/MainMenuButton" to="Menu" method="_on_main_menu_button_pressed"] [connection signal="pressed" from="Menu/Control/VBoxContainer/QuitButton" to="Menu" method="_on_quit_button_pressed"] diff --git a/game/scenes/Levels/location_level.gd b/game/scenes/Levels/location_level.gd deleted file mode 100644 index a6c979e..0000000 --- a/game/scenes/Levels/location_level.gd +++ /dev/null @@ -1,235 +0,0 @@ -extends Node3D - -const LOCATIONS_API_URL := "https://ploc.ranaze.com/api/Locations" - -@export var tile_size := 4.0 -@export var block_height := 1.0 -@export_range(1, 8, 1) var tile_radius := 3 -@export var tracked_node_path: NodePath -@export var border_color: Color = Color(0.05, 0.05, 0.05, 1.0) -@export var border_height_bias := 0.005 -@export var show_tile_labels := true -@export var tile_label_height := 0.01 -@export var tile_label_color: Color = Color(1, 1, 1, 1) - -@onready var _block: MeshInstance3D = $TerrainBlock -@onready var _camera: Camera3D = $Camera3D - -var _center_coord := Vector2i.ZERO -var _tiles_root: Node3D -var _tracked_node: Node3D -var _tile_nodes: Dictionary = {} -var _camera_start_offset := Vector3(0.0, 6.0, 10.0) -var _border_material: StandardMaterial3D -var _known_location_coords: Dictionary = {} -var _locations_loaded := false - -func _ready() -> void: - _tiles_root = Node3D.new() - _tiles_root.name = "GeneratedTiles" - add_child(_tiles_root) - - if _camera: - _camera_start_offset = _camera.global_position - - _tracked_node = get_node_or_null(tracked_node_path) as Node3D - if _tracked_node == null: - _tracked_node = get_node_or_null("Player") as Node3D - - var start_coord := SelectedCharacter.get_coord() - _center_coord = Vector2i(roundi(start_coord.x), roundi(start_coord.y)) - - _block.visible = false - await _load_existing_locations() - _rebuild_tiles(_center_coord) - _snap_camera_to_coord(_center_coord) - - -func _process(_delta: float) -> void: - if not _locations_loaded: - return - var target_world_pos := _get_stream_position() - var target_coord := _world_to_coord(target_world_pos) - if target_coord == _center_coord: - return - _center_coord = target_coord - _rebuild_tiles(_center_coord) - - -func _get_stream_position() -> Vector3: - if _tracked_node: - return _tracked_node.global_position - if _camera: - return _camera.global_position - return _coord_to_world(_center_coord) - - -func _world_to_coord(world_pos: Vector3) -> Vector2i: - return Vector2i( - roundi(world_pos.x / tile_size), - roundi(world_pos.z / tile_size) - ) - - -func _coord_to_world(coord: Vector2i) -> Vector3: - return Vector3(coord.x * tile_size, block_height * 0.5, coord.y * tile_size) - - -func _snap_camera_to_coord(coord: Vector2i) -> void: - if _camera == null: - return - var center_world := _coord_to_world(coord) - _camera.global_position = center_world + _camera_start_offset - _camera.look_at(center_world, Vector3.UP) - - -func _rebuild_tiles(center: Vector2i) -> void: - var wanted_keys: Dictionary = {} - for x in range(center.x - tile_radius, center.x + tile_radius + 1): - for y in range(center.y - tile_radius, center.y + tile_radius + 1): - var coord := Vector2i(x, y) - if not _known_location_coords.has(coord): - continue - wanted_keys[coord] = true - if _tile_nodes.has(coord): - continue - _spawn_tile(coord) - - var keys_to_remove: Array = _tile_nodes.keys() - for key in keys_to_remove: - if wanted_keys.has(key): - continue - var tile_node := _tile_nodes[key] as Node3D - if tile_node: - tile_node.queue_free() - _tile_nodes.erase(key) - - -func _spawn_tile(coord: Vector2i) -> void: - var tile_root := Node3D.new() - tile_root.name = "Tile_%d_%d" % [coord.x, coord.y] - tile_root.position = _coord_to_world(coord) - _tiles_root.add_child(tile_root) - - var tile := _block.duplicate() as MeshInstance3D - tile.name = "TileMesh" - tile.visible = true - tile.scale = Vector3(tile_size, block_height, tile_size) - tile_root.add_child(tile) - - tile.add_child(_create_tile_border()) - if show_tile_labels: - tile_root.add_child(_create_tile_label(coord)) - - var anchor := Marker3D.new() - anchor.name = "NpcAnchor" - anchor.position = Vector3(0.0, (block_height * 0.5) + 0.5, 0.0) - tile_root.add_child(anchor) - - _tile_nodes[coord] = tile_root - - -func _create_tile_border() -> MeshInstance3D: - var top_y := 0.5 + border_height_bias - var corners := [ - Vector3(-0.5, top_y, -0.5), - Vector3(0.5, top_y, -0.5), - Vector3(0.5, top_y, 0.5), - Vector3(-0.5, top_y, 0.5), - ] - - var border_mesh := ImmediateMesh.new() - border_mesh.surface_begin(Mesh.PRIMITIVE_LINES, _get_border_material()) - for idx in range(corners.size()): - var current: Vector3 = corners[idx] - var next: Vector3 = corners[(idx + 1) % corners.size()] - border_mesh.surface_add_vertex(current) - border_mesh.surface_add_vertex(next) - border_mesh.surface_end() - - var border := MeshInstance3D.new() - border.name = "TileBorder" - border.mesh = border_mesh - return border - - -func _get_border_material() -> StandardMaterial3D: - if _border_material: - return _border_material - - var material := StandardMaterial3D.new() - material.albedo_color = border_color - material.shading_mode = BaseMaterial3D.SHADING_MODE_UNSHADED - material.disable_receive_shadows = true - material.no_depth_test = true - _border_material = material - return _border_material - - -func _create_tile_label(coord: Vector2i) -> Label3D: - var label := Label3D.new() - label.name = "LocationIdLabel" - label.text = _location_id_for_coord(coord) - label.position = Vector3(0.0, (block_height * 0.5) + border_height_bias + tile_label_height, 0.0) - label.rotation_degrees = Vector3(-90.0, 0.0, 0.0) - label.billboard = BaseMaterial3D.BILLBOARD_DISABLED - label.modulate = tile_label_color - label.pixel_size = 0.01 - label.outline_size = 12 - label.no_depth_test = false - return label - - -func _location_id_for_coord(coord: Vector2i) -> String: - return "%d,%d" % [coord.x, coord.y] - - -func _load_existing_locations() -> void: - _locations_loaded = false - _known_location_coords.clear() - - var request := HTTPRequest.new() - add_child(request) - - var headers := PackedStringArray() - if not AuthState.access_token.is_empty(): - headers.append("Authorization: Bearer %s" % AuthState.access_token) - - var err := request.request(LOCATIONS_API_URL, headers, HTTPClient.METHOD_GET) - if err != OK: - push_warning("Failed to request locations: %s" % err) - request.queue_free() - _locations_loaded = true - return - - var result: Array = await request.request_completed - request.queue_free() - - var result_code: int = result[0] - var response_code: int = result[1] - var response_bytes: PackedByteArray = result[3] - var response_body: String = response_bytes.get_string_from_utf8() - if result_code != HTTPRequest.RESULT_SUCCESS or response_code < 200 or response_code >= 300: - push_warning("Failed to load locations (%s/%s): %s" % [result_code, response_code, response_body]) - _locations_loaded = true - return - - var parsed: Variant = JSON.parse_string(response_body) - if typeof(parsed) != TYPE_ARRAY: - push_warning("Locations response was not an array.") - _locations_loaded = true - return - - for item in parsed: - if typeof(item) != TYPE_DICTIONARY: - continue - var location: Dictionary = item - var coord_variant: Variant = location.get("coord", {}) - if typeof(coord_variant) != TYPE_DICTIONARY: - continue - var coord_dict: Dictionary = coord_variant - var x := int(coord_dict.get("x", 0)) - var y := int(coord_dict.get("y", 0)) - _known_location_coords[Vector2i(x, y)] = true - - _locations_loaded = true diff --git a/game/scenes/Levels/location_level.gd.uid b/game/scenes/Levels/location_level.gd.uid deleted file mode 100644 index 6befa8a..0000000 --- a/game/scenes/Levels/location_level.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://1fico5npv6dy diff --git a/game/scenes/Levels/location_level.tscn b/game/scenes/Levels/location_level.tscn deleted file mode 100644 index c62e156..0000000 --- a/game/scenes/Levels/location_level.tscn +++ /dev/null @@ -1,23 +0,0 @@ -[gd_scene load_steps=4 format=3 uid="uid://b7p7k1i4t0m2l"] - -[ext_resource type="Script" path="res://scenes/Levels/location_level.gd" id="1_6y4q1"] - -[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_yu2x4"] -albedo_color = Color(0.2, 0.6, 0.2, 1) - -[sub_resource type="BoxMesh" id="BoxMesh_t2a5k"] -material = SubResource("StandardMaterial3D_yu2x4") - -[node name="LocationLevel" type="Node3D"] -script = ExtResource("1_6y4q1") - -[node name="TerrainBlock" type="MeshInstance3D" parent="."] -mesh = SubResource("BoxMesh_t2a5k") - -[node name="DirectionalLight3D" type="DirectionalLight3D" parent="."] -transform = Transform3D(1, 0, 0, 0, 0.819152, 0.573576, 0, -0.573576, 0.819152, 0, 6, 0) -shadow_enabled = true - -[node name="Camera3D" type="Camera3D" parent="."] -transform = Transform3D(1, 0, 0, 0, 0.92388, 0.382683, 0, -0.382683, 0.92388, 0, 6, 10) -current = true diff --git a/game/scenes/Levels/transportation_level.gd b/game/scenes/Levels/transportation_level.gd new file mode 100644 index 0000000..c6d89cd --- /dev/null +++ b/game/scenes/Levels/transportation_level.gd @@ -0,0 +1,37 @@ +extends Node3D + +@export var player_spawn_position := Vector3(0.0, 0.0, 0.0) +@export var day_length := 120.0 +@export var start_light_angle := -90.0 + +@onready var _player: RigidBody3D = get_node_or_null("Player") as RigidBody3D +@onready var _sun: DirectionalLight3D = $DirectionalLight3D + +var _time := 0.0 + + +func _ready() -> void: + _move_player_to_spawn() + + +func _process(delta: float) -> void: + _update_day_night(delta) + + +func _move_player_to_spawn() -> void: + if _player == null: + return + _player.global_position = player_spawn_position + _player.linear_velocity = Vector3.ZERO + _player.angular_velocity = Vector3.ZERO + + +func _update_day_night(delta: float) -> void: + if _sun == null or day_length <= 0.0: + return + _time = fmod(_time + delta, day_length) + var t: float = _time / day_length + var angle: float = lerp(start_light_angle, start_light_angle + 360.0, t) + _sun.rotation_degrees.x = angle + var energy_curve: float = -sin((t * TAU) + (start_light_angle * PI / 180.0)) + _sun.light_energy = clamp((energy_curve * 1.0) + 0.2, 0.0, 1.2) diff --git a/game/scenes/Levels/transportation_level.gd.uid b/game/scenes/Levels/transportation_level.gd.uid new file mode 100644 index 0000000..ecbc775 --- /dev/null +++ b/game/scenes/Levels/transportation_level.gd.uid @@ -0,0 +1 @@ +uid://c2vm651r4nepy diff --git a/game/scenes/Levels/transportation_level.tscn b/game/scenes/Levels/transportation_level.tscn new file mode 100644 index 0000000..a2c3f74 --- /dev/null +++ b/game/scenes/Levels/transportation_level.tscn @@ -0,0 +1,62 @@ +[gd_scene load_steps=9 format=3 uid="uid://b7p7k1i4t0m2l"] + +[ext_resource type="Script" path="res://scenes/Levels/transportation_level.gd" id="1_6y4q1"] +[ext_resource type="Script" path="res://scenes/player.gd" id="2_player"] +[ext_resource type="PackedScene" path="res://assets/models/TestCharAnimated.glb" id="3_model"] +[ext_resource type="PackedScene" path="res://scenes/Interaction/scene_teleporter.tscn" id="4_teleporter"] + +[sub_resource type="SphereShape3D" id="SphereShape3D_player"] + +[sub_resource type="BoxShape3D" id="BoxShape3D_ground"] +size = Vector3(1080, 2, 1080) + +[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_ground"] +albedo_color = Color(0.194, 0.575, 0.194, 1) + +[sub_resource type="BoxMesh" id="BoxMesh_ground"] +material = SubResource("StandardMaterial3D_ground") +size = Vector3(1080, 2, 1080) + +[node name="TransportationLevel" type="Node3D"] +script = ExtResource("1_6y4q1") + +[node name="Ground" type="StaticBody3D" parent="."] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -1, 0) + +[node name="CollisionShape3D" type="CollisionShape3D" parent="Ground"] +shape = SubResource("BoxShape3D_ground") + +[node name="MeshInstance3D" type="MeshInstance3D" parent="Ground"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.00053596497, 0.0075991154, -0.0019865036) +mesh = SubResource("BoxMesh_ground") + +[node name="Player" type="RigidBody3D" parent="."] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 2, 0) +script = ExtResource("2_player") +camera_path = NodePath("Camera3D") + +[node name="CollisionShape3D" type="CollisionShape3D" parent="Player"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.5, 0) +shape = SubResource("SphereShape3D_player") + +[node name="TestCharAnimated" parent="Player" instance=ExtResource("3_model")] +transform = Transform3D(-0.9998549, 0, 0.01703362, 0, 1, 0, -0.01703362, 0, -0.9998549, 0, 0, 0) + +[node name="Camera3D" type="Camera3D" parent="Player"] +transform = Transform3D(0.9989785, -4.651856e-10, -0.045188628, 0.006969331, 0.9880354, 0.15407, 0.044647958, -0.15422754, 0.9870261, 0.22036135, 1.8988357, 0.64972365) +current = true +fov = 49.0 + +[node name="SpotLight3D" type="SpotLight3D" parent="Player"] +transform = Transform3D(1, 0, 0, 0, 0.906308, -0.422618, 0, 0.422618, 0.906308, 0, 1.7, -0.35) +visible = false +spot_range = 30.0 +spot_angle = 25.0 + +[node name="DirectionalLight3D" type="DirectionalLight3D" parent="."] +transform = Transform3D(1, 0, 0, 0, 0.819152, 0.573576, 0, -0.573576, 0.819152, 0, 6, 0) +shadow_enabled = true + +[node name="ReturnTeleporter" parent="." instance=ExtResource("4_teleporter")] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -5.5, 0.5, 0) +target_scene_path = "res://scenes/Levels/level.tscn" diff --git a/game/scenes/UI/character_screen.gd b/game/scenes/UI/character_screen.gd index 7723b95..2bc6502 100644 --- a/game/scenes/UI/character_screen.gd +++ b/game/scenes/UI/character_screen.gd @@ -110,7 +110,7 @@ func _on_select_button_pressed() -> void: var character: Dictionary = _characters[index] SelectedCharacter.set_character(character) - get_tree().change_scene_to_file("res://scenes/Levels/location_level.tscn") + get_tree().change_scene_to_file("res://scenes/Levels/transportation_level.tscn") func _on_refresh_button_pressed() -> void: _load_characters() From a689b75651352c702ed468ac4318bf6e097b2923 Mon Sep 17 00:00:00 2001 From: Zeeshaun Date: Fri, 6 Mar 2026 12:38:14 -0600 Subject: [PATCH 03/19] Fixing zoom range bug --- game/scenes/player.gd | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/game/scenes/player.gd b/game/scenes/player.gd index 01225c6..db880cf 100644 --- a/game/scenes/player.gd +++ b/game/scenes/player.gd @@ -11,8 +11,8 @@ const ACCELLERATION := 30.0 const DECELLERATION := 40.0 const JUMP_SPEED := 4.0 const MAX_NUMBER_OF_JUMPS := 2 -const MIN_FOV := 10 -const MAX_FOV := 180 +const MIN_FOV := 10.0 +const MAX_FOV := 179.0 const ZOOM_FACTOR := 1.1 # Zoom out when >1, in when < 1 var mouse_sensitivity := 0.005 var rotation_x := 0.0 @@ -187,6 +187,8 @@ func _input(event): _flashlight.visible = !_flashlight.visible func zoom_camera(factor): + if cam == null: + return var new_fov = cam.fov * factor cam.fov = clamp(new_fov, MIN_FOV, MAX_FOV) From 393521ae8cc5d5f48f6c21584545218a0aef5c4d Mon Sep 17 00:00:00 2001 From: Zeeshaun Date: Thu, 12 Mar 2026 15:01:28 -0500 Subject: [PATCH 04/19] Adding kenney prototype textures --- .../kenney_prototype_block_dark.tres | 8 ++++ .../kenney_prototype_ground_green.tres | 8 ++++ .../materials/kenney_prototype_prop_red.tres | 8 ++++ .../textures/kenney_prototype/License.txt | 23 ++++++++++ .../kenney_prototype/PNG/Dark/texture_01.png | Bin 0 -> 2774 bytes .../PNG/Dark/texture_01.png.import | 41 ++++++++++++++++++ .../kenney_prototype/PNG/Dark/texture_02.png | Bin 0 -> 1338 bytes .../PNG/Dark/texture_02.png.import | 40 +++++++++++++++++ .../kenney_prototype/PNG/Dark/texture_03.png | Bin 0 -> 2727 bytes .../PNG/Dark/texture_03.png.import | 40 +++++++++++++++++ .../kenney_prototype/PNG/Dark/texture_04.png | Bin 0 -> 13212 bytes .../PNG/Dark/texture_04.png.import | 40 +++++++++++++++++ .../kenney_prototype/PNG/Dark/texture_05.png | Bin 0 -> 19065 bytes .../PNG/Dark/texture_05.png.import | 40 +++++++++++++++++ .../kenney_prototype/PNG/Dark/texture_06.png | Bin 0 -> 2739 bytes .../PNG/Dark/texture_06.png.import | 40 +++++++++++++++++ .../kenney_prototype/PNG/Dark/texture_07.png | Bin 0 -> 2743 bytes .../PNG/Dark/texture_07.png.import | 40 +++++++++++++++++ .../kenney_prototype/PNG/Dark/texture_08.png | Bin 0 -> 637 bytes .../PNG/Dark/texture_08.png.import | 40 +++++++++++++++++ .../kenney_prototype/PNG/Dark/texture_09.png | Bin 0 -> 2838 bytes .../PNG/Dark/texture_09.png.import | 40 +++++++++++++++++ .../kenney_prototype/PNG/Dark/texture_10.png | Bin 0 -> 9183 bytes .../PNG/Dark/texture_10.png.import | 40 +++++++++++++++++ .../kenney_prototype/PNG/Dark/texture_11.png | Bin 0 -> 9048 bytes .../PNG/Dark/texture_11.png.import | 40 +++++++++++++++++ .../kenney_prototype/PNG/Dark/texture_12.png | Bin 0 -> 9585 bytes .../PNG/Dark/texture_12.png.import | 40 +++++++++++++++++ .../kenney_prototype/PNG/Dark/texture_13.png | Bin 0 -> 9867 bytes .../PNG/Dark/texture_13.png.import | 40 +++++++++++++++++ .../kenney_prototype/PNG/Green/texture_01.png | Bin 0 -> 9868 bytes .../PNG/Green/texture_01.png.import | 41 ++++++++++++++++++ .../kenney_prototype/PNG/Green/texture_02.png | Bin 0 -> 2774 bytes .../PNG/Green/texture_02.png.import | 40 +++++++++++++++++ .../kenney_prototype/PNG/Green/texture_03.png | Bin 0 -> 1338 bytes .../PNG/Green/texture_03.png.import | 40 +++++++++++++++++ .../kenney_prototype/PNG/Green/texture_04.png | Bin 0 -> 2727 bytes .../PNG/Green/texture_04.png.import | 40 +++++++++++++++++ .../kenney_prototype/PNG/Green/texture_05.png | Bin 0 -> 13212 bytes .../PNG/Green/texture_05.png.import | 40 +++++++++++++++++ .../kenney_prototype/PNG/Green/texture_06.png | Bin 0 -> 19065 bytes .../PNG/Green/texture_06.png.import | 40 +++++++++++++++++ .../kenney_prototype/PNG/Green/texture_07.png | Bin 0 -> 2739 bytes .../PNG/Green/texture_07.png.import | 40 +++++++++++++++++ .../kenney_prototype/PNG/Green/texture_08.png | Bin 0 -> 2743 bytes .../PNG/Green/texture_08.png.import | 40 +++++++++++++++++ .../kenney_prototype/PNG/Green/texture_09.png | Bin 0 -> 637 bytes .../PNG/Green/texture_09.png.import | 40 +++++++++++++++++ .../kenney_prototype/PNG/Green/texture_10.png | Bin 0 -> 2838 bytes .../PNG/Green/texture_10.png.import | 40 +++++++++++++++++ .../kenney_prototype/PNG/Green/texture_11.png | Bin 0 -> 9200 bytes .../PNG/Green/texture_11.png.import | 40 +++++++++++++++++ .../kenney_prototype/PNG/Green/texture_12.png | Bin 0 -> 9056 bytes .../PNG/Green/texture_12.png.import | 40 +++++++++++++++++ .../kenney_prototype/PNG/Green/texture_13.png | Bin 0 -> 9588 bytes .../PNG/Green/texture_13.png.import | 40 +++++++++++++++++ .../kenney_prototype/PNG/Light/texture_01.png | Bin 0 -> 1338 bytes .../PNG/Light/texture_01.png.import | 40 +++++++++++++++++ .../kenney_prototype/PNG/Light/texture_02.png | Bin 0 -> 2727 bytes .../PNG/Light/texture_02.png.import | 40 +++++++++++++++++ .../kenney_prototype/PNG/Light/texture_03.png | Bin 0 -> 13212 bytes .../PNG/Light/texture_03.png.import | 40 +++++++++++++++++ .../kenney_prototype/PNG/Light/texture_04.png | Bin 0 -> 15848 bytes .../PNG/Light/texture_04.png.import | 40 +++++++++++++++++ .../kenney_prototype/PNG/Light/texture_05.png | Bin 0 -> 2739 bytes .../PNG/Light/texture_05.png.import | 40 +++++++++++++++++ .../kenney_prototype/PNG/Light/texture_06.png | Bin 0 -> 2743 bytes .../PNG/Light/texture_06.png.import | 40 +++++++++++++++++ .../kenney_prototype/PNG/Light/texture_07.png | Bin 0 -> 637 bytes .../PNG/Light/texture_07.png.import | 40 +++++++++++++++++ .../kenney_prototype/PNG/Light/texture_08.png | Bin 0 -> 2838 bytes .../PNG/Light/texture_08.png.import | 40 +++++++++++++++++ .../kenney_prototype/PNG/Light/texture_09.png | Bin 0 -> 9102 bytes .../PNG/Light/texture_09.png.import | 40 +++++++++++++++++ .../kenney_prototype/PNG/Light/texture_10.png | Bin 0 -> 8958 bytes .../PNG/Light/texture_10.png.import | 40 +++++++++++++++++ .../kenney_prototype/PNG/Light/texture_11.png | Bin 0 -> 9494 bytes .../PNG/Light/texture_11.png.import | 40 +++++++++++++++++ .../kenney_prototype/PNG/Light/texture_12.png | Bin 0 -> 9076 bytes .../PNG/Light/texture_12.png.import | 40 +++++++++++++++++ .../kenney_prototype/PNG/Light/texture_13.png | Bin 0 -> 2774 bytes .../PNG/Light/texture_13.png.import | 40 +++++++++++++++++ .../PNG/Orange/texture_01.png | Bin 0 -> 9912 bytes .../PNG/Orange/texture_01.png.import | 40 +++++++++++++++++ .../PNG/Orange/texture_02.png | Bin 0 -> 2774 bytes .../PNG/Orange/texture_02.png.import | 40 +++++++++++++++++ .../PNG/Orange/texture_03.png | Bin 0 -> 1338 bytes .../PNG/Orange/texture_03.png.import | 40 +++++++++++++++++ .../PNG/Orange/texture_04.png | Bin 0 -> 2727 bytes .../PNG/Orange/texture_04.png.import | 40 +++++++++++++++++ .../PNG/Orange/texture_05.png | Bin 0 -> 13212 bytes .../PNG/Orange/texture_05.png.import | 40 +++++++++++++++++ .../PNG/Orange/texture_06.png | Bin 0 -> 19073 bytes .../PNG/Orange/texture_06.png.import | 40 +++++++++++++++++ .../PNG/Orange/texture_07.png | Bin 0 -> 2739 bytes .../PNG/Orange/texture_07.png.import | 40 +++++++++++++++++ .../PNG/Orange/texture_08.png | Bin 0 -> 2743 bytes .../PNG/Orange/texture_08.png.import | 40 +++++++++++++++++ .../PNG/Orange/texture_09.png | Bin 0 -> 637 bytes .../PNG/Orange/texture_09.png.import | 40 +++++++++++++++++ .../PNG/Orange/texture_10.png | Bin 0 -> 2838 bytes .../PNG/Orange/texture_10.png.import | 40 +++++++++++++++++ .../PNG/Orange/texture_11.png | Bin 0 -> 9194 bytes .../PNG/Orange/texture_11.png.import | 40 +++++++++++++++++ .../PNG/Orange/texture_12.png | Bin 0 -> 9054 bytes .../PNG/Orange/texture_12.png.import | 40 +++++++++++++++++ .../PNG/Orange/texture_13.png | Bin 0 -> 9581 bytes .../PNG/Orange/texture_13.png.import | 40 +++++++++++++++++ .../PNG/Purple/texture_01.png | Bin 0 -> 9797 bytes .../PNG/Purple/texture_01.png.import | 40 +++++++++++++++++ .../PNG/Purple/texture_02.png | Bin 0 -> 2774 bytes .../PNG/Purple/texture_02.png.import | 40 +++++++++++++++++ .../PNG/Purple/texture_03.png | Bin 0 -> 1338 bytes .../PNG/Purple/texture_03.png.import | 40 +++++++++++++++++ .../PNG/Purple/texture_04.png | Bin 0 -> 2727 bytes .../PNG/Purple/texture_04.png.import | 40 +++++++++++++++++ .../PNG/Purple/texture_05.png | Bin 0 -> 13212 bytes .../PNG/Purple/texture_05.png.import | 40 +++++++++++++++++ .../PNG/Purple/texture_06.png | Bin 0 -> 19065 bytes .../PNG/Purple/texture_06.png.import | 40 +++++++++++++++++ .../PNG/Purple/texture_07.png | Bin 0 -> 2739 bytes .../PNG/Purple/texture_07.png.import | 40 +++++++++++++++++ .../PNG/Purple/texture_08.png | Bin 0 -> 2743 bytes .../PNG/Purple/texture_08.png.import | 40 +++++++++++++++++ .../PNG/Purple/texture_09.png | Bin 0 -> 637 bytes .../PNG/Purple/texture_09.png.import | 40 +++++++++++++++++ .../PNG/Purple/texture_10.png | Bin 0 -> 2838 bytes .../PNG/Purple/texture_10.png.import | 40 +++++++++++++++++ .../PNG/Purple/texture_11.png | Bin 0 -> 9192 bytes .../PNG/Purple/texture_11.png.import | 40 +++++++++++++++++ .../PNG/Purple/texture_12.png | Bin 0 -> 9059 bytes .../PNG/Purple/texture_12.png.import | 40 +++++++++++++++++ .../PNG/Purple/texture_13.png | Bin 0 -> 9592 bytes .../PNG/Purple/texture_13.png.import | 40 +++++++++++++++++ .../kenney_prototype/PNG/Red/texture_01.png | Bin 0 -> 9911 bytes .../PNG/Red/texture_01.png.import | 41 ++++++++++++++++++ .../kenney_prototype/PNG/Red/texture_02.png | Bin 0 -> 2774 bytes .../PNG/Red/texture_02.png.import | 40 +++++++++++++++++ .../kenney_prototype/PNG/Red/texture_03.png | Bin 0 -> 1338 bytes .../PNG/Red/texture_03.png.import | 40 +++++++++++++++++ .../kenney_prototype/PNG/Red/texture_04.png | Bin 0 -> 2727 bytes .../PNG/Red/texture_04.png.import | 40 +++++++++++++++++ .../kenney_prototype/PNG/Red/texture_05.png | Bin 0 -> 13212 bytes .../PNG/Red/texture_05.png.import | 40 +++++++++++++++++ .../kenney_prototype/PNG/Red/texture_06.png | Bin 0 -> 19065 bytes .../PNG/Red/texture_06.png.import | 40 +++++++++++++++++ .../kenney_prototype/PNG/Red/texture_07.png | Bin 0 -> 2739 bytes .../PNG/Red/texture_07.png.import | 40 +++++++++++++++++ .../kenney_prototype/PNG/Red/texture_08.png | Bin 0 -> 2743 bytes .../PNG/Red/texture_08.png.import | 40 +++++++++++++++++ .../kenney_prototype/PNG/Red/texture_09.png | Bin 0 -> 637 bytes .../PNG/Red/texture_09.png.import | 40 +++++++++++++++++ .../kenney_prototype/PNG/Red/texture_10.png | Bin 0 -> 2838 bytes .../PNG/Red/texture_10.png.import | 40 +++++++++++++++++ .../kenney_prototype/PNG/Red/texture_11.png | Bin 0 -> 9207 bytes .../PNG/Red/texture_11.png.import | 40 +++++++++++++++++ .../kenney_prototype/PNG/Red/texture_12.png | Bin 0 -> 9072 bytes .../PNG/Red/texture_12.png.import | 40 +++++++++++++++++ .../kenney_prototype/PNG/Red/texture_13.png | Bin 0 -> 9590 bytes .../PNG/Red/texture_13.png.import | 40 +++++++++++++++++ game/scenes/Levels/level.tscn | 2 + game/scenes/Levels/transportation_level.tscn | 6 +-- game/scenes/Vehicles/car.tscn | 6 +-- game/scenes/block.tscn | 41 +++++++++--------- 164 files changed, 3196 insertions(+), 29 deletions(-) create mode 100644 game/assets/materials/kenney_prototype_block_dark.tres create mode 100644 game/assets/materials/kenney_prototype_ground_green.tres create mode 100644 game/assets/materials/kenney_prototype_prop_red.tres create mode 100644 game/assets/textures/kenney_prototype/License.txt create mode 100644 game/assets/textures/kenney_prototype/PNG/Dark/texture_01.png create mode 100644 game/assets/textures/kenney_prototype/PNG/Dark/texture_01.png.import create mode 100644 game/assets/textures/kenney_prototype/PNG/Dark/texture_02.png create mode 100644 game/assets/textures/kenney_prototype/PNG/Dark/texture_02.png.import create mode 100644 game/assets/textures/kenney_prototype/PNG/Dark/texture_03.png create mode 100644 game/assets/textures/kenney_prototype/PNG/Dark/texture_03.png.import create mode 100644 game/assets/textures/kenney_prototype/PNG/Dark/texture_04.png create mode 100644 game/assets/textures/kenney_prototype/PNG/Dark/texture_04.png.import create mode 100644 game/assets/textures/kenney_prototype/PNG/Dark/texture_05.png create mode 100644 game/assets/textures/kenney_prototype/PNG/Dark/texture_05.png.import create mode 100644 game/assets/textures/kenney_prototype/PNG/Dark/texture_06.png create mode 100644 game/assets/textures/kenney_prototype/PNG/Dark/texture_06.png.import create mode 100644 game/assets/textures/kenney_prototype/PNG/Dark/texture_07.png create mode 100644 game/assets/textures/kenney_prototype/PNG/Dark/texture_07.png.import create mode 100644 game/assets/textures/kenney_prototype/PNG/Dark/texture_08.png create mode 100644 game/assets/textures/kenney_prototype/PNG/Dark/texture_08.png.import create mode 100644 game/assets/textures/kenney_prototype/PNG/Dark/texture_09.png create mode 100644 game/assets/textures/kenney_prototype/PNG/Dark/texture_09.png.import create mode 100644 game/assets/textures/kenney_prototype/PNG/Dark/texture_10.png create mode 100644 game/assets/textures/kenney_prototype/PNG/Dark/texture_10.png.import create mode 100644 game/assets/textures/kenney_prototype/PNG/Dark/texture_11.png create mode 100644 game/assets/textures/kenney_prototype/PNG/Dark/texture_11.png.import create mode 100644 game/assets/textures/kenney_prototype/PNG/Dark/texture_12.png create mode 100644 game/assets/textures/kenney_prototype/PNG/Dark/texture_12.png.import create mode 100644 game/assets/textures/kenney_prototype/PNG/Dark/texture_13.png create mode 100644 game/assets/textures/kenney_prototype/PNG/Dark/texture_13.png.import create mode 100644 game/assets/textures/kenney_prototype/PNG/Green/texture_01.png create mode 100644 game/assets/textures/kenney_prototype/PNG/Green/texture_01.png.import create mode 100644 game/assets/textures/kenney_prototype/PNG/Green/texture_02.png create mode 100644 game/assets/textures/kenney_prototype/PNG/Green/texture_02.png.import create mode 100644 game/assets/textures/kenney_prototype/PNG/Green/texture_03.png create mode 100644 game/assets/textures/kenney_prototype/PNG/Green/texture_03.png.import create mode 100644 game/assets/textures/kenney_prototype/PNG/Green/texture_04.png create mode 100644 game/assets/textures/kenney_prototype/PNG/Green/texture_04.png.import create mode 100644 game/assets/textures/kenney_prototype/PNG/Green/texture_05.png create mode 100644 game/assets/textures/kenney_prototype/PNG/Green/texture_05.png.import create mode 100644 game/assets/textures/kenney_prototype/PNG/Green/texture_06.png create mode 100644 game/assets/textures/kenney_prototype/PNG/Green/texture_06.png.import create mode 100644 game/assets/textures/kenney_prototype/PNG/Green/texture_07.png create mode 100644 game/assets/textures/kenney_prototype/PNG/Green/texture_07.png.import create mode 100644 game/assets/textures/kenney_prototype/PNG/Green/texture_08.png create mode 100644 game/assets/textures/kenney_prototype/PNG/Green/texture_08.png.import create mode 100644 game/assets/textures/kenney_prototype/PNG/Green/texture_09.png create mode 100644 game/assets/textures/kenney_prototype/PNG/Green/texture_09.png.import create mode 100644 game/assets/textures/kenney_prototype/PNG/Green/texture_10.png create mode 100644 game/assets/textures/kenney_prototype/PNG/Green/texture_10.png.import create mode 100644 game/assets/textures/kenney_prototype/PNG/Green/texture_11.png create mode 100644 game/assets/textures/kenney_prototype/PNG/Green/texture_11.png.import create mode 100644 game/assets/textures/kenney_prototype/PNG/Green/texture_12.png create mode 100644 game/assets/textures/kenney_prototype/PNG/Green/texture_12.png.import create mode 100644 game/assets/textures/kenney_prototype/PNG/Green/texture_13.png create mode 100644 game/assets/textures/kenney_prototype/PNG/Green/texture_13.png.import create mode 100644 game/assets/textures/kenney_prototype/PNG/Light/texture_01.png create mode 100644 game/assets/textures/kenney_prototype/PNG/Light/texture_01.png.import create mode 100644 game/assets/textures/kenney_prototype/PNG/Light/texture_02.png create mode 100644 game/assets/textures/kenney_prototype/PNG/Light/texture_02.png.import create mode 100644 game/assets/textures/kenney_prototype/PNG/Light/texture_03.png create mode 100644 game/assets/textures/kenney_prototype/PNG/Light/texture_03.png.import create mode 100644 game/assets/textures/kenney_prototype/PNG/Light/texture_04.png create mode 100644 game/assets/textures/kenney_prototype/PNG/Light/texture_04.png.import create mode 100644 game/assets/textures/kenney_prototype/PNG/Light/texture_05.png create mode 100644 game/assets/textures/kenney_prototype/PNG/Light/texture_05.png.import create mode 100644 game/assets/textures/kenney_prototype/PNG/Light/texture_06.png create mode 100644 game/assets/textures/kenney_prototype/PNG/Light/texture_06.png.import create mode 100644 game/assets/textures/kenney_prototype/PNG/Light/texture_07.png create mode 100644 game/assets/textures/kenney_prototype/PNG/Light/texture_07.png.import create mode 100644 game/assets/textures/kenney_prototype/PNG/Light/texture_08.png create mode 100644 game/assets/textures/kenney_prototype/PNG/Light/texture_08.png.import create mode 100644 game/assets/textures/kenney_prototype/PNG/Light/texture_09.png create mode 100644 game/assets/textures/kenney_prototype/PNG/Light/texture_09.png.import create mode 100644 game/assets/textures/kenney_prototype/PNG/Light/texture_10.png create mode 100644 game/assets/textures/kenney_prototype/PNG/Light/texture_10.png.import create mode 100644 game/assets/textures/kenney_prototype/PNG/Light/texture_11.png create mode 100644 game/assets/textures/kenney_prototype/PNG/Light/texture_11.png.import create mode 100644 game/assets/textures/kenney_prototype/PNG/Light/texture_12.png create mode 100644 game/assets/textures/kenney_prototype/PNG/Light/texture_12.png.import create mode 100644 game/assets/textures/kenney_prototype/PNG/Light/texture_13.png create mode 100644 game/assets/textures/kenney_prototype/PNG/Light/texture_13.png.import create mode 100644 game/assets/textures/kenney_prototype/PNG/Orange/texture_01.png create mode 100644 game/assets/textures/kenney_prototype/PNG/Orange/texture_01.png.import create mode 100644 game/assets/textures/kenney_prototype/PNG/Orange/texture_02.png create mode 100644 game/assets/textures/kenney_prototype/PNG/Orange/texture_02.png.import create mode 100644 game/assets/textures/kenney_prototype/PNG/Orange/texture_03.png create mode 100644 game/assets/textures/kenney_prototype/PNG/Orange/texture_03.png.import create mode 100644 game/assets/textures/kenney_prototype/PNG/Orange/texture_04.png create mode 100644 game/assets/textures/kenney_prototype/PNG/Orange/texture_04.png.import create mode 100644 game/assets/textures/kenney_prototype/PNG/Orange/texture_05.png create mode 100644 game/assets/textures/kenney_prototype/PNG/Orange/texture_05.png.import create mode 100644 game/assets/textures/kenney_prototype/PNG/Orange/texture_06.png create mode 100644 game/assets/textures/kenney_prototype/PNG/Orange/texture_06.png.import create mode 100644 game/assets/textures/kenney_prototype/PNG/Orange/texture_07.png create mode 100644 game/assets/textures/kenney_prototype/PNG/Orange/texture_07.png.import create mode 100644 game/assets/textures/kenney_prototype/PNG/Orange/texture_08.png create mode 100644 game/assets/textures/kenney_prototype/PNG/Orange/texture_08.png.import create mode 100644 game/assets/textures/kenney_prototype/PNG/Orange/texture_09.png create mode 100644 game/assets/textures/kenney_prototype/PNG/Orange/texture_09.png.import create mode 100644 game/assets/textures/kenney_prototype/PNG/Orange/texture_10.png create mode 100644 game/assets/textures/kenney_prototype/PNG/Orange/texture_10.png.import create mode 100644 game/assets/textures/kenney_prototype/PNG/Orange/texture_11.png create mode 100644 game/assets/textures/kenney_prototype/PNG/Orange/texture_11.png.import create mode 100644 game/assets/textures/kenney_prototype/PNG/Orange/texture_12.png create mode 100644 game/assets/textures/kenney_prototype/PNG/Orange/texture_12.png.import create mode 100644 game/assets/textures/kenney_prototype/PNG/Orange/texture_13.png create mode 100644 game/assets/textures/kenney_prototype/PNG/Orange/texture_13.png.import create mode 100644 game/assets/textures/kenney_prototype/PNG/Purple/texture_01.png create mode 100644 game/assets/textures/kenney_prototype/PNG/Purple/texture_01.png.import create mode 100644 game/assets/textures/kenney_prototype/PNG/Purple/texture_02.png create mode 100644 game/assets/textures/kenney_prototype/PNG/Purple/texture_02.png.import create mode 100644 game/assets/textures/kenney_prototype/PNG/Purple/texture_03.png create mode 100644 game/assets/textures/kenney_prototype/PNG/Purple/texture_03.png.import create mode 100644 game/assets/textures/kenney_prototype/PNG/Purple/texture_04.png create mode 100644 game/assets/textures/kenney_prototype/PNG/Purple/texture_04.png.import create mode 100644 game/assets/textures/kenney_prototype/PNG/Purple/texture_05.png create mode 100644 game/assets/textures/kenney_prototype/PNG/Purple/texture_05.png.import create mode 100644 game/assets/textures/kenney_prototype/PNG/Purple/texture_06.png create mode 100644 game/assets/textures/kenney_prototype/PNG/Purple/texture_06.png.import create mode 100644 game/assets/textures/kenney_prototype/PNG/Purple/texture_07.png create mode 100644 game/assets/textures/kenney_prototype/PNG/Purple/texture_07.png.import create mode 100644 game/assets/textures/kenney_prototype/PNG/Purple/texture_08.png create mode 100644 game/assets/textures/kenney_prototype/PNG/Purple/texture_08.png.import create mode 100644 game/assets/textures/kenney_prototype/PNG/Purple/texture_09.png create mode 100644 game/assets/textures/kenney_prototype/PNG/Purple/texture_09.png.import create mode 100644 game/assets/textures/kenney_prototype/PNG/Purple/texture_10.png create mode 100644 game/assets/textures/kenney_prototype/PNG/Purple/texture_10.png.import create mode 100644 game/assets/textures/kenney_prototype/PNG/Purple/texture_11.png create mode 100644 game/assets/textures/kenney_prototype/PNG/Purple/texture_11.png.import create mode 100644 game/assets/textures/kenney_prototype/PNG/Purple/texture_12.png create mode 100644 game/assets/textures/kenney_prototype/PNG/Purple/texture_12.png.import create mode 100644 game/assets/textures/kenney_prototype/PNG/Purple/texture_13.png create mode 100644 game/assets/textures/kenney_prototype/PNG/Purple/texture_13.png.import create mode 100644 game/assets/textures/kenney_prototype/PNG/Red/texture_01.png create mode 100644 game/assets/textures/kenney_prototype/PNG/Red/texture_01.png.import create mode 100644 game/assets/textures/kenney_prototype/PNG/Red/texture_02.png create mode 100644 game/assets/textures/kenney_prototype/PNG/Red/texture_02.png.import create mode 100644 game/assets/textures/kenney_prototype/PNG/Red/texture_03.png create mode 100644 game/assets/textures/kenney_prototype/PNG/Red/texture_03.png.import create mode 100644 game/assets/textures/kenney_prototype/PNG/Red/texture_04.png create mode 100644 game/assets/textures/kenney_prototype/PNG/Red/texture_04.png.import create mode 100644 game/assets/textures/kenney_prototype/PNG/Red/texture_05.png create mode 100644 game/assets/textures/kenney_prototype/PNG/Red/texture_05.png.import create mode 100644 game/assets/textures/kenney_prototype/PNG/Red/texture_06.png create mode 100644 game/assets/textures/kenney_prototype/PNG/Red/texture_06.png.import create mode 100644 game/assets/textures/kenney_prototype/PNG/Red/texture_07.png create mode 100644 game/assets/textures/kenney_prototype/PNG/Red/texture_07.png.import create mode 100644 game/assets/textures/kenney_prototype/PNG/Red/texture_08.png create mode 100644 game/assets/textures/kenney_prototype/PNG/Red/texture_08.png.import create mode 100644 game/assets/textures/kenney_prototype/PNG/Red/texture_09.png create mode 100644 game/assets/textures/kenney_prototype/PNG/Red/texture_09.png.import create mode 100644 game/assets/textures/kenney_prototype/PNG/Red/texture_10.png create mode 100644 game/assets/textures/kenney_prototype/PNG/Red/texture_10.png.import create mode 100644 game/assets/textures/kenney_prototype/PNG/Red/texture_11.png create mode 100644 game/assets/textures/kenney_prototype/PNG/Red/texture_11.png.import create mode 100644 game/assets/textures/kenney_prototype/PNG/Red/texture_12.png create mode 100644 game/assets/textures/kenney_prototype/PNG/Red/texture_12.png.import create mode 100644 game/assets/textures/kenney_prototype/PNG/Red/texture_13.png create mode 100644 game/assets/textures/kenney_prototype/PNG/Red/texture_13.png.import diff --git a/game/assets/materials/kenney_prototype_block_dark.tres b/game/assets/materials/kenney_prototype_block_dark.tres new file mode 100644 index 0000000..6ffbb83 --- /dev/null +++ b/game/assets/materials/kenney_prototype_block_dark.tres @@ -0,0 +1,8 @@ +[gd_resource type="StandardMaterial3D" load_steps=2 format=3] + +[ext_resource type="Texture2D" path="res://assets/textures/kenney_prototype/PNG/Dark/texture_01.png" id="1_block"] + +[resource] +albedo_texture = ExtResource("1_block") +uv1_triplanar = true +uv1_scale = Vector3(1, 1, 1) diff --git a/game/assets/materials/kenney_prototype_ground_green.tres b/game/assets/materials/kenney_prototype_ground_green.tres new file mode 100644 index 0000000..06090cc --- /dev/null +++ b/game/assets/materials/kenney_prototype_ground_green.tres @@ -0,0 +1,8 @@ +[gd_resource type="StandardMaterial3D" load_steps=2 format=3] + +[ext_resource type="Texture2D" path="res://assets/textures/kenney_prototype/PNG/Green/texture_01.png" id="1_ground"] + +[resource] +albedo_texture = ExtResource("1_ground") +uv1_triplanar = true +uv1_scale = Vector3(0.25, 0.25, 0.25) diff --git a/game/assets/materials/kenney_prototype_prop_red.tres b/game/assets/materials/kenney_prototype_prop_red.tres new file mode 100644 index 0000000..cfff784 --- /dev/null +++ b/game/assets/materials/kenney_prototype_prop_red.tres @@ -0,0 +1,8 @@ +[gd_resource type="StandardMaterial3D" load_steps=2 format=3] + +[ext_resource type="Texture2D" path="res://assets/textures/kenney_prototype/PNG/Red/texture_01.png" id="1_prop"] + +[resource] +albedo_texture = ExtResource("1_prop") +uv1_triplanar = true +uv1_scale = Vector3(1, 1, 1) diff --git a/game/assets/textures/kenney_prototype/License.txt b/game/assets/textures/kenney_prototype/License.txt new file mode 100644 index 0000000..bda3f93 --- /dev/null +++ b/game/assets/textures/kenney_prototype/License.txt @@ -0,0 +1,23 @@ + + + Prototype Textures 1.0 + + Created/distributed by Kenney (www.kenney.nl) + Creation date: 08-04-2020 + + ------------------------------ + + License: (Creative Commons Zero, CC0) + http://creativecommons.org/publicdomain/zero/1.0/ + + This content is free to use in personal, educational and commercial projects. + Support us by crediting Kenney or www.kenney.nl (this is not mandatory) + + ------------------------------ + + Donate: http://support.kenney.nl + Request: http://request.kenney.nl + Patreon: http://patreon.com/kenney/ + + Follow on Twitter for updates: + http://twitter.com/KenneyNL \ No newline at end of file diff --git a/game/assets/textures/kenney_prototype/PNG/Dark/texture_01.png b/game/assets/textures/kenney_prototype/PNG/Dark/texture_01.png new file mode 100644 index 0000000000000000000000000000000000000000..69be2111ccdf84505de4f29ccf49925419687a21 GIT binary patch literal 2774 zcmeAS@N?(olHy`uVBq!ia0y~yU;#2&7+9ErRIjnw1`sdZ(btiIVPik{pF~z5UnsyQ z#5FQ9Iy*ZzIy%?SW>G0y07%hb7@#gx81K zSnK+f_xa2gjAWQGss$JV8@L;GA1&IpmGj*GP2aaO&KV69GDF}7>wz~Lr#$$*tL)#2 zd-vH2n8-9|gljWn`rz@3VS;Rf@B{u49u(wze>TGm+i5~I@z>AE-~4@>!H;~CM!3#5 zOb_xl&dJSf`n>+l-&_Xu5gr`md%uj)pjt=u$G&xQ?MJH_vV*aqm%(O|RlR}lA(4rz Rz3za_@pScbS?83{1OOF$a6JG3 literal 0 HcmV?d00001 diff --git a/game/assets/textures/kenney_prototype/PNG/Dark/texture_01.png.import b/game/assets/textures/kenney_prototype/PNG/Dark/texture_01.png.import new file mode 100644 index 0000000..b690b77 --- /dev/null +++ b/game/assets/textures/kenney_prototype/PNG/Dark/texture_01.png.import @@ -0,0 +1,41 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://b8i4pqjyuvjtg" +path.s3tc="res://.godot/imported/texture_01.png-48911e4a61e64b91b096e3230a1d043c.s3tc.ctex" +metadata={ +"imported_formats": ["s3tc_bptc"], +"vram_texture": true +} + +[deps] + +source_file="res://assets/textures/kenney_prototype/PNG/Dark/texture_01.png" +dest_files=["res://.godot/imported/texture_01.png-48911e4a61e64b91b096e3230a1d043c.s3tc.ctex"] + +[params] + +compress/mode=2 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=true +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=0 diff --git a/game/assets/textures/kenney_prototype/PNG/Dark/texture_02.png b/game/assets/textures/kenney_prototype/PNG/Dark/texture_02.png new file mode 100644 index 0000000000000000000000000000000000000000..6fb471b66da8e1a04293df9aa244cf0c8e52641d GIT binary patch literal 1338 zcmeAS@N?(olHy`uVBq!ia0y~yU;#2&7?_xW6jSkG0T3_U(btiIVPik{pF~z5pEJNG z#C5`iiSF*6#>S>w*BPb*)!gxPaSW-r_4e{X!3G5$SI1Wixn_F^PfMFR?SP_{%jWl| z8fQK=Ug!G!{CReu5rYQ=FeuEL9(Ul*pQhsP;)BOoK$rM499fk7q$?%=em>)1a@YbU z2NV6h4eRHFlE`2I4MGeTZMX-EYryUhWmr`ClJ(44eT(w?K^1`?SR8b$+}3$~`}S9C qP=%NlgUjbj+&_L<4klNvD5zuRE$b_Z+ah2La+jy8pUXO@geCwQHcT@B literal 0 HcmV?d00001 diff --git a/game/assets/textures/kenney_prototype/PNG/Dark/texture_02.png.import b/game/assets/textures/kenney_prototype/PNG/Dark/texture_02.png.import new file mode 100644 index 0000000..c0ed22c --- /dev/null +++ b/game/assets/textures/kenney_prototype/PNG/Dark/texture_02.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dads6gh1t660d" +path="res://.godot/imported/texture_02.png-960eceabe386ca9f851706002042b1c9.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/textures/kenney_prototype/PNG/Dark/texture_02.png" +dest_files=["res://.godot/imported/texture_02.png-960eceabe386ca9f851706002042b1c9.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/game/assets/textures/kenney_prototype/PNG/Dark/texture_03.png b/game/assets/textures/kenney_prototype/PNG/Dark/texture_03.png new file mode 100644 index 0000000000000000000000000000000000000000..3f8b186b7fedf3898b1eb3358201df3f51eb8066 GIT binary patch literal 2727 zcmeAS@N?(olHy`uVBq!ia0y~yU;#2&7+9ErRIjnw1`sdZ(btiIVPik{pF~z5pFhAS z#C7rFB{OHv`v3pGySt~cvFU87PFDs7E@w{{$B>F!Z?8M@wgd>c9CTw6+hE{vV85D6 zf#jvH@BSOi_DVmw^wlHv4E7H-um64j{rSZ{d7zP_fYcC3kZxG1_j2ETrU+7Xj;e=- zzzybvRo=VaZ)Xr24H7a#;2Xn?SCiiT)@=Zl3!{Lv5NOC{IF~Pb@BdF*1_qa-kqq1q z{1>bz&4^LekPv9FWmvXr$?rPu1jf-IAuj|H_(v-g@3{$={ XeX-K{pTTh>5@dv@tDnm{r-UW|PXu2= literal 0 HcmV?d00001 diff --git a/game/assets/textures/kenney_prototype/PNG/Dark/texture_03.png.import b/game/assets/textures/kenney_prototype/PNG/Dark/texture_03.png.import new file mode 100644 index 0000000..844f217 --- /dev/null +++ b/game/assets/textures/kenney_prototype/PNG/Dark/texture_03.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://csxunghpwjxd2" +path="res://.godot/imported/texture_03.png-039c6543f305e252ad7acb009d0edcd6.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/textures/kenney_prototype/PNG/Dark/texture_03.png" +dest_files=["res://.godot/imported/texture_03.png-039c6543f305e252ad7acb009d0edcd6.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/game/assets/textures/kenney_prototype/PNG/Dark/texture_04.png b/game/assets/textures/kenney_prototype/PNG/Dark/texture_04.png new file mode 100644 index 0000000000000000000000000000000000000000..e2bc22b18acff00543fbe7f82da5129ebfcd09c9 GIT binary patch literal 13212 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 WetP@}`12a{>dSAw^wVF`Kl)#B_>q(V literal 0 HcmV?d00001 diff --git a/game/assets/textures/kenney_prototype/PNG/Dark/texture_04.png.import b/game/assets/textures/kenney_prototype/PNG/Dark/texture_04.png.import new file mode 100644 index 0000000..a3c2691 --- /dev/null +++ b/game/assets/textures/kenney_prototype/PNG/Dark/texture_04.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dmby2f03vt8ek" +path="res://.godot/imported/texture_04.png-fe95fa0099eff4ffe433a81bff8f6494.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/textures/kenney_prototype/PNG/Dark/texture_04.png" +dest_files=["res://.godot/imported/texture_04.png-fe95fa0099eff4ffe433a81bff8f6494.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/game/assets/textures/kenney_prototype/PNG/Dark/texture_05.png b/game/assets/textures/kenney_prototype/PNG/Dark/texture_05.png new file mode 100644 index 0000000000000000000000000000000000000000..3fd2e56308b236e09bc4e6060c681a3d0edb8893 GIT binary patch literal 19065 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 CTJEp_ literal 0 HcmV?d00001 diff --git a/game/assets/textures/kenney_prototype/PNG/Dark/texture_06.png.import b/game/assets/textures/kenney_prototype/PNG/Dark/texture_06.png.import new file mode 100644 index 0000000..e2a10e9 --- /dev/null +++ b/game/assets/textures/kenney_prototype/PNG/Dark/texture_06.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://i8pevhcyh3lf" +path="res://.godot/imported/texture_06.png-6482d6b88e2ba98ab34cabcb2745ac1e.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/textures/kenney_prototype/PNG/Dark/texture_06.png" +dest_files=["res://.godot/imported/texture_06.png-6482d6b88e2ba98ab34cabcb2745ac1e.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/game/assets/textures/kenney_prototype/PNG/Dark/texture_07.png b/game/assets/textures/kenney_prototype/PNG/Dark/texture_07.png new file mode 100644 index 0000000000000000000000000000000000000000..adf5e6fc67d0660e30eb7b5ba22bf238ba8fd74f GIT binary patch literal 2743 zcmeAS@N?(olHy`uVBq!ia0y~yU;#2&7+9ErRIjnw1`sdZ(btiIVPik{pF~z5pFhAS z#5FuTB04(u|NsBS#-_Tu`d^xJ6&M(}f<0XvLn>~)z2?Y!#DRy!G1#DWu>jY@{+A9v z1fzr13|@uWZmZM#bxL>%b4B`hp7(#t_G|B!2bwtwNDYAm>4w{km;b(cQ%9=KQT4D8 zXs~6-WB2*Kd(&@5n9wLqY6yH|*dc3hcm26{?4;@(RSyh-8*B^G!w+Zwj(^9@(7^6< zkDa06_WT(y>%zlE)e-c@Ne6|3e z5LaDYePd(O=mm@l3=B+4o-U3d6}R4A*vQMkz`^ABJwD2P!J@@&A0EY>%)m0y)Cd)z4*}Q$iB}lFuX{ literal 0 HcmV?d00001 diff --git a/game/assets/textures/kenney_prototype/PNG/Dark/texture_08.png.import b/game/assets/textures/kenney_prototype/PNG/Dark/texture_08.png.import new file mode 100644 index 0000000..4fe4465 --- /dev/null +++ b/game/assets/textures/kenney_prototype/PNG/Dark/texture_08.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://ncixgg70mtah" +path="res://.godot/imported/texture_08.png-399dbb29d96119a8cc5a4ae628bce06d.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/textures/kenney_prototype/PNG/Dark/texture_08.png" +dest_files=["res://.godot/imported/texture_08.png-399dbb29d96119a8cc5a4ae628bce06d.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/game/assets/textures/kenney_prototype/PNG/Dark/texture_09.png b/game/assets/textures/kenney_prototype/PNG/Dark/texture_09.png new file mode 100644 index 0000000000000000000000000000000000000000..57cc6073581c8483bec167a64627a05eed93426b GIT binary patch literal 2838 zcmeAS@N?(olHy`uVBq!ia0y~yU;#2&7+9ErRIjnw1`sdZ(btiIVPik{pF~z5Un0OK z#8p#MTUAv}U0p**M^8gTOGQOhS6AQI*!0U*i%tdxu9coHjv*Dd-d=OeI^-bI@KC3y zRmRa@VTZ28gsq28$0^2gvsL|-bKqKAcB19`U-lUX_UNB{{iwaIV!h(IkLTysf4;Im zY+LmIe}eK$XWIpv_s6e{2HHFd1~vo|vKjKG-(iqj{)FM#3El+FfpraiZO;)rpqI5h zU+TcZEAMWYHN5)VzcQ2I>ht(x+ZcIHGJd(qc!N==k-knESlevMefb{DlRa>2EpNix zfpyBL?F?~D0w=XkzTOn?@J)Qd>3^JO{&9m!@=-9LA<(dvv0_dU^N!d_%n@FB48;TL z7&=?N!IhysXm|2uhO)rjwYM2oo!{T%%e=zw|BPE~7u4AeQrHvNH?T0#*--;&-G@82 xmJQiu4B6Yw8n%MkSEFD6L!g4w!81Kjb)H5F*DX-jG5>A)qOp$`#e3*>)yJ$zt`*MkK^mRopavj{W+g=&ev5#eJwto zO*{YqJ{@h1698~Qhg{$XPUx3*B`FL3%Sla74S=j@UZxE<034qTj~Qt$EiK)+5i>bC z+0f8HrBYwMe0k^)l0u=x$KQJLS$yLvT3U0vhTr%$1w7jklP!@@3UXlS;#w`XT(D=8@@Cf@V%@{W$a zQCC-2TU*!FMY6QCYH4ZF)6=)NcQ}9ke0h2K`}b{wgM-Dz#m2@asi~=HY0rFp{cyNs z6bkkD@e@l+%YuS}eZ4wY5Ed{DiZ!i;az~r{}qtn3%x8 zAU{7p6BE;jh)53)^tEf(9z1wZP*CXa?{8va^6FL2+}zyRv+inYhc8{aeDb7GX=!PF zeSLFt^Q%{{4jlM3CFQZQvPwcif}!E@ix;R#-^T)I4(cZsPp>d|6rfxpU`2LPC&8#b?i+XJ%$; zX=%H;ou$+1FJ8PTDJkjf?5wV?K6UCejYcyyJ#+i^ZAV8Z27__(AL%&8XA(5lb@QJx_I&8+qZ8YK78opc$hWME)eSy`E$o_^=fo$l`LsHiAAJNwqw){qd4m6i3$lP3=zlpPrvk&xKW zVzHW-kR>qDVD9zA+= z@7_I0NvZw&C9SP(o<4nAQ&TfG_NlLrEH5vgl9F=$`t^PLBnAcsjEqk8_V$X4@B8rK zgOt>PxVX4GckU`FDQjuzu-WY0yZ1;-A7t;q&H%6t=xC@J`FBn9_}z<}y}ufb|Hv3R z%Gg;jV;-=-Ae*jXCpRZ(H*R4^)zLV9V{gRvD?-;#7^xPXSdUO!yIqgVc&&QM5Bb$o ziVM?8ebdLzJNgP9z?1Gzeq3S-B%SwlR8FK$FBU-uf__)e%9^#H2pdD+wY7rRK0RHw z3$vtNJ=tk|pWxp4@IxqQQ37C%0A)dVA`j5UUoaVS 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 literal 0 HcmV?d00001 diff --git a/game/assets/textures/kenney_prototype/PNG/Dark/texture_10.png.import b/game/assets/textures/kenney_prototype/PNG/Dark/texture_10.png.import new file mode 100644 index 0000000..43d049f --- /dev/null +++ b/game/assets/textures/kenney_prototype/PNG/Dark/texture_10.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://csyx7j6uhn7pj" +path="res://.godot/imported/texture_10.png-a0427e6988aab61871aedaf8b1dc17fe.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/textures/kenney_prototype/PNG/Dark/texture_10.png" +dest_files=["res://.godot/imported/texture_10.png-a0427e6988aab61871aedaf8b1dc17fe.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/game/assets/textures/kenney_prototype/PNG/Dark/texture_11.png b/game/assets/textures/kenney_prototype/PNG/Dark/texture_11.png new file mode 100644 index 0000000000000000000000000000000000000000..424ba712ed8ad1f8058075f2fe85a9beebdf615f GIT binary patch literal 9048 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 J%(Eum{{asjf^q-= literal 0 HcmV?d00001 diff --git a/game/assets/textures/kenney_prototype/PNG/Dark/texture_12.png.import b/game/assets/textures/kenney_prototype/PNG/Dark/texture_12.png.import new file mode 100644 index 0000000..b21e5b4 --- /dev/null +++ b/game/assets/textures/kenney_prototype/PNG/Dark/texture_12.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bjovin3jiwoxi" +path="res://.godot/imported/texture_12.png-8d1b0886e4e4d4bb83b9635e5b00be7d.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/textures/kenney_prototype/PNG/Dark/texture_12.png" +dest_files=["res://.godot/imported/texture_12.png-8d1b0886e4e4d4bb83b9635e5b00be7d.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/game/assets/textures/kenney_prototype/PNG/Dark/texture_13.png b/game/assets/textures/kenney_prototype/PNG/Dark/texture_13.png new file mode 100644 index 0000000000000000000000000000000000000000..13c43884ccec7829d4b6d695e89ffebc2e440e61 GIT binary patch literal 9867 zcmeHNcT|(vwm+fhC<5bH7#R?*Zy??u(^TnUC zwUFJYxDfy#YkA`6833e2ODXV`r08*i)L$xo^EIytgJAZOj}#KyLXdM zpSJ(`=i+D2o(~KRxVX4hRJ@#>o$cxAF)%P3A0HTMSEG&}AWHy`adef{%%@MR zy1M%J?|U9UesbuL-u(PL8jZ2Bu_F+wEG$k`RaNKY2c`?CefgSJzy;=y~FV)xyHU+}zycy(w1JvcZ>p-?`5{>PyTrLlb{V6y&#M;^>CgxgTAVODH|HFq5 z%gf7YY4=DZQek1CtLu4ZXP3CR_`JM_nVDH<&e)HPj2Idk_4oI8c6Nn^hCO(YZ(8>Xl-rt_y2KaWwpJ%y}P^H$?4pqNBJcsrPr^=hJ=KA zdHHm8b>VP7-M*dZ;BXd+yi#6XVQdWZ@VGcVJv}k;DIx+{SopNOyxiRU7#@$0jz%L8 z!JeL8=g+%)d;9eD^_@HCT3n3J&CNS}7)qsf`1=Qxm6eZ-jIvm)^z{2Mn3=x5K}$<3 zgTZifgI~E4`Sj_tl$2CDeOOP=U~Fs*3N>q7)hHYF*d0KkRGrsfNDE8pTi%F3^ADi4u^iL(IZrt^K-kD;DZKt*# zz2msA?CSW&8>yitE4Azl9jH!C^!8Kty;m||!zX*)#<*E=y}jNO_VFnx_HoAO{g#ta zF76Xa#221Ip&AD{B>(^?00#m1Bo8G2%1Z!TzH6{pd&W%O67@2yC;nxnzaX|vQ>+=C z47pD*$kA-2+7MVDTIx#)zL@brR9ntkM($`O*KAF8!JqCQX(uxx9V!a|2M-13gHL{A z3nlAlvA?FCSD-Ft?x2QIg|P7^oo2#60dvg?Fhv;*Cz$LC1%*xAY4thOaf}wsB2{lZF+1h)N&40G1fd!UBBH3+4Y~$Ll#$LQ!|%H4qPv6Ev`C#y1f`#6 zu><#bvxveJDlt5VqM-GmnGOTZYF@r%%wZ+v`!MAocLNicJ5p0bgNu-A=z(uU4iuK* z1=MB?k>5L&-i@&B4xAH2o7Y+rcJ1gv99f;dpa09ADxizYG+t>vq`XrwPuI^re8>ha zPeh79Pneg>gkgAAHJ zvj?t)U1KL$H+J5r7m&1CA=$-X4kYZSp) zM2K6KH0?V)5bhfX-|l0#K}ychEt_A~6UcaX*m9cn0V-xzp#qBc&-4+iRH6D04UkyE z%&dGS>kWJF0e#4?A48$#m_|Gbz)x z#aak36^4&mT%ESBrnPVItxjuKin?roj1cJJn5poW>i;cIZdaWiW`f;TIN@7xU1x9s ztHHY*+|oJ6^At-XQY~cxI;}6CFtKiIVn&vdMIi~sT*rmGKD~?)6I6T$x;m{JS!7=8 zBa~0`vEB=G-t6?ethK^ac74s`ΖXpz11goct0UA*^Gt@qN>o!qJ_IPdpPp9zf@ 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 pUkT&?-W>F^kf4x|&n1Pz^* literal 0 HcmV?d00001 diff --git a/game/assets/textures/kenney_prototype/PNG/Dark/texture_13.png.import b/game/assets/textures/kenney_prototype/PNG/Dark/texture_13.png.import new file mode 100644 index 0000000..6d033e6 --- /dev/null +++ b/game/assets/textures/kenney_prototype/PNG/Dark/texture_13.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://6bmoir20ynik" +path="res://.godot/imported/texture_13.png-7698c24bc4ccaa000bc01ab906cd2e5f.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/textures/kenney_prototype/PNG/Dark/texture_13.png" +dest_files=["res://.godot/imported/texture_13.png-7698c24bc4ccaa000bc01ab906cd2e5f.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/game/assets/textures/kenney_prototype/PNG/Green/texture_01.png b/game/assets/textures/kenney_prototype/PNG/Green/texture_01.png new file mode 100644 index 0000000000000000000000000000000000000000..d5765146f1dce038486f5ffbdfd029e94c67ae5f GIT binary patch literal 9868 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 aT%Eyc`ihG?@vt@keYS6P-IBXGAokDMD3Fi< literal 0 HcmV?d00001 diff --git a/game/assets/textures/kenney_prototype/PNG/Green/texture_01.png.import b/game/assets/textures/kenney_prototype/PNG/Green/texture_01.png.import new file mode 100644 index 0000000..a601dcf --- /dev/null +++ b/game/assets/textures/kenney_prototype/PNG/Green/texture_01.png.import @@ -0,0 +1,41 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://c6ixhluav3j7r" +path.s3tc="res://.godot/imported/texture_01.png-89479c56308e7d4336c829b935d72f77.s3tc.ctex" +metadata={ +"imported_formats": ["s3tc_bptc"], +"vram_texture": true +} + +[deps] + +source_file="res://assets/textures/kenney_prototype/PNG/Green/texture_01.png" +dest_files=["res://.godot/imported/texture_01.png-89479c56308e7d4336c829b935d72f77.s3tc.ctex"] + +[params] + +compress/mode=2 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=true +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=0 diff --git a/game/assets/textures/kenney_prototype/PNG/Green/texture_02.png b/game/assets/textures/kenney_prototype/PNG/Green/texture_02.png new file mode 100644 index 0000000000000000000000000000000000000000..7bc7cf8a0cf93d4fbf0262ce1520930d62d6faa9 GIT binary patch literal 2774 zcmeAS@N?(olHy`uVBq!ia0y~yU;#2&7+9ErRIjnw1`sdZ(btiIVPik{pF~z5UnsyQ z#MSNogs8`JJswOly3_Li|9|P5<^@qwZ7b)w{hPjTXPh${C}f7f4b}s1Hcol)dso@N z6Zh`36)=%$&Is3L#`MAC6~hGC2H^+%BRnX`_x@~#8Mf1eYT~b-lfU`gX>LWZj$oGC3qd~Qf>W_Wv=Gu=|Gh_#2Lob8PB&&J@-$No3 SS9{$7nd9l|=d#Wzp$P!)HguB! literal 0 HcmV?d00001 diff --git a/game/assets/textures/kenney_prototype/PNG/Green/texture_02.png.import b/game/assets/textures/kenney_prototype/PNG/Green/texture_02.png.import new file mode 100644 index 0000000..2c95204 --- /dev/null +++ b/game/assets/textures/kenney_prototype/PNG/Green/texture_02.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bwpfmh3kvlemk" +path="res://.godot/imported/texture_02.png-6a82345168fec8d21c2cf52543b07d63.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/textures/kenney_prototype/PNG/Green/texture_02.png" +dest_files=["res://.godot/imported/texture_02.png-6a82345168fec8d21c2cf52543b07d63.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/game/assets/textures/kenney_prototype/PNG/Green/texture_03.png b/game/assets/textures/kenney_prototype/PNG/Green/texture_03.png new file mode 100644 index 0000000000000000000000000000000000000000..e2a3889d26e665493a639396a3ffc0085d9a4848 GIT binary patch literal 1338 zcmeAS@N?(olHy`uVBq!ia0y~yU;#2&7?_xW6jSkG0T3_U(btiIVPik{pF~z5pEJNG z#I@zsR--#D(l^TuA1gfvs=4Fo;uunK>+R)(f(;5hu8yx3a?SP-o|ZOs+5tr?m(A}_ zHO_o$yw3Ic`Sa{RBL)u$U{IJfJ?_ArKTXBo#RreGfG+W8II<}DNmok#{d~s3<+w?)7hF!Z?8M@wgd>c9CTw6+hE{vV85D6 zf#jvH@BSOi_DVmw^wlHv4E7H-um64j{rSZ{d7zP_fYcC3kZxG1_j2ETrU+7Xj;e=- zzzybvRo=VaZ)Xr24H7a#;2Xn?SCiiT)@=Zl3!{Lv5NOC{IF~Pb@BdF*1_qa-kqq1q z{1>bz&4^LekPv9FWmvXr$?rPu1jf-IAuj|H_(v-g@3{$={ XeX-K{pTTh>5@dv@tDnm{r-UW|*k544 literal 0 HcmV?d00001 diff --git a/game/assets/textures/kenney_prototype/PNG/Green/texture_04.png.import b/game/assets/textures/kenney_prototype/PNG/Green/texture_04.png.import new file mode 100644 index 0000000..882075e --- /dev/null +++ b/game/assets/textures/kenney_prototype/PNG/Green/texture_04.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dbf3slco12d2p" +path="res://.godot/imported/texture_04.png-ed20497316f610b3d35ab67c79ba9928.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/textures/kenney_prototype/PNG/Green/texture_04.png" +dest_files=["res://.godot/imported/texture_04.png-ed20497316f610b3d35ab67c79ba9928.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/game/assets/textures/kenney_prototype/PNG/Green/texture_05.png b/game/assets/textures/kenney_prototype/PNG/Green/texture_05.png new file mode 100644 index 0000000000000000000000000000000000000000..84976ba6dd194085fa812f7ea8707aed3f70b3ac GIT binary patch literal 13212 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 Ub~yZb4SMyZH(&huPnjS6A4WTwzW@LL literal 0 HcmV?d00001 diff --git a/game/assets/textures/kenney_prototype/PNG/Green/texture_05.png.import b/game/assets/textures/kenney_prototype/PNG/Green/texture_05.png.import new file mode 100644 index 0000000..f3fcf47 --- /dev/null +++ b/game/assets/textures/kenney_prototype/PNG/Green/texture_05.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://fxpjus6cbowb" +path="res://.godot/imported/texture_05.png-c0468820fc54369295a4059072eb210b.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/textures/kenney_prototype/PNG/Green/texture_05.png" +dest_files=["res://.godot/imported/texture_05.png-c0468820fc54369295a4059072eb210b.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/game/assets/textures/kenney_prototype/PNG/Green/texture_06.png b/game/assets/textures/kenney_prototype/PNG/Green/texture_06.png new file mode 100644 index 0000000000000000000000000000000000000000..1128198d97306e3e90f54df2f845fdc27767d193 GIT binary patch literal 19065 zcmeHvX?zq_`tGT&Buy65!3Y6aIt)u-SP~2n_G*MN;;4y&f}_wVO5B)40mBly3W5Yg zjfjx2**N$&IHJLePEZ0>tO;w!3mTE7IwTGyllgsbZ*r4L_T-ScAMD-K@;A*p2A)X6iJ{C;~!?B-r$KN-4w{<6WNzrH!- z4u3J{`a|oNkLi{~6?Y5JD%@qFGd4W+wu17TX+9h5O z&pd4ZDo8{A^q}iB?MCjH-1ljl;|-naLw(LNI*eS7mfC12d`1&ZsdQ;jW^J>{i!@(J zyH0zPV9sgUg zc(d>?vR@ak=A5EE0OTZ}On$|l9b6in2_XIG0`eGwTn~S$$pEriD`eb50pwC3(YwR#iW++qc@V(!-3n;K(f~wZPU+toKdOoFa=?&=q#Zb#OHjE4kas*N>g~GRs&S} zYZc7e7l2BhlGnh+0u?uBvHb>AxD{M1eIBSp)AeL3#?2pC=yAr_^h}Q!XRAZDUPqkn zhn`J(8MF3zK&iaylIWj^PvmGTS&eZjQ_|dgR}z#zgXdka>$XtHFD3|@a*ppR2si+* zeow1pQ|UIpJx1bzul=Anp8kb2@%efy*`E$Drvq6nVw|AmpS5=(3jQdpU)9QB1UrIn zn%o$eAy?(CbR6_Of`672LG1Xmq4EBi@Qwn_mC!K|u3W~?)3=gZ`Y&x0<9QJXFIJS( zcBHpS98ErgR-!MwAlM24-{zZXmhyp2{ULD(|0JvJtmewjK<1>JL@I%d zo$8-yzW|xu!52*K?}1FutMVt}Bp}n5pH7Op0h!aG@xCl1)0iJGoCY%a%lIk!W+3yf z_95e$1!NW|N{##=koiy?MG}#WH+);Ygk-!~X2}6$st$=gd6*!4x_*z8V`Q!evKsS| z%yGF3X$3N}uFuiVVr10irnwlI@mJ;d#fdoT6z zHvk!*R?O_h$jnnJT^vNlzJni0Vt@?q2{#98fXsTo#XPqN$dty-+QGvd7e~`2WDPDI z55H>IIqo6&)mAx`?80AZ=`a0y-I^$9m1pw12#0}SzQ>jESAVJ5rl(xbij{EYSE-Xf z*c9vx;H|z(QFC7d@NL?l>qoS1FpgJ)ADS|7y)SU|m^a(85m^3HdyeUjEFTp=`f;fE zBn0GX$3Aiw-VXn@<&{~R%aE$O@YHtjbCls~wbzro- zm-M*S2jisfFx6q4W+%?=>nH<0f7a$OuOXjF=Dmqx4$$f1s3I4TP6az_jXW6W#E5qC zPoz`N>^Y)fj8@4b$PY;8HtE(-h#``c9>OW0qZE=iJt2&cyRftE3euS%3{ZPRfc*YY z%+5EEP9G^w`wZy(JGg_*#rVv&%w-()K;|P!!kxmO+{+T?M z__!>QC&Q6WfH`wcf#^85a;an{(g~A+Erk#r*BNUUVLj5}$wGe!qLX&r5-Z_Cv=)%* zeltw$mgdq}=`=ohn`HX4;YmfaB~HTiVSR@r`%Bqsvc7M0lYPdHd1oRxozB*L)xCgx176%IbefW zNcR-CI+u}T&vbb5mg8OG80In8a{;1imq{(R1+tS=J?O2mav!Uf9kc}!fjN$QJfq#G z9Q{$%?|ws51eYtEPJ(IvjjSi6aGsQaDfbzF1n}?Vs;(!$x11UDRd5Ti7{`qw3e{I0 zIY>UepdEuQoX#FXDNnUw!cuIs6h;#ZgjFqAlEoa0w@o{n153jtx#FdI7k4n;J)1oK zhT}PS0dbDMkwd)hokDJ7hZ}JkdG?tK{C=0yG%H2;WNUjoA>=ZzK4AL^`}`DU(ok(X zxg6HdSCMnkJHNP|htsy9BFe1?toc#7!^wbATwj<>7Oo$$h_q;k@HSFwgb*crlT98q zXf8B$!Vb6z&@7oRBA-p7O>=A-qLsoPoO9gTM`&?z%aW2D_|wRo$~L>*epjF9sdgBG z{u>Z^MLW!lxvw2fV-6c|BLS`_PGOGTecpD+YfN7wUx}6kX}56S!uux1-O2&Ql1iN(=6L%0}e8coRijWf?wgrbxC^H zU}r4A>}dD#fOALeS|dy&;5|%(rRljDvgAZZVbJxDp^H7*2xdtzT+w2B8RNuHg%|NR z_)E2}H>Q{#F`n7r*&KZ>d9jEFhcI1`iVVjhH-fj3;i^5p(|&vrcc6zY!7y8JobM}9 ze1pqji>bI?XpsicO(cM?UV&`TxlJBV>a{Xcbvks|zMZv@86JCl!65|t7Jx1WSFpK9 z?R_Osl@<-DOT11XG=1_o|G9tNdQzL_ah6mCruL!pcTNVucL&F^i{{xF-*4^OFLYHkp$oh`v`*xN0!wKG=_u0q?DyC0vB{iW;9max2?H@N9kK`c1ZQ@h(Lu8h(r(@_s8ObR?E+2E*>5kLs^KTgBdIPx?m>-|czyHe<6Af~a z3^|*85QHS^yGA6Jh2*Z~TZB=fw?4DVAonYfdkzxpjFzlEJ7FC_D+p!a8YJNp#Wr%* zz#0b0ObsJqMQp)w4XI zZV_%ft+0#rgo}f;PJUI`jFGTI9wKjm%f%dR5#BB$oncV=8Yuk=7qo(w!anZ%7$rN* z+`x6X#BpMPlp!U$7_b-W>q(U7fTh5|wgd0N7QVO8$w8Un#$-mMds;f1bi|q=wPJVe zH_WfeF;8}a$A{ofcu~n7v6C%{uO*en?_P(yD@&J>f2i|fmKbM~3+BsUHHS?)VI3(2 zalGv}-gsLt{sO5mI6+qITuu9vmD)?}c4J3B3OC$taJQc7tLa?u4o099fL>QEY|<&~ z7|Ck@;Vr&_i?a>on@EWP1PP>bElnkdwa?jJ22ce64b)r6RDVrkK>-3;A(UUi{XXfO zb%NwapmsSR!8U=vOL7b#xJEiZpnXY{?qT{ED=?xetRUSrFFU~q_a%THryn4>YAk!% zn5Ns{$t3*}DNuW`myPZfc=Cw8jeM*QW-lAZVI@3yR9DDebu4??z;VHo$Ms55r%q#w z44hJU@|5l(9`$*)$iNA}lV|i&k`#QMEi!Pb;K_4(fMf)hvPA|CY9-%m`OHpVvU!P! z=SI71W3n~pC3@av)XY(o=k>uT<-oIwL{G@%&~|L4R(k&h-S4wICaTw2?I(fLA3sY) z8Yt6Rn)!J005uY=XZ$oIb4{G$42V%@UXbjRDjZ*Nowh)dgqZXJk82OB=^?AOX)6Ui z;uBh}DSYf>s2YLbbC$L`nP$+6LUz+LkPA~Kkm;xTogT}S*McMOf_2)YD)f%!X9ka z=6FW0EREU-IeHZr_XH-ZveME-_1xSbq>O796Q97mHlVaLiu4^oJ3;R*C0Jq#6e+wEp4}vz;ACQXa@htW)s3n{aZ1gzc*qrVW@4vBkCyrTnBQJFNRHzOWszZf>jkQCC>QJE^9V%3Z3WfKL4iyT7kq#B=|5SyN9(!%TA6|eCMG9^{ z9g0+kBGsWtf%5eKnIa`dyTuC}_f;kJ^HgzOO99ENifB)0Enxo$h{w|PJ^WSrK!(Db z!uKgpgX2d*`L87(4NZEPz|ZgP4#?D9c|oJ$prK~bzuIm>LDld%*=fQc)UEg=C@t;R zdC|Fr1}vtNP&X>IM$boEPgNkwU@(!hBi zuZ`QQp|oU6`W<^H0y|WTc@=7V+e)M6VYAA>MjyYTf4PRzQf}^l$7X1I3Y4rm1v24* z(&!dcQ?>=B`{bgb`!$r7UQRj%&BPVpi@KdsjPJLkGG-n&I}k|r$ty+yS|hK$lY0c4 z@tl>0%Zg9&59<|`=2A2~S(J)KUR_oYbRDM;3MyPZsOlK4m%v;Z4#MbaEK^qmHhMXb zfv0<|QK`%RS1D=`IgH|sJ3K>kfx87Ob zP_+_4kUR~#_8n~|(+Q=!6eZtfn3u-VSBZvve+eDPg<$}dT!|MI*&;eh2Nx>pO4dZ^LgP-1BcIeD_P|9pml#}hHi2>v(B-0Qc z_DA_5TFL`5Rn=m@_7Vqp7I4~p8OUmCFN1U^r9ei$r#rMrspJLLy%)&zl;w}aNI7L8 zxdoBoTSEuD?IjnBfChigH|rcPpNhJ8wwCss1}uDWWEh#U2Cru^&n{1kOTT8Z8jE3)aC44jLdjhUL&SMAtjbC zB)2d!O6UMoprEpWC9I1;Mse`TdZd8GGJ7#HVMRGCW6@?M-=91RWO#RYm>NPd9!s<| zAIOwei!8;8@CvA_m1AT+4`jL9t7_c|`a-yS`h9H*kohH;&CbQhm}UECJXEj6F|>f3 zz&W#9_$6ot+&96{G#6D|3r+j&nzjpm^9hlY{ainiv&{+ z7@CBYz%u`CYx!w#O@S+?8LFKW0)i#HXTdcEw7}4`b2-r3wxa*}e}HT1V>$o~O?3x= z*6m53zWpS)rfTW?U}(C5wANTpSN8|k6joQyleUXm?fNRPp_5nlFPe|+EGc$*Q zYYJ$gqiG`2x_7!qJrr$$7Fe2ukC2wucIGs=rhpcBnryh7vL*>=ngUkfY1+9ISiNAC z&@%ABK_JCyy z2%)EG7!qnG-M}&he8AHrtN}jCLV}hlpaY&JTNvmRjuX%_1$4mEv=g_z<-H}eOhJsm z)0B%bx{^2-EmO4=Jx#ljj>EhcEmK&duO}CfP7ON?EmJ-YJx%{aIxWl|uuPGl6Fp6% zkWL%v29_!Ci-4y|cpvG2$p}1O~b6}(6(9`r3?gAH>GpDTR^FdEj z9t?}SMFxUp3Wf!qCSfBC%UVd#G6ll|Pm|<@VOhZF({2o@iE(3fBD;@-mML(Efv2ee z4T@7NbI~$Y3x$=RnK4M`J97qFrkda&^N%-?0sfMp8kyzfjB zYOr$$+2}2SvSi-1yeRie&{d69dQtO2S7>V5kH_I^wj7$nkHFL<9DpCW#t2)~9?%3$ zP5bd=`;;vQ#}qUHQIHpLj#lMjCprve!IfLagi7%%m&Fl`C zxc&N9<_rd`Nj}&0JhQvr#217YTEN!?Gif6f@yIo&m4|}lI$9Ux_0>?W%cCh$C8d7n zdL>7`&x2j*GBth7Kg^9KBGp;`Z7gO+09#_*w-xT`{U|^Yp| zs>8xC2URW3%ncz~9MuL3M%g(MPY8K9T$0XwVe|>>)pf)bD_v2z74dGYYJ!)oiGRrP zIJv`9@1vv{3(v{0Wc{8@lgATsRhhaYH4X~4To*7$l{)!?G{GqJ9)+cpiGI0%`*ZF@ zA2TYeH-PR8t$|shYrD)$gYnbIoLWQ@C(&C^+wS5JN+G^EC#=1MT`sQZfutg=8&3ha zePGLTd;B@h=wn6^wie(PX`eG=bghwPJ~!YZZogN^Qh zEX~S8)HB0Yhh11Obf>JzLYd4j8=h+TR@z;Uu~MtTIr^qHVeHJX0fINOlLVG3@qr|x zMjwWeCBt9btLP7cfITREpocA>O3l<#Od3uZu@K(F8|c>b*<%Zg>hd|5%0C7VvIS@P z!BPmp+qbhsTQvQFv=~5O1$OR`v&bl|tEtEULi6%6*g9u;>pK+~o`{bCC>Wf`=GNE; zfZY*+UO@oB z3Aw*yxKb{`t^yw1PPTshHd2B>`4A)fI(ZWLM*Glo%NQDZD+a^iHPT-dmtn-{1OWY@ ze#6$ClZQ%%C8Pa7OthK#1EkRaLc8>b@@O(q>uq|=07C2gSU7+ec>|p?j2Nu}pf+_F zTUR3wkPQ1pyHPp8mc~2DQ3D8Lv_T$D4r)70w~V1Z3qaH0h+pIn#AO&UdK6<6{Ki!0 zl7~q*F-Gl~L!3l-5iHv{G>p+Ec_8Vhv8J~SAk1f<2kUi$x3p7+5u+H4QE-?k;{?}V zx`sgQj_yuUDlI3)2*jZUYzseu?9z%&Cva%=H2``Ya-jr&X10#=MMf&?q$9H%+w z?!sB$o?^`<2`c7J9z?gmoS2Dr^=R=hck}~e!9)z}Q<#hfG?0I8bcxn1CuDu2wSnCG zV-4>}d)^l%t;O^y1_uPWWD{=&5B)4}&+xeU6xWaft3Dso#!Lrz$Zr_rb^y7Fn2Ofq z-`nuSK_u6njOLMqAY@SA856b;$Q7coe}LFf^Kif*7qRxwW-^-5M*c05ld(o#0{QX3 zv@h*vFD%53pglv5lFBiO8gGzW2;|b>YlB(-p8Ujxkeq;X3CUrCz0lFf{Ene)|0dyA z@|*t!OP#StU4l&ozFUZqR?0=fuSSn>NWr%a!$=?P9y`+5v^K*o^DZR(1r3GWcNz}W z_HQI&1&dfio;1c7`Ho@=*{;rxdChp=k#8+pS@&@z({>aoRU#$4fMhu;n41PAoVYn~ zNm0GaJLj&z;k6=(O zo87sA;T!Au7@_kelZ+W4!VIWr6ywQz&I~DRyZ|_dK(^>i zN}MC4EBJ(h?KrJTj3w)w4@Pk6lXH`7jJgLAahVmyIkHLsbskd4kPsmAyfWP{)(>PG&|y)6WAve6+hRQ#50 zhT}TPPZ7B3ei~?T{_*T45!2l@GJFQ-trXFk)LdVjKS`>LR~u0@3i13&NTaJrs@F)g z`i%lxRCtQ+*O$`2O4ZR?8>PCx@C}{UT{2>Z(;0eZoTP~KfBv=(q^Jv!0Mgblc(U{! zx!|=D>44P5kf4J8lSvh8)F)uwveGySGe`Wujt@OOH|RP=gD&A1{#19&(F69FPwmp#twR z^ah}vplYkM8k`-?1(Tk{UH*yumvQ;wLDir-E-t6}v-yoTEP$w%M{K`(}$S91VqtZFaH%r)eu z|9pe@b!ALEMzBR`adR-!^W1#!iZBB1J@j~JuZ)uBRls8Ag$REG-Hp+f!NQK9~9o>fLj?63I$1?W(u z;O^d`NOdSu9g0+kBGsWtbtqCGl65Fj9g5WdJBrl(UEKYRZKbB2@DJ5R%}@O4r+r0V Vep&+m?LvV!L;gCEUkd9}6d#oGV>{~O(Dk-k~3>GA3%0|S?vr;B4q#jUs34)z{05OKYz z^P-V$LIks*=mn;ETshk~8khaeWHjd7_O<_e_#yrF10|(S^ItyyUjKZV{LXqth6YAP z0|f>)mIDn85&{g&ObHGQJRF1sD;OAFFkWC@!0y1`Aje?KP{r_NU<80+M68=peD{HY zfhgy{=Wx*SdoXz~;~y3j{lo?tI|EwyJb3%r;#eKS+V}Tm4ixwCF8KPF5#)yv0)D(< zexo-veI4(&SZ0a0|JG|xbv>W?wOG$~{>69mr`Iv(g#BmB*tVWX=KgYUUrD#3oXd5`dp!AoDY#7y$(eQDqT&zLaAi zwm7P0oX{owBPE}~o{_}z4{YZHMuvee06_r;3M#^7HhMS#z0Ax&WcgjI&k$6|H2)3n z19g(>37DNW4Coa^{`}*H-iNYlfA*C9-}6N}Ve>EZgxg=G6Sn;R&HuoD#DojTqwzl&zB_{w#C;jGs*}jH z3T=&KGc0+;Vs}&efIp$e3@nkNWT6q%!Z~o2v-Tf@)!SF!Sfw{k2gQM>tDnm{r-UW| D(=YR* literal 0 HcmV?d00001 diff --git a/game/assets/textures/kenney_prototype/PNG/Green/texture_07.png.import b/game/assets/textures/kenney_prototype/PNG/Green/texture_07.png.import new file mode 100644 index 0000000..5bf66e3 --- /dev/null +++ b/game/assets/textures/kenney_prototype/PNG/Green/texture_07.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://tnna4xkff51h" +path="res://.godot/imported/texture_07.png-d54a79d279a55bef5e5d0957c53a2032.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/textures/kenney_prototype/PNG/Green/texture_07.png" +dest_files=["res://.godot/imported/texture_07.png-d54a79d279a55bef5e5d0957c53a2032.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/game/assets/textures/kenney_prototype/PNG/Green/texture_08.png b/game/assets/textures/kenney_prototype/PNG/Green/texture_08.png new file mode 100644 index 0000000000000000000000000000000000000000..386293dfae46440d9a43594b94dec326d5f01b89 GIT binary patch literal 2743 zcmeAS@N?(olHy`uVBq!ia0y~yU;#2&7+9ErRIjnw1`sdZ(btiIVPik{pF~z5pFhAS z#MSLwyT^k`|NsA&IFu!Qv;0rcG9Ly8u3%3W$B>F!Z?8G>9&zAdaSS$ST`a)$u>YmQ z55eeQHG@~7w%h9Tew`9t!d#K|o$vk6vi;h-<$-370#ZXDLAv2KUK z++$~GxIKTy%ewF~`_b?rBLohZF>GgE_WSD1zhr10)dC5DYKA*}Gv1Y_eg`!JMgdtN x@P@I#I$>A*+`If_X&>pDHt;rd+c6w^&mXWhQtz0Tm>noUJYD@<);T3K0RZ&XVvYa+ literal 0 HcmV?d00001 diff --git a/game/assets/textures/kenney_prototype/PNG/Green/texture_08.png.import b/game/assets/textures/kenney_prototype/PNG/Green/texture_08.png.import new file mode 100644 index 0000000..cffee45 --- /dev/null +++ b/game/assets/textures/kenney_prototype/PNG/Green/texture_08.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dsl3y63xqi1ck" +path="res://.godot/imported/texture_08.png-237c756eafffd5cc50b0172949f9e834.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/textures/kenney_prototype/PNG/Green/texture_08.png" +dest_files=["res://.godot/imported/texture_08.png-237c756eafffd5cc50b0172949f9e834.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/game/assets/textures/kenney_prototype/PNG/Green/texture_09.png b/game/assets/textures/kenney_prototype/PNG/Green/texture_09.png new file mode 100644 index 0000000000000000000000000000000000000000..48234f6d2239880b848d87b2b9fa8ce47ab04ecb GIT binary patch literal 637 zcmeAS@N?(olHy`uVBq!ia0y~yU;#2&7#Nv>lE)e-c@Ne6|3e z5LbyqS<*MlnO&UsGB7YHdAc};RNQ)dVIwaC0|%4i_xLFH1&cnt@YJ&x-j?{*9;j&m vfrGq);Q(3>w7S7*VC`oR0!8P*fj#Up$N%$vvOU7O2;>M)S3j3^P6(M?Ihb3?`VW{9ke5nUTEJUc}CX1T~)y>@UV zlc7MvL)%-8vNxJ}J7hb|`Gxj$x9siGiL*WNX;-Z+hqKVL-`*!`JkwU4)IK@;+5RhQ zx0k;X1KKtU1~vpFcn^G^D1G4dESUpQ#mo_)lrmy~GLyyC7w2M`EvCHat7YbxUq5#@ zn}FT_qSw*~%w!Ji%VyYJz#whiAUk3L1nAL*iwrgIb~4)NpJd#!&a~kg<4E%SVD#%B zmIZ3-Rq{{OG2GNYFy$}jnSZQIgVCKM%S{I|7~-zqVc6IIgkjnw=>t(CDVs15PJ53I)iGZY32W*mtqphypI-uoapK5=d#Wzp$P!8e~hRA literal 0 HcmV?d00001 diff --git a/game/assets/textures/kenney_prototype/PNG/Green/texture_10.png.import b/game/assets/textures/kenney_prototype/PNG/Green/texture_10.png.import new file mode 100644 index 0000000..5a9d456 --- /dev/null +++ b/game/assets/textures/kenney_prototype/PNG/Green/texture_10.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://qpmiu0ubthx4" +path="res://.godot/imported/texture_10.png-d12a87bb602d176bef794b9bd568c8fc.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/textures/kenney_prototype/PNG/Green/texture_10.png" +dest_files=["res://.godot/imported/texture_10.png-d12a87bb602d176bef794b9bd568c8fc.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/game/assets/textures/kenney_prototype/PNG/Green/texture_11.png b/game/assets/textures/kenney_prototype/PNG/Green/texture_11.png new file mode 100644 index 0000000000000000000000000000000000000000..82ad45853f0bcd6f800a4ce02f0b251792360ea8 GIT binary patch literal 9200 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 KeJOjaul@%Sc}&&- literal 0 HcmV?d00001 diff --git a/game/assets/textures/kenney_prototype/PNG/Green/texture_11.png.import b/game/assets/textures/kenney_prototype/PNG/Green/texture_11.png.import new file mode 100644 index 0000000..17ff8ea --- /dev/null +++ b/game/assets/textures/kenney_prototype/PNG/Green/texture_11.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://ce2gscdnwql6i" +path="res://.godot/imported/texture_11.png-1acc0733a994cb0b7388853de591ee94.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/textures/kenney_prototype/PNG/Green/texture_11.png" +dest_files=["res://.godot/imported/texture_11.png-1acc0733a994cb0b7388853de591ee94.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/game/assets/textures/kenney_prototype/PNG/Green/texture_12.png b/game/assets/textures/kenney_prototype/PNG/Green/texture_12.png new file mode 100644 index 0000000000000000000000000000000000000000..a15000d879f381090288e3b883f9be6f8aa14b54 GIT binary patch literal 9056 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 z zwlH@d!e&p;tpq8lohBy3Si!@;6l$l-ZDQ~H^7(j z>o?%#Gx0Z?ZqBGOPN=_I{vE-_{A3|uQZ!6OE{orIwwr21{5@@G*#2~wnQ*U36_Vg!A ztO(%M%k~tRT%l?X?4yR*S#w<&UJ{%m-4Ph-gj?%&+scGhzjBr45jwCRjEA_Yg2wB? z@xjW&1>1xR?hhjGdpda>vJA0%u7*21J&&XFvW1k+=md*YcS3*!vKGjzL)}l@QR>Q0 zb&Trj);B@1l@Rt5FBf^0vP5kEPSI}_rW!fPVyK(D*G$BR5(8i!w=P@|(7{&*ZseR0 z1OfoH!mGgx64;;-fHZY*>^I{2jRYTZnk&oShbvMGUy)EN$UJu)ZI7B_E~enE&({WHdzgxW^6oY5BYzAgVyHTU89y+74-kVs-OY{T+Ldr{B-v z(_0`fA&TlNJAhW5BRed0Nn<)91~gQcr0t5U$sNPtgRUj&QI5g*x2%?)c*&Bg%0!ax zv!16skAty?f$7ep=36mX;#8GGGjc)U{87mg33*PM19{0YT`y9SW6fn+TLI%U(>Sb#c`}|Ngm)4)JToHQ=1(_V z^Dsg{T_B))_J%uYNgdg@$%bV=N^LDy^-QOlT9;2gmh*=s#`|aXp>R{7gpayFt#)FeaO>R=YYBg1)d^ePKaZ=XCIG$iZZXQ`s|_SftXXf zf%j=C1`ZKADbDdZ;z*l% znG)+VokO&&GAAsvPAw3`Ez|KLV@f^oQhLg-!UHW}3&;$7goiB+kyT0#mE$O&=aw z$;g}pGBS>F4vjr@Z4`@?BdFn(_{Jh{WpI5*RS9`t3F4576CH+>^Zm*4qBfk=Pxjcx z#oa;_Fl}HH;s*_hVG}cCv#p4fkwKQ36+7_I)pEWk&kkKZ(5BX=Gn8LYHc-F{&U1&* z^kET22P|-srBS&iu2Iw>1CG(Wu-KfbU??!s|yeX8Mc6ouB zoH7CV;+4Ix#k0<%v6C|~X2H2CJ{|(V;=Sy7^LU}#%RS+e_Mz##8qD0LxWw{>7?)=X zvc0``?XQ&Gse#yvK)C530IGvwU78)4deLG#gqJ5pM&i*1!N(AZyXdD0O1)|K)13sf zt}-9?KQSvGho1#^ulYtJp15QMNlWcEs++=zSLw_KZ z4w2>`P&;Eo)Xfm4I4lG!le0Hv^j(rW1jd<~J!WH8aGpkw-xAoy+h)Ig&UkUWRAA$3 zzO~MBEIfu+0r|+uGXEgBcLlWv%B}n{3JZ4^fXCC>JmEduSs!(T=h7yW zTL3H9CQrUdM@t4+iEs_F3la@IGmZCdjd!B{Qi9G%^d_RG#j&|O??^>A#}cR|LQMm% zTt=;K<(tJfB;fk+wF+!CvgQ(OJGX&Lej{QHAQl4So&Di|3SwW0ZU4M@OdSmKYN-7O z25vn5UqbOezun)7=iEj94``9Q>f|}!z99dv0-tM)Z`w^DG@F6M4n6=ZLBf5AabpE> z#`)MXo3e%AvY~&!h9d7QQu|&hUaN%@8FHJ=Sv|nt`SYU~s=|0=!|!MT{SgR5qF!^< ze`oG5(RYl%Y|{oy&Fx{iyrq49O|1+W`+Z>cG7~9t!2<2W@!ZhAg|HhH^&RW?*Vg~P zAdvfxcXo}*%q;%IjAg~h(7b~P#~IdYO8JkE1_sjqQ$i3*md9K8ALW0&|AoMx7Xi!h zb$_|(Kd*Vd{m$SoAo7t}t7YtOA3^}c@>z7sa1nz~n0XL-P(T^rzBdwQ2bMxD!q?6cFWO+yOy8#*3*Q XVx!O5Ouv7WYx47_b+xj8v3&S9S!I-b literal 0 HcmV?d00001 diff --git a/game/assets/textures/kenney_prototype/PNG/Green/texture_13.png.import b/game/assets/textures/kenney_prototype/PNG/Green/texture_13.png.import new file mode 100644 index 0000000..fb5e973 --- /dev/null +++ b/game/assets/textures/kenney_prototype/PNG/Green/texture_13.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dao8x3dcubt4t" +path="res://.godot/imported/texture_13.png-9c579c2792017ac2572adb06ed4be9d9.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/textures/kenney_prototype/PNG/Green/texture_13.png" +dest_files=["res://.godot/imported/texture_13.png-9c579c2792017ac2572adb06ed4be9d9.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/game/assets/textures/kenney_prototype/PNG/Light/texture_01.png b/game/assets/textures/kenney_prototype/PNG/Light/texture_01.png new file mode 100644 index 0000000000000000000000000000000000000000..60b632b74fbbb17641a174e7b814a59e8dd52eae GIT binary patch literal 1338 zcmeAS@N?(olHy`uVBq!ia0y~yU;#2&7?_xW6jSkG0T3_U(btiIVPik{pF~z5pEJNG z#P#{hSJ!XdxqR*BLscGopqe|LE{-7;x87bpDA=IDmD@UxZ{Plk r4XO~+VsQCbP0l+XkK{aH{i literal 0 HcmV?d00001 diff --git a/game/assets/textures/kenney_prototype/PNG/Light/texture_01.png.import b/game/assets/textures/kenney_prototype/PNG/Light/texture_01.png.import new file mode 100644 index 0000000..5113ab1 --- /dev/null +++ b/game/assets/textures/kenney_prototype/PNG/Light/texture_01.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dolg1kgbvbc0i" +path="res://.godot/imported/texture_01.png-e7546efb61390ffcb487b954608b513f.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/textures/kenney_prototype/PNG/Light/texture_01.png" +dest_files=["res://.godot/imported/texture_01.png-e7546efb61390ffcb487b954608b513f.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/game/assets/textures/kenney_prototype/PNG/Light/texture_02.png b/game/assets/textures/kenney_prototype/PNG/Light/texture_02.png new file mode 100644 index 0000000000000000000000000000000000000000..19aad62c22cb0d88d941e6ef7d3d42f987daac63 GIT binary patch literal 2727 zcmeAS@N?(olHy`uVBq!ia0y~yU;#2&7+9ErRIjnw1`sdZ(btiIVPik{pF~z5pFhAS z#P#*tcQ0SR`Tzg_^;>r?U%OfUDYJxufy>#`#WAGf*4yijye$C&E(hJ1#5Nds9N4es zQXqNh>%0F3v%S(!E`9Y#J%jy2&Fg>Pe}8_lPabIGC?GWi5~Lee>b=}|pDBV=oulfZ zA#j5^VU_o;_uCo7MuUXR5ctM0l&?4;6XtKV;f^YDZ`ZS YOkb>Y{%3I9hy)qo>FVdQ&MBb@0H8!=asU7T literal 0 HcmV?d00001 diff --git a/game/assets/textures/kenney_prototype/PNG/Light/texture_02.png.import b/game/assets/textures/kenney_prototype/PNG/Light/texture_02.png.import new file mode 100644 index 0000000..7fc1c49 --- /dev/null +++ b/game/assets/textures/kenney_prototype/PNG/Light/texture_02.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dh358ryyyh5te" +path="res://.godot/imported/texture_02.png-0a03687d762dd0b17d41845950fd082e.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/textures/kenney_prototype/PNG/Light/texture_02.png" +dest_files=["res://.godot/imported/texture_02.png-0a03687d762dd0b17d41845950fd082e.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/game/assets/textures/kenney_prototype/PNG/Light/texture_03.png b/game/assets/textures/kenney_prototype/PNG/Light/texture_03.png new file mode 100644 index 0000000000000000000000000000000000000000..a8a6c06f5e4fdd806758f0e7b4806a0aac52d6f6 GIT binary patch literal 13212 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 T3x8gNUVh>A=YRZ5`Un3HC26E1 literal 0 HcmV?d00001 diff --git a/game/assets/textures/kenney_prototype/PNG/Light/texture_03.png.import b/game/assets/textures/kenney_prototype/PNG/Light/texture_03.png.import new file mode 100644 index 0000000..db46a3c --- /dev/null +++ b/game/assets/textures/kenney_prototype/PNG/Light/texture_03.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cnph3c4ag2euh" +path="res://.godot/imported/texture_03.png-d0f5a60e42bd37456d3c346266206ccd.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/textures/kenney_prototype/PNG/Light/texture_03.png" +dest_files=["res://.godot/imported/texture_03.png-d0f5a60e42bd37456d3c346266206ccd.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/game/assets/textures/kenney_prototype/PNG/Light/texture_04.png b/game/assets/textures/kenney_prototype/PNG/Light/texture_04.png new file mode 100644 index 0000000000000000000000000000000000000000..b8270e147705d53c36a49888d8d84cccb26b904d GIT binary patch literal 15848 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 E0I!MoH~;_u literal 0 HcmV?d00001 diff --git a/game/assets/textures/kenney_prototype/PNG/Light/texture_05.png.import b/game/assets/textures/kenney_prototype/PNG/Light/texture_05.png.import new file mode 100644 index 0000000..2b7e28b --- /dev/null +++ b/game/assets/textures/kenney_prototype/PNG/Light/texture_05.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://kx7f2kenlsaa" +path="res://.godot/imported/texture_05.png-25f8455e8ed56fc6c1ad5b4a6e15befd.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/textures/kenney_prototype/PNG/Light/texture_05.png" +dest_files=["res://.godot/imported/texture_05.png-25f8455e8ed56fc6c1ad5b4a6e15befd.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/game/assets/textures/kenney_prototype/PNG/Light/texture_06.png b/game/assets/textures/kenney_prototype/PNG/Light/texture_06.png new file mode 100644 index 0000000000000000000000000000000000000000..195ad7777812a29068ba49e5b29f225081e0461a GIT binary patch literal 2743 zcmeAS@N?(olHy`uVBq!ia0y~yU;#2&7+9ErRIjnw1`sdZ(btiIVPik{pF~z5pFhAS z#P!sfbGPq3`2YX^C+_ zeeSU{G~Av)<7HiVnf++^kP!k0%ow&aFZ+G<=3g>2k7|L0KsCc1z8UYzQ@?|n0i%Gd x5O~8_V4bile(qgv_Q!7>#TAfB#%F6*2UngG%-W^Mog literal 0 HcmV?d00001 diff --git a/game/assets/textures/kenney_prototype/PNG/Light/texture_06.png.import b/game/assets/textures/kenney_prototype/PNG/Light/texture_06.png.import new file mode 100644 index 0000000..bc1a6d5 --- /dev/null +++ b/game/assets/textures/kenney_prototype/PNG/Light/texture_06.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cmrwqkfrgvl4x" +path="res://.godot/imported/texture_06.png-782c4b10026cbcd42040942dbeca2bb1.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/textures/kenney_prototype/PNG/Light/texture_06.png" +dest_files=["res://.godot/imported/texture_06.png-782c4b10026cbcd42040942dbeca2bb1.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/game/assets/textures/kenney_prototype/PNG/Light/texture_07.png b/game/assets/textures/kenney_prototype/PNG/Light/texture_07.png new file mode 100644 index 0000000000000000000000000000000000000000..fbf92e0af8b6e58e0056b75e309407e8e9f1cfe3 GIT binary patch literal 637 zcmeAS@N?(olHy`uVBq!ia0y~yU;#2&7#Nv>lE)e-c@Ne6|3e z5ZAp24qd)>bK-$7n;00FlssJ=Ln>~)y|9s&fq{d`@q2uf`+`NEUU=%+3vWw&YY)^k wfWSds!EgYr2U^|WG_dwF2!Wz=;J_YsndATYKG_~&T?BH3r>mdKI;Vst0N*Srm;e9( literal 0 HcmV?d00001 diff --git a/game/assets/textures/kenney_prototype/PNG/Light/texture_07.png.import b/game/assets/textures/kenney_prototype/PNG/Light/texture_07.png.import new file mode 100644 index 0000000..6d55bbe --- /dev/null +++ b/game/assets/textures/kenney_prototype/PNG/Light/texture_07.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://boyc8ex5h27n8" +path="res://.godot/imported/texture_07.png-7570284e3001f1960a1043e76fd88def.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/textures/kenney_prototype/PNG/Light/texture_07.png" +dest_files=["res://.godot/imported/texture_07.png-7570284e3001f1960a1043e76fd88def.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/game/assets/textures/kenney_prototype/PNG/Light/texture_08.png b/game/assets/textures/kenney_prototype/PNG/Light/texture_08.png new file mode 100644 index 0000000000000000000000000000000000000000..72e1a07703f86f06142125b0a44e4bd3bac81ef1 GIT binary patch literal 2838 zcmeAS@N?(olHy`uVBq!ia0y~yU;#2&7+9ErRIjnw1`sdZ(btiIVPik{pF~z5UoOBW z#C6r$^|R;BU%O$`%-M5y?B2U{`N|cm*G``~`|`D$dk-Ayt{2|Rz`(WG)5S5Q;?~=1 z2Uju~3N$>lz11jtqnWouw!@rXXis;`-Y%Uu+Y_I5)!K463qAYoeWJ!QZPiKble3@g zzp{3F`71G?ZKGgdLqLM}!1syL2VT#TIS^IM905uxBL*llSzLW_E|%G1%8R~QW{&yw zb9b`|*!?ehEq%aD=D@yehTR1W($)>KBPKwA9&NbDQ1fmlqmBMa#x3hi8?G^qB+m~< zzy4uaptfEm|5P2rP5lE?{&JrA$I3Jq-8r({bRdHv?)n{uef>`urcIJQ5H*sriG<*R zg)Zf9qzzopr04%DNl>h($ literal 0 HcmV?d00001 diff --git a/game/assets/textures/kenney_prototype/PNG/Light/texture_08.png.import b/game/assets/textures/kenney_prototype/PNG/Light/texture_08.png.import new file mode 100644 index 0000000..0f3959f --- /dev/null +++ b/game/assets/textures/kenney_prototype/PNG/Light/texture_08.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bueuw1b7pf8l6" +path="res://.godot/imported/texture_08.png-415ded57289e289f252a178fe471d729.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/textures/kenney_prototype/PNG/Light/texture_08.png" +dest_files=["res://.godot/imported/texture_08.png-415ded57289e289f252a178fe471d729.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/game/assets/textures/kenney_prototype/PNG/Light/texture_09.png b/game/assets/textures/kenney_prototype/PNG/Light/texture_09.png new file mode 100644 index 0000000000000000000000000000000000000000..9ada5dd55795de4f7eb3198ce5740b76664798e9 GIT binary patch literal 9102 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 f0*_Pge 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 literal 0 HcmV?d00001 diff --git a/game/assets/textures/kenney_prototype/PNG/Light/texture_10.png.import b/game/assets/textures/kenney_prototype/PNG/Light/texture_10.png.import new file mode 100644 index 0000000..924da29 --- /dev/null +++ b/game/assets/textures/kenney_prototype/PNG/Light/texture_10.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://c740qguwtwydx" +path="res://.godot/imported/texture_10.png-7f63eb22e8ac8d37530dd26472b94469.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/textures/kenney_prototype/PNG/Light/texture_10.png" +dest_files=["res://.godot/imported/texture_10.png-7f63eb22e8ac8d37530dd26472b94469.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/game/assets/textures/kenney_prototype/PNG/Light/texture_11.png b/game/assets/textures/kenney_prototype/PNG/Light/texture_11.png new file mode 100644 index 0000000000000000000000000000000000000000..840ecec81fa3d946b44c62569679aaaa9fd5d08e GIT binary patch literal 9494 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 TiL1TtfXwl9^>bP0l+XkKEwy<% literal 0 HcmV?d00001 diff --git a/game/assets/textures/kenney_prototype/PNG/Light/texture_13.png.import b/game/assets/textures/kenney_prototype/PNG/Light/texture_13.png.import new file mode 100644 index 0000000..d149267 --- /dev/null +++ b/game/assets/textures/kenney_prototype/PNG/Light/texture_13.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://tb4aifsnjgw2" +path="res://.godot/imported/texture_13.png-7f0c183e444e41ae4d0eabb58b6f909a.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/textures/kenney_prototype/PNG/Light/texture_13.png" +dest_files=["res://.godot/imported/texture_13.png-7f0c183e444e41ae4d0eabb58b6f909a.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/game/assets/textures/kenney_prototype/PNG/Orange/texture_01.png b/game/assets/textures/kenney_prototype/PNG/Orange/texture_01.png new file mode 100644 index 0000000000000000000000000000000000000000..4f5bf92e498da9d61e01e7ff05437de16b011466 GIT binary patch literal 9912 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 literal 0 HcmV?d00001 diff --git a/game/assets/textures/kenney_prototype/PNG/Orange/texture_01.png.import b/game/assets/textures/kenney_prototype/PNG/Orange/texture_01.png.import new file mode 100644 index 0000000..4b94bc2 --- /dev/null +++ b/game/assets/textures/kenney_prototype/PNG/Orange/texture_01.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://d0hpwwujblbf6" +path="res://.godot/imported/texture_01.png-fb420d45cb04a154afa72ffe12d81894.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/textures/kenney_prototype/PNG/Orange/texture_01.png" +dest_files=["res://.godot/imported/texture_01.png-fb420d45cb04a154afa72ffe12d81894.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/game/assets/textures/kenney_prototype/PNG/Orange/texture_02.png b/game/assets/textures/kenney_prototype/PNG/Orange/texture_02.png new file mode 100644 index 0000000000000000000000000000000000000000..dec5b59cc01a269635586fa27586d6b40e511fd0 GIT binary patch literal 2774 zcmeAS@N?(olHy`uVBq!ia0y~yU;#2&7+9ErRIjnw1`sdZ(btiIVPik{pF~z5UnsyQ z#P$C|!~bjC|1UQFKV9lS5cDwU@z^CYFmUC2x;TbZ+A`@48 Q-2s{7>FVdQ&MBb@0EF*zl>h($ literal 0 HcmV?d00001 diff --git a/game/assets/textures/kenney_prototype/PNG/Orange/texture_02.png.import b/game/assets/textures/kenney_prototype/PNG/Orange/texture_02.png.import new file mode 100644 index 0000000..aff26e1 --- /dev/null +++ b/game/assets/textures/kenney_prototype/PNG/Orange/texture_02.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cfs5l88ygbrfi" +path="res://.godot/imported/texture_02.png-492da03299e722dcf9c0137443e8d877.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/textures/kenney_prototype/PNG/Orange/texture_02.png" +dest_files=["res://.godot/imported/texture_02.png-492da03299e722dcf9c0137443e8d877.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/game/assets/textures/kenney_prototype/PNG/Orange/texture_03.png b/game/assets/textures/kenney_prototype/PNG/Orange/texture_03.png new file mode 100644 index 0000000000000000000000000000000000000000..666197fd8ca7c0503d4a0cfc85c763bbfe9272ca GIT binary patch literal 1338 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 NFTU}@Pk+f+_kRU@SZ~ zUy6o5kDZY-^HF-zMh_Lx6D#N`8*TUpm6y>Yi|Lt-bnAn3S2nFkrH5Xo@>04{PdCNV z9Rn!*wWT-RK)#<@Fqx2aGHuGFnZ>`{J{tE)>eLU1W{)abaVU08+p`LtZ=UBJ8gfwM6~`I+00}u7Xd3xN=e$Q(@PlXpi1eq^ z$!rt}N4Bf^AhJQN;nIhJ$hN?N4?M$MCt?+IRhe63I8|xI*6pv z$)p#GXpxm_5s3U|D zJt=e}q1;-bi&!5m-w{+>AFY857tlD+|1hvGOc^oAkJbTFBOO-_Xe1s(cy8XL@yNq-q%#|mCg*OPjx zsnzq)FnToO zreYyZ(*Pz$oy_gS$nLjYwXRTeu&q3Vk+gTCk&xN4&IV!do?_Sz5=DLS68>~G6Ym@RYS%p}> z^~uk-WyJ$loi#<=i&*!5$cgji!7A9&nw4mFAXen9(|3Z?VNve(<{2t+TBQgR{BNn> z0@kVEIsFBkG#ibUv9?yAdQrX0y@FIf8us;;mIBluTN(Kpq5S&U8M?yll4AacJ+hImUbPR&J~&1V6qXsq~da4v?)QxaYI z67Ymm<#Fmnj8gD7-3*MeJ7~trn z0x}qJ6mHLPH%3TQMw6w8<0YRsiy%M_hdV|55^bZCWz6&xe%TM z{t`na&aH4CSyhh#PDAK7ec@5WF$)wqLm0OzVcWU1E3&tIp<6;vF%&<0VETjoa7oCO|b6lpYQ`o zHLj0(E~nAd1)hA&4*bpYl4%-{t-WvxL{cP4YKQ+5zYWdgQ=%@35I1_N)Gs@ zM#He$jPdf%Ff3!XI4x8QQ6A-+8sl6D!>UV@x2tc$uwp}#^@T@ZSbC%72~CD!tyK4O zV{lj>7)JCJ7Q(Q`X-<-g=iCK-#U}n?7*>k#Hc3RBKe)y^Qwrd0;KvgO;snXARwHcJ zj#DO+ScN#N$N}$ESmaeL8BxwRq4P46yije1&OZ$%bH%fvE3aWhPhll=^`Pwu@+ZWC zZzj8-xmj~HyP}+U1dU3x46r>0O?um&A#Y%lYh*x66*MVmE{JyG`LZO@(#Q4`H0fe{ zksQM&zmr|f84wAV(-rMp3{4IsT6)-?hbEnE^T|YPa+?fju7V~7&Vm>xE(m|3CDAqy zn&@n=k*nCmOLjRkV48%~E93~i-s@bW?0}hcDb&CPkIKfq!c8tm&P@>21EHU};5V{q z4!xpx`j@~=S_t`y7^>|wF`d76^FyQ-TsWO{O9!op!i+AOpeg7p>set;~9Tf=whYqWinBV_-n{@ zY~+H`WB{YsLsfJ%{s(s zbllNdKIhsU2?#bLva;wX9B{qEybf9^lS&r)EitnkL zOE@p8@#6ruyHHF%V;7S#biTSM=e2bFzq98UzL@syY=?fvabcJoVnQ&l3S5B%bAs?LQJ7FN2z>@y=X2_4-5e&g0EBEd z2f6H>73(>ILN=g`4yNg6G~{Qg^0hZB)^iYr?gG)f!8F~4dS!szj6~ZYMzdOKjOHQ2P7+2TE5s=OA8>e`Q@_$R zvZ1{RLc?sg$k+a?xP2@}?FZsU{e|Poa5>0?AV#xVYZA;xp^W^>gdj%w@52E+SDm2C zVL~r~&;;9A@|U+Lb{~t;GK^6uL4Tn^$&fuv2xHV%6KBp8s>op`gfaRMj`-iyqq;^m zw5LI6x@|Z4%U=|?kHzQ_5PCGUQ8z+XGUXdg2xD}uCRXl5MY4?vVT?Y3Ol7j#SC_+t zCV|jg+j_FWYmD8;V$_N;3MJ@9)bj&mHjj)Lqw6N4Jdjq3UKHXXlh5A@xlpaTQ@0j} zMlB%pIwV*d{6?Db6I(?0Q>s9><6UxL^dR9HjA(q2&aJ z*^(A8b|bJixghIHkQ&P8zt47p_PkHejcCF2X*F^{E*Vl*OFVgAeN1})X93qx39R}& zNE_u1%1wRpA%qj4J`;?PivHx?wyNK=Zd{W0lhI@{*#;TZ9}I3Tz|9SYb(RKeaDU?} zgp)D=E&+1coX{|-;`3V=*dl-nG(&zoO!|G+s5=aU{>63UKd96UdM1 z>3qi(8^Yxw935 z6^e^uZ#e!!AtEhCBq%`SjmoRyJw(cfiK}deBE_c8)6Zl`hX8386f%WvMJbhc5os18 zVX>1TDdb~@Gysr>K|wSplxFyXA$13&RZuiJ&$`E&e?TNws$pSOU~A%DLnOKgkP4vq zD)xsHXS|6>)vyibL4hXkP?n3g5J`ZUt89ZJPE)Vy=di7}3AE3JpuCjb6J@3i1zce<*CqX9FY@*(;Fm*|_rjhblCJqUFu1p^!lhnWIkFeEL1>*6l zi(A)Hp6on@;5^g|RZc#^+)KDXTsU6ZUhxhkZ>mr0w=*WliiIxPW)kHqODJ51Loq^h zU%=YB!IUL8Fd;Y#s+#$D^FYB#>X=YEl+I;zAla{epigB&kU$C#YNaH~UzS+Njs`o7 z{i9B=M>j_2cn;*1{n4kXA;Lg0+TXHp$yv zg#c&q)EPZ&23Udd_n=#6ZqA4=WNXL@orQu{z1&<7U&zt{3EISltU7Z`ReWIyj!c3! z$stKEx47a9m*5i~+6;o{=GKe^4?BT*Xfqa`%dG_oo~77Efi}}Zyw2QKmEd8=sse3Z zfah|XE5XBFzX1CU*e=oHncP%o1Si{l+a`{DY#%HC8ttsUtO}a?q~>pLmF5gYtHF%X zRG_y^A;(!EbjP{P=((lSg4v@f4J*<$K9lB=O+iOFuLVEYN)@U>o<)z){+6pc?H>Fv z1V5({2k*0Qp^;3Eo*9R!)^X)uA*zOI&@`e?nr}k3Oz+rU)ADKjKsbRF+GP`(CW2)D zlm?8t2H{1mT!^+{xmXkE>X#w|_o)Tfs9Iodfu9NjV1zUE4Z<^8wO#MTq!}G1K^?bG zb+u7#QaZDgR`Nrr%dng#nfwDDcg#Uor zIogSpEm}>=%Ap5USF1!9r894772lWM?paz7iF%n5vk;pd4uBW6YBZ>|3hGkJ2~d*+ z-b5o?O3%P_sdDJogSc8W1}0995AXjK@yl@ z@0|J_Hu`Vx>F$2#YHSpYj91H`(NMKYiAzEUF83-}Q>b)8&`zblgpK})3{^9rQL37G zEP3E-kfqy?+25g16WiC&A7+(CV+8$yCE!Zv5A?uY*V&4k)rZ7^azQmrUTfd zpGptHzM3h3^#av~@IyGo-vkE`7)|k_3tn7xiIA^-3H$S2^&74bE3=Q?*0cFg+k(+F zj@ST3x*M4r8Uib?#MfkyUk8|3k~ByF!x4<8wWJusb1x8RtA@f1jHWK63SbnE_KA82 zU=l*xbWXG_^R6l%NU+6#(UeE#V10KfoZ_oNm{x1NSO+lH5`out0n8ifS6m^+YNOj) zr}O}r4boV07heha1`jJL)huLPJZNlF$L1I!TZeKH#(b2kuZu_DY#r7LMg7_auc zdK)7XJgl=|WJ<2W+1eLij6y!i!N@d)Q@jC$X?Dkp*8s*{BAB$j05e=Y%8kIt>~LFa z6^zU~QZ`wJFoDS2U^c>d0tWf-08=DMv4Ry~;!aJ|rdYZYP-JVFZra1o?! z@#t=p3Tt23DxljkLYhWSL-*1tYzHLAWX<}zt2Fk2^OB)x3UWa+R-nT8fQhGSiuZ1Ed!K>ru#W-$tz3@%{Z;Hv=!H{1z(5vwBEbTP>IVa z#U#I_p2lDWZ|g5$u)Z={MnjTbPoGf}xmOVCx?x{0X*n?UhbrJ9locDgk(b-%JJb|&|(%>qLlIL)A zCA#t1Y4StrQy8QmoLCs7qluR8P{q{KF6#T-7l`wQVP7XH4{)NPOqz)}l74onk_k9O zT1;*tPAfO`xElgww<}rXImGdk=bZtFPp-qADsDxb6(r7cxVzVDrt9<-pYpIH@xz1}WFD@MP5KISt$h3tVJ4Y} zyJ3aC0$nQ~KM2cUT$>lToU??z; zvY@RzUT%P4m1m1%?^oSrG0tKbmZ6XQk-8d&6$&oU7aoLR^)*@^)9PVZZ>z_-F*vNx z4I};r#eAFah<1adBF<0xigF$-cRm?C1H|!gIdvvDL+tDMi6j?s?va;U%VCk{od92P}0@dtZ;S85^GB*~QoIu|Mnz&Ns@#=PH(og-GtVEUXxt!YEc55Y0ZbFqbd8oPv znsif7l9j0P3zu^OFjWWmN-{18SDKuv9)TuNX!oE>3zu^|7p93n1db4F&$LlrvDyw9 zag~3w-czy~Jg3Y03egUgTY>+8-m`c$e^C3*AiG>JlN#Ww7xA*>X!S|qhRQ=q;rAV& zan2@6;q(twStAlzY5P;)>iJLYsiGp#)zWvEbG8dE(R=O&>;suEZo)B_PtKCAr$LzS>`U7|H&w%|{bRkw6JRBE% z0^gqmBwE~8d<*l@SeQ)9(Ps=sTzT9EL^GieyUv~@);aitUCpeHXtyI<^`5^%83A1j zD=Oax+`-^ajTf|wrJ{%Zw0%yEBL=&0cVPNG96}w$Hv>FR`J&4-F}4%44?c%pf5s^s z3{^RF^O;<`m3o1s3YvGdc!9~`Mo`W_L^AAxtzWv2$-xTAV9ss8l-juyOX*(%xnx)= zh4&&Eb-ET-=*w@Op=T1y?fb%uxa2E~a^4A;q@*MkJ3Tz}`=&-YTf&a~*mW#W8lb!v z((4M3(-+M$_D}>xsH4$s5{GDUoQ7{u$%gkZ8n&L{q3WoESYO^Z%&&3>uS?yWtaNDK z&aw@aYv_xjp9z71>NpSPd~dBYcZ>;*0-*`8b$%IK9CeV*p*mO-s`?rCMQe2zC#x?a zKpE%Bj;Z`mdP;0%LNNELWp_{UMePaB#)O8z9vlUG^OvE;(Fd8a+5Sag9`}W-x`&gM zF75k$c68-xX&yM~I5Y@e^$GZT(L;;jCNd$+NaEpa*&57?0{0(=Rt7}l)IQuRt=2B! zZ^N9s4ZBL5H#@5G18KTgi$Yltqw14ZllZ*$7L=Wd zR(BT*i_vY2kuN2taDtX;(iG>&_O31L1v6f%{GKT1#ipSu8SgHxj_SiDL> z^pM(v>(y%NVqx*B!+7~qqAZ()9Fdj2CfKQ~8~Hxs)7m7i6-5R3?jSu3dC}U?)aZET zS+sx8+sXBEnY7$}7jXsLPq#*p7!~rUQN{Q+%3$of{pHc}8pUaU=`^z>9*4!V9I~|v zPoA27`T~x_gkP#0kO8LHHk(dCxdM($dk$#OSx#aqrAH3PD}9n)5Xhe3MqAneic2;C zJ3tMlkjc^yhKJr}aOYu^eIPB}*P0c6eAiWkyPuejB5PI1rhZ~C<}kn=_5`Bk4;9aX zPs40w=K@>``CCthUEXCCp-QEGe1&*KJ2ZDlFO6@;w~IxKJ2Z^CMY7FQitomX3p77 zh{XF)Xn0xz$(78LZ9*h0MpC3p%6*Gf0-ej1*G#( zh9)ObBdY-bkM&^Fw_NW7yyvAT$N)^-kA~ zX-;-b@DP(xUfz(tm0u>7vf(lpfOZoLH7EBO69NyO?@1Ssme5W^F*~aRAhZxHgmh1t z(Zg1t8{Wy!LAPFZmYbYx1}MM?*IlB;6S=*d8d588Ci%Tej9BaF<@^($pi2ZUMwECm zH`&Q7NdbZ2rj2;Yk?g$A+JFw+y@?i2=k|7n*%Q!N;uB)vaPRG8ZmtA6;H^Z7^|>id zKemxT=Kx&$5gQyS&Q^RvVZW)mCZPW`Mh@d-qu|Lq&e9%aFuz2siIel0PqYPnB5Vcb zQC!fQ`LO{pT@Fpl*TYs_%v9kSv-bD^I_wJoBs2wX0OI^E3r%0ugm_D{!aOmqc5npO)jAJHSKo9{FQOASeJ zG{Q%~)p)n5u3R??l3x02_`Q%~>oyz4CTI^O;ipzfLbq!RG#f;ls`Y-TKxkd~)evt> zn~h--(mSDBARM!QO#S*vc**J9)HVCDSyOmgNSfFs2O_T61`d1`n@RS~G(36IHTZ`4 zTiu!^*z8<*P{=y5#~gfl!pKgGpqX;a{sFza9@Nrk?X1#~*zC7(Y{-4AcaC)h86>y!!KXv#|9sW~?|J30>b@)#m{!@ql^nc|)b$Cu4o>PbC)Zsb(PxYL9w~l9-oK4ZH zw+M`=dmXo+I&MLA+=2pUu;Ug~$1SLiTTmUhpgL|r{l9Yy>Z2n7Djdw_**~CPxUK5JG|rP W2iNt1|A!Qr_UKbn_Wp-u&3^$4`OmWe literal 0 HcmV?d00001 diff --git a/game/assets/textures/kenney_prototype/PNG/Orange/texture_06.png.import b/game/assets/textures/kenney_prototype/PNG/Orange/texture_06.png.import new file mode 100644 index 0000000..6354792 --- /dev/null +++ b/game/assets/textures/kenney_prototype/PNG/Orange/texture_06.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://diohjhmc5jre6" +path="res://.godot/imported/texture_06.png-a043840f324cef1c1d8332b72657762d.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/textures/kenney_prototype/PNG/Orange/texture_06.png" +dest_files=["res://.godot/imported/texture_06.png-a043840f324cef1c1d8332b72657762d.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/game/assets/textures/kenney_prototype/PNG/Orange/texture_07.png b/game/assets/textures/kenney_prototype/PNG/Orange/texture_07.png new file mode 100644 index 0000000000000000000000000000000000000000..95f27900aba93f43bbf38394db959dd5bfe51f81 GIT binary patch literal 2739 zcmeAS@N?(olHy`uVBq!ia0y~yU;#2&7+9ErRIjnw1`sdZ(btiIVPik{pF~z5Un0OK z#P$D{$p72p|F5wBf1vdLuC)I^FkR|@4@3RxmIej}E;mmX$B>F!Z?7HfJ!Bx_dQs;^ zBin=sW3FO0|Nt5 z&VSG0pyl^q@?OS2EGYVk4Kj8HwD5WG_Or#YI)=6H@5>x0?&DqX^)DmH4EA5aHZu&0Y-NX4zU*Bp6|IPkDI1{<_47T|i=|I*=y zV05sW!K+Z)ZFPFTP6;nzu1NdN_x@+ue(l}zKr=@HsUeUc-Ef=n^50i)>PXc&svZ^s z4Ymw<>^|RjZ~Dy$6B?yS4S{bAJ7f*+u0QvVom8Ep>VY9}gKa^2_~Go|@$Z-!8rXgA zu`@K>olE)e-c@Ne6|3e z5Z9-*4F7u=PBVScVqjoW@^o=u4riffzr9b?c&4p7seN+xv;9}r zZZCf&2DEJy3~UHU@E-U+QTo8^SuzKrikTxoDP_a}WhRTOFV4j>TTFS;SIf*Xzkcp+ zHUYc;MX#j~n8_U2m(8%dfI-^2L3YFh2+*Sq7a3~a?PRpkKgqadooT~0#*yUt!RXgN zEDO}utK^@mW4Nh*V9H<4Gyhnb2BSMimYWV_FvMNI!?3Ua3B$BW(g&hOQZ|tgJh0HE z{EgIsm2Tzlq#b_zIlVTU;o;}?#rGM?9x|B4GT&%pzHyuJ&4@}7J!}suPx3w}_UBtr qx|VSZ--z=3AoT15bq3W+)5`xrFU2I1c^@qRInmSA&t;ucLK6UL2#%8g literal 0 HcmV?d00001 diff --git a/game/assets/textures/kenney_prototype/PNG/Orange/texture_10.png.import b/game/assets/textures/kenney_prototype/PNG/Orange/texture_10.png.import new file mode 100644 index 0000000..dac6730 --- /dev/null +++ b/game/assets/textures/kenney_prototype/PNG/Orange/texture_10.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cbtpv5s1up3ir" +path="res://.godot/imported/texture_10.png-ec0a9a256fbd60f1c174db650022982c.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/textures/kenney_prototype/PNG/Orange/texture_10.png" +dest_files=["res://.godot/imported/texture_10.png-ec0a9a256fbd60f1c174db650022982c.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/game/assets/textures/kenney_prototype/PNG/Orange/texture_11.png b/game/assets/textures/kenney_prototype/PNG/Orange/texture_11.png new file mode 100644 index 0000000000000000000000000000000000000000..dc94567ff8c6302a91459d75cc5f8222841286ff GIT binary patch literal 9194 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 literal 0 HcmV?d00001 diff --git a/game/assets/textures/kenney_prototype/PNG/Orange/texture_11.png.import b/game/assets/textures/kenney_prototype/PNG/Orange/texture_11.png.import new file mode 100644 index 0000000..5e12552 --- /dev/null +++ b/game/assets/textures/kenney_prototype/PNG/Orange/texture_11.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://d04g85b80udnd" +path="res://.godot/imported/texture_11.png-acf1389cfd46786de7f0d1a3454e4d3a.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/textures/kenney_prototype/PNG/Orange/texture_11.png" +dest_files=["res://.godot/imported/texture_11.png-acf1389cfd46786de7f0d1a3454e4d3a.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/game/assets/textures/kenney_prototype/PNG/Orange/texture_12.png b/game/assets/textures/kenney_prototype/PNG/Orange/texture_12.png new file mode 100644 index 0000000000000000000000000000000000000000..b730544dff562baecabd1518f7a46ffc8cfe46cc GIT binary patch literal 9054 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 I7l%9l0=zgXu>b%7 literal 0 HcmV?d00001 diff --git a/game/assets/textures/kenney_prototype/PNG/Orange/texture_12.png.import b/game/assets/textures/kenney_prototype/PNG/Orange/texture_12.png.import new file mode 100644 index 0000000..6806f26 --- /dev/null +++ b/game/assets/textures/kenney_prototype/PNG/Orange/texture_12.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bil6g5fcdofha" +path="res://.godot/imported/texture_12.png-dbd2ccd5022482214c76aa18350c92b8.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/textures/kenney_prototype/PNG/Orange/texture_12.png" +dest_files=["res://.godot/imported/texture_12.png-dbd2ccd5022482214c76aa18350c92b8.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/game/assets/textures/kenney_prototype/PNG/Orange/texture_13.png b/game/assets/textures/kenney_prototype/PNG/Orange/texture_13.png new file mode 100644 index 0000000000000000000000000000000000000000..01f4aa8af14df0cb80ca4548fdc373080ead65cb GIT binary patch literal 9581 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 literal 0 HcmV?d00001 diff --git a/game/assets/textures/kenney_prototype/PNG/Orange/texture_13.png.import b/game/assets/textures/kenney_prototype/PNG/Orange/texture_13.png.import new file mode 100644 index 0000000..f93a327 --- /dev/null +++ b/game/assets/textures/kenney_prototype/PNG/Orange/texture_13.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dphpr66n7cv13" +path="res://.godot/imported/texture_13.png-fa85c6a0c33ba49033d65d403af78b03.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/textures/kenney_prototype/PNG/Orange/texture_13.png" +dest_files=["res://.godot/imported/texture_13.png-fa85c6a0c33ba49033d65d403af78b03.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/game/assets/textures/kenney_prototype/PNG/Purple/texture_01.png b/game/assets/textures/kenney_prototype/PNG/Purple/texture_01.png new file mode 100644 index 0000000000000000000000000000000000000000..d501875c6c24e1fe0a85061880855917aa03b8d3 GIT binary patch literal 9797 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 literal 0 HcmV?d00001 diff --git a/game/assets/textures/kenney_prototype/PNG/Purple/texture_01.png.import b/game/assets/textures/kenney_prototype/PNG/Purple/texture_01.png.import new file mode 100644 index 0000000..a6229a7 --- /dev/null +++ b/game/assets/textures/kenney_prototype/PNG/Purple/texture_01.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dolx5sa0cxuci" +path="res://.godot/imported/texture_01.png-2533652906fd6c188a64ea25d0158276.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/textures/kenney_prototype/PNG/Purple/texture_01.png" +dest_files=["res://.godot/imported/texture_01.png-2533652906fd6c188a64ea25d0158276.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/game/assets/textures/kenney_prototype/PNG/Purple/texture_02.png b/game/assets/textures/kenney_prototype/PNG/Purple/texture_02.png new file mode 100644 index 0000000000000000000000000000000000000000..48a51c1700f525cb537c3a78fa1fa86054cc41ed GIT binary patch literal 2774 zcmeAS@N?(olHy`uVBq!ia0y~yU;#2&7+9ErRIjnw1`sdZ(btiIVPik{pF~z5UnsyQ z#C3zuuN?`$H~9TtZt?5?|NnE9e)-=%vWbC#E8o+_F{I+w+iM4T4=eDnUhv2fFmrgx za)H%pm*ejLTC#`OC;a&*8yR1<$x_a9?&HthPi1TVM_K=$z1JRS_9!4D1aepszD0O_ zsExI*PkEouY{5u|8KYW&A+UkFVfWFZZCg3d?cel$JL8M4b4Iu}Go}w7uNWrCHV8l9AK^hkzV~M{%&?s%R1<&woczt-w;BA%H)(|H ze8co0Z{wWY+@{a#-~7#GP#@vJLB99P7!9g*RDbMSH`ji&njt$F8+sXRCRx=R_#P6O SxZ3Lu$Q(~sKbLh*2~7YsLv|ei literal 0 HcmV?d00001 diff --git a/game/assets/textures/kenney_prototype/PNG/Purple/texture_02.png.import b/game/assets/textures/kenney_prototype/PNG/Purple/texture_02.png.import new file mode 100644 index 0000000..f0d3230 --- /dev/null +++ b/game/assets/textures/kenney_prototype/PNG/Purple/texture_02.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://c5ucfhxus7qhv" +path="res://.godot/imported/texture_02.png-c747129582448a69ce05670e2bbddea2.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/textures/kenney_prototype/PNG/Purple/texture_02.png" +dest_files=["res://.godot/imported/texture_02.png-c747129582448a69ce05670e2bbddea2.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/game/assets/textures/kenney_prototype/PNG/Purple/texture_03.png b/game/assets/textures/kenney_prototype/PNG/Purple/texture_03.png new file mode 100644 index 0000000000000000000000000000000000000000..5f97f24f48e1193d0352d162bc402bd69f84a1c0 GIT binary patch literal 1338 zcmeAS@N?(olHy`uVBq!ia0y~yU;#2&7?_xW6jSkG0T3_U(btiIVPik{pF~z5pEJNG z#PwABpXC<6<|_SC*LbH5RCCAE#WAGf*4xVm1sfE2TpeF6^XJ)tMhqShz@RW|dfb6Kf0~NFiw_=W0bSzHaAZ;PldhEf`}vH6$zcna z98C20HmsiyN+N>=Gzc+VwBa5st^vD4lwncjOV%@I^)1Tl2UP@qU~$l~a$D!|?b~0m qK^0#`#WAGf*4yijye$C&E(hJ1#5Nds9N4es zQXqNh>%0F3v%S(!E`9Y#J%jy2&Fg>Pe}8_lPabIGC?GWi5~Lee>b=}|pDBV=oulfZ zA#j5^VU_o;_uCo7MuUXR5ctM0l&?4;6XtKV;f^YDZ`ZS YOkb>Y{%3I9hy)qo>FVdQ&MBb@0MQd;yZ`_I literal 0 HcmV?d00001 diff --git a/game/assets/textures/kenney_prototype/PNG/Purple/texture_04.png.import b/game/assets/textures/kenney_prototype/PNG/Purple/texture_04.png.import new file mode 100644 index 0000000..b4efa73 --- /dev/null +++ b/game/assets/textures/kenney_prototype/PNG/Purple/texture_04.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cdeu6y3m43hpj" +path="res://.godot/imported/texture_04.png-0cb6c6fb7215e630ffd369654a0115d0.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/textures/kenney_prototype/PNG/Purple/texture_04.png" +dest_files=["res://.godot/imported/texture_04.png-0cb6c6fb7215e630ffd369654a0115d0.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/game/assets/textures/kenney_prototype/PNG/Purple/texture_05.png b/game/assets/textures/kenney_prototype/PNG/Purple/texture_05.png new file mode 100644 index 0000000000000000000000000000000000000000..52352c8f21212dc9317c8017479a8301bfc85a4c GIT binary patch literal 13212 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 T0{*-Pz5K%K&;Rh3to8p7fhL^k literal 0 HcmV?d00001 diff --git a/game/assets/textures/kenney_prototype/PNG/Purple/texture_05.png.import b/game/assets/textures/kenney_prototype/PNG/Purple/texture_05.png.import new file mode 100644 index 0000000..b4e4a8a --- /dev/null +++ b/game/assets/textures/kenney_prototype/PNG/Purple/texture_05.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://c7ri11frsg7fc" +path="res://.godot/imported/texture_05.png-ef4a017243972413bd35ab4cde773c93.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/textures/kenney_prototype/PNG/Purple/texture_05.png" +dest_files=["res://.godot/imported/texture_05.png-ef4a017243972413bd35ab4cde773c93.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/game/assets/textures/kenney_prototype/PNG/Purple/texture_06.png b/game/assets/textures/kenney_prototype/PNG/Purple/texture_06.png new file mode 100644 index 0000000000000000000000000000000000000000..86deeb3fb3fcf2f7e2227e72182db75327112160 GIT binary patch literal 19065 zcmeHvX?PUXy6&p3Buxg=!3Y5vI>-=^A;AD)Of|wb;#Ly{1-C+@Y>5*)QNS>Su40gY zs1Xqo#>S1uprXNx?w|y!7!$^h2Q(^3b;zUwRu6=(PFL4D-&Y-_-_ zc)!UFAA8OsB$Z5`Hf840pKtAo-P&jT`@>f(SUz;@XTJ~oga0YF z<(`cz#`VaYK|Zb~yZ8OL`HR7s19UIFox|TwyXE9xG=;x&US`yg>j90ueudY=vyRz6 z3DS^1J?J_|dyqd&?snSdcv+|VaG$e`jv!Z~r8XK0pVvfFDqR+oS=$`)EGm14s=`BBudF5XLVNZ@uNknFWa+w@BwXH@FzOkvn6I!kB<@j2h5!^tY7(i9%8)c}=&S_QNI z8K9D{p9U(?bR(IDaq|Zjd7LpeJ<}t`+3Jw3*Ab`tp=Xm` z#;kuDP%5vvBziCLi5$H_)?%E>lr%Trodo6G@Vpy#-4+V@#RNf9F7n+40SDmK?`V~5 zD&66?$4ETzwI2~D(!Y=yrV#KC3FmgE0^>0_3fmV{!81!c%B8qOBCgt9qDZm z$C7uUmFNpE4Bmi%@9@nsO9eot{-`*Ne*wtk>h0tZ2IBWXR&!-nAah1eB9%bKPW9c| z_dup^@EMc)D(U*l}8Vllub3mqGIX_k33S{2U-eEkm zfy_chsgdsnGVh3ENFtK)hHt4?kc>CWEIEKo)lsoG4-*YA*Wj7&=)tFZvdoRYhd z8$d?Z^|{&wjEuU%G!G*)@tXXWI2p)v<7bgqF*2^uL~jw2X;9*Y-++v=oFAa?1~Ox{ zUCaTD%t}Q$A!B6T6tl=WB;yY+R6|I{Q)HI@0b~M4#dtm+$XIlplw)N62xK)VNah%q zL_R|@RPU$#f{{^kO!F`@=4RYYx!WkfAUCy)mCLrU} z)-VS!GV_&67YC8C@8U<37$C!Y!p*@NAhXeLG0!UoGNo~|ckwXC#j$iLS%*u=B3 zk-GMu3h^puvYSP5r-l{)3^Ey1n; ze#3VqYTkN{-RL8K+_ zd~LGh63}{C`+@ltX`Qyas{4owfz~L8pL~V18rj+J%Hx1l4{;^gj;z|4{ih3HBelOJ z_a~ntDUI}K%(4KdlS((?G;-p}E8Z&@sq00twktrXXq@mLYF`YLCls~kC1A9okMywC z596fnGSy+6<|NMR?o%eQ^C$&Cl3WWF`}J(igfCk z{l^uI(Q0`V`5NimB0U<4Fhr8lOE?R3lp^wqCxj7l7j?D$f^;ScgVeqdAiqBpv*%@` z(@%=ib_1Q?g1gu}jL#g)JjPKEbZ%9n%tyXEo3$7P8; z8HscP%=wE7M8~I0@H>^>vc$FM%id&82Y?;#e0EzpngqKV`K-SL>a32_XQ^9VcM(_vkWpJaY(-ptsrb4bE=RWS#SF;R-exFKkeULX)S} zr}Sj0bi&MWu6FhmT-aoyFkO8K zn)Fh)F)F_CYPNihGXWWpF1J6Ue`VMtIEiT!5(BRZ`1sgX|<#4|;2?+(+2m1!<|0!U z?0}mD&64?IvOAkL&9!NWRtkG??kQ_Oq1DALPfBv&Pa|_G$Lx0dUHzh`*T$4)TfI8tXkmql?Qiea%#6l>s*#;0C}-c}%2Dvu#%mILI_|&scj1eubORE$Iz|ov{FO zqTQzg&RwzVjWCUZ_b?rnrswyNB{w<>gRZ{^UF_FJF-wEtidNI}7$<%jyokTSU#fMz zF~#(N@yrI#=IZOov&A$xjOm6{WH=VNQM`?eRPFIy4&jUV1A5pN46}u&`2G^bH@E_} zn2MGni!_LCApv~#3S@)M9r8p{ua%jq)1kwT?W~o|^w{GIk0Q_)0Q6IEC7XA`-d{52 z-U?XM6|Jy!cIV$A^#)K+0CLKiWQq2qX_5hC2bPSZhRpQU#}-y2&_4jEyBap-owE;> z6oV1$!Da5Ec-t8Mb5dmh;ZeOt9!A=TrslWSCG-3`uIX4cq0MmNp+>E?zo&P zwHiP$#mXAsY)R%fk}?A*34luE0c4@}sA-Y`v=SKgca)IPzN*+lBStL%v_-we)}57y zNIC*N12HPQo@KFR@}Chu0u?}v>>K3?2mk zxxaMB0D>5mHD-0SrSPTXk^uxUvX{#Dla<;W({KX_a(sS@;{;jk3&ds^F(zsj3i+06occ1w5^F>qJK$ddwOe` z=YPZnV}+YTI%a6ej*ZrnJq_+GblDb!tnWmDZ*TbkoZuaKpN+h&V*2Dp9!2o3irk7t z=q`R&IscBa>aW2X>H%qEMq^dGZQUP8PKIMjUIVG<8`=Wvnajpr8G+P{BfvOzAAA?J{{ zgOEgh*@)z_klghGi!es?)@N23>^;AN7LyMPnO(6ngvxl6m*B0?yWmyb6#PCj2Rm66R-oar{(Z&%vcY^{hy!Ta4Sz z4cNtc!^J_`Aip4N#Yos850N*)D6gC#!v&UEgvyf6#Wmmx} z)|2lIN+W^NP`JqS3H}nZ&!F@qP?`gm9rqa}%hrsPDv=Uih-NuznBNUbcn!0|rAhUz zNX%P;l<=z78!lGTHhGD#9Vzkna<;+c>za0yooP_|3@H5o7qr6GqJHjnjFKH@ZlDD& zahw<+Wk`uG0qjNkMiS*YY$-Ib?ZCUJmG3KbaZqNYF_{tRj+V|Q9k*skH?X^o8|G)^ zq$elA<3n&Kyr^W4*u|E_*OE%(cQ3)+m8HwbKh^m$OO3P11@mR7n#(4gwvLv9INpvM zZ@jG!f0Ok2J5Y4n!hHoun>W)5Xw*BexG#FI!W>) zP=_3lV4K9>CbTqB)t)BYq%_b~m86&O(!R+65Ymz`vU`wBo$&<~S5HI}_Du~4_UP>+bQS~@6&2c z;bR{{)d&Qi3-pGQX$Gw*WH&tlxiD1%nSQEINku8iTS?ACT1f9Wp4Y3a(Ocm_chZE1 zFtb$@pg~`NW@l;JB2tabypF%=rFQdHx>J+6F4HiVbt?JIRI??arsUr&?8jzpjwkfW z(x}alqgQcpk6^MYE3Hjb&&vx!${09Ic0x1W?|4|>Q5s!Fi?x85Fb&h*DkZ;33_lNO zHPmxOcpIAq91rM+D`Pg(SG7_x@e#~x14?V7NM8rE)AaT-;)O)k(3~uG%SgyWom|pD zyeV@>o$tVO@;NtBck(JjWx5nPqekXpY4%;imtrFk{tQ<#=LYJ@WaeXpj)h>V!i3$R zmU4HG#(RkM2>dw}8kNwd8LI|hqlOUt*;pQ~>>iT}vC+T9r`s!->v-co6M9K41*GY! zOYAxDRcPcq0@~C-Kw3jjWwC!jE#XpNv&RX?<_wS6{_=r6IA-0EsKeEkkI~EIu08QO zXRmgyrjTDc1=?1&W*sU{vy^-{57!9UNv~g7H30iN7l6G1)gu?**5+m~E}be=rwY}n zLUpQ8ohlS;teq-UrwZlhRG~UmD7RHQl; zsZK=-l&AmC6e%&3P@g6M0-SQ1^Y)pJejWV=daPbG8EnvZl^pA zP8AX9hcWsQb|hMGnHYWp1us)o2b$dI8#csshP=F+AjehSJgtsn_ABJi47i>FgO0`<-d)u`?5D2hi*%>lD3PP~qx9RmWJp1m?;}5JuNxnYtpd*~@_pJi}{^ zN?rbcN>M||F%)my;hCBX6vk;<39}vry&NU~Iv0^(6K%gj=Ug$@jXn+va928=+>64L zH?#~C+f=9}yG%)kAjG-Xa!>GRq&m*uBOF3`>5ij^4u%ds5ll^M|1Sxui|sPP@|>AQ zgyqjj6gEjwD!?%%XlZV~mr#xa`aPVWrNcP@E~i9WE&PZNI!yX3pnEHrZc6$RRVxt$ z$#bA<|Dnxdx}bEIq7=9c^U`?w0@0A~_o2goO6G||2;*4{T6siP@6LGU!jI||r9*lb z2a}5s81Z`e^FQVJXsHNdS6?k=@(~FirWMYjPXk$h%KW{E3kcf-`cW-X3V4NeV`PTO z@>VfYE?7b|tlr-W9rksU6f6SNFxo2}{EUvWLs!OwQf8Z?oarb{3?h#qnTGI)Kg$=< zQa+HWsul-ylsLe%fYavVKvq*n8KfsE1v2s--JwNFCC{+#13;#?EWay8$|;M;O^6JC zBXro?QF5^eXpksy@R@p~EYp`cfRVYSD5qq2xAF!tjhsd@jp5JLEAaYzdyAr_H-Jo_ zT1@71pa5ZoYEd~x=8Hhq^^RImFM@UrIiP22bFfIFu3+b3WG2e;Ix!szDY1MJxrvcc zLWiLO1(gjfVf_ST6bGNIM+#Uha{wa~R+M8h7HwAX1IdFxhIfZYs39cdu|!J?fJ|w% z$Wp8buY|f=gdCg z`=A+cUjakYJXCQlH0{Uh+Ftn8e}JJ0YKn*S8hY1)g?a-_zO!Ix>WP|m3{5yVx}#{g znY<0tnujXh>}}wh@`)qC(6kOlDxN8Qek8c2phmbA3{3-I9CAz9s2`vf38ow{GzqJK zWx?$m<>$aP1+JWCsCH5a2$t}k1lJVM0z=cD6+mmp%7K^u39hO4=pZmO)g1;}x3WKY z?NM+|)zY`X(DWE{!WeaGU0#@K@+OrH;J!6&7GX=2% zPg5Pn>Vjn+TBd3#dYWEDPIt@)&@zQ3=rZyZQYv9*qh-n`qNiy)GOA(rgJlW`p{HpC z5^5$rz%m7Vz|$nG13tL^L5#rDl!r0; zC2<~FrfMmAn)V?bhxq_nrm#j|Pc9>!8g@2XrhFWFnm$E3t;~L~Op%}yJxybfP8;a~ zmMQRyfTu}#3+aH#2P{)y@&Qki)P{7xnhVavC2V58&E)AShb0+*TdXRYY-K~GaY42!!- z27_e^h6SD`VKWTNT13z?1;YYQljMbAS-|MiVGOB>abtBNr=NtDDR78^r>PJPic>A~ z&@xpEg_ZA^aY*M&a|T+bn&2SwkV#0#&6cBO%EzUktp%dY-)7E(WeVuL@9(^Wd8O1DED*FRgG18R`WtvXlgoy$KhJG9Gb(Az|OhFScH3^m2WP*T>DX@p3M+k%d6<*Z?L;5G? z3n;A?`Jv>A$camZsQP2A-=h%t$l>OF0S~lq++ZaPX)MxV9RrR z{JGBPlSUD?7T^|ZA2Q=~t&wFuG~gm`zrT~mvZ?lvt;v9c6_Q(P?I|2oxN&zUEk(E! zFo;Yv7v2u#z8ihgsPgUuxDT}Fm~m9!o6J0Cz(p3|Oft8a{Hnw3YX zXQr(VyRcyB&RUa&GMQgKGS%>{bhsX4r5g(8=%3nzu`|O42;Rsp5?HFlyON9=eHccT z41aO2re6yJ_Mr5G9=3rhHA_n|X*gxXB6trkqg&Hwk1aH+%NJoPe-k{y7GB_oN+AUA z*v=Ad(e!K5Y5;*1*ttv2B4f1freXsK&CAPS>zwJW?^0-ZBHjg{U~n>4ZHr06IVGa)Bo_AOng05?!oyhaehh%ds7FkBF8c`S zh5;1W@8fJNe}q&RK(MgwZ^~(8gx1wmYye?K(hJU((cY>qh2J1hA^C!6X{%L66D zm2w4k74YD8u?^sNkP-wcfEd{~$l2s`?H$uiV`%8D7z&5iXn$2)h7qIF0Q9x`Ia_y8 z9xfS{jE(~_(PriklSTsw?b7eaW65N#ujy3-2(9nq;Q(Ij4RpycVzdr`+SCzjU5z|Q zGVB)}M&$%s8t)`03?PirCV3<|qU|!>G=}yh08NJ@ez89gmtn-{L5xxGb5os59wGgX zG3v-1;v~Y0VA;l@VT`uOgUJAmHN9#8VLtmbSg#YjrClJG$Z5`bdvVrx zq*(Jvf{MA52hlAsCuX5tJz6}*op{?=FcHK0R3@VV4dfphU7|J130dD*Z7}!Nc*8r= zk@rPO>oI+b!2v-o*~FW{LqFTwJ3L_l#WkeBsxQE_G1CDa@?Q;dyMWweOhs!7?reJG z2$JhaM)OHR5HhGQjR{)>TFd5BgBmV-)$yg&Vf&BPi+Q;?_ zmlxqi(2*fWN#&SCO*F_Y0&;2awZUwEZ+`M3NKU}Hgyb;6UgT(Ge#TICe3S44`O*K3 zrOw!+uE3@O-z~&QtK?$g2ct(gq~P0z5u~4XhaGKfT3cb4c>@yu!iJ)rdklwa$2StO zf<>$$j~Zi)d`B^r>{RE(ylA}d$hQ_ZSobL<({=(WRU#$4fMhu;nBNUbIB|2~lA?N7 zbj@3d!@Gf$;36Y!k{1d;BPFmp;kO?n$!^WT&NL`Rz7KhlDQqt4v&S&+b$mk-E2N99 zaJL}nS-$h%0dXV$v|R<|*kBi;piKk2VAY_%~L(qSlY!;G^f@Fz*S z0lo~by9|7+6Xh*Q@EEHp^0kiBocb2GKu9sb;l2QliP7XaZ3?^7IEErO-hYc% zVfu?$GjdHywbrrHPdF3~4&eL-F3~oSze>^!AUF%0>u3h~P+P_JF@Pf9Anhe5eL0DR z#<>!4i&#ua=dBZ@?+}Ow7e+pQ?KGOdNz4WiB&*K1z-rQ<9b+dMKoL2hhMe^0SUiRc zPJvSa94aQ8+hTQlaRtgS$q#zr+pA+%PBLbI2s5CfQH&>VIy0oO@dDr+0@M)quvMWmX*dym^tDHc6{jZc|q4%8gvOK@u#|Dt{$+*ypNyMab^kq zPFAI&nW{^m*%=yMWBUr51szZ6E=$xVNF%bi*jh~W?FvM#{h^GYtCkP#l|I5|VaH>- zVu{{@-`0uo68fF8l!_)XI2&Z58lIlBeE`k)kmEu9N_xyD$Z;%U*ILZWixha5p_c*e zG*xd%Yq1%1Wb2`H^A`Nb&S_2(A(6FSL)%oF8x2oEcFJ+QDL00Gg6WhBt|&`(w;_hg zbOcOxk-7NmfMct%(Z9dFvvA27C>mI+VX8)qed^RHQ?b!^p>3)Kkd~>r+1Mg#X*Cy+#;f+?%sfMG`u8_@ zpH;@hV+323RyPMTJ>Sg-e-TE(y@#F(4OLyRKw?!pKmJ8SacXnK=qYeogoEiv`;L1a z`V)&`Z-`haXW1?NP(SEYp*mHlP8F(Ch3ZtHI#sCu9u?|7^XxK0Vt>H@FF>av1$XyO zMXFPg>QtmU6{$`|s#B2yk*rgZ>Qtou=O|L`d%5<_ZKb9?@DJ5R&5zvs?ZM)YKPZ9! RcNCfam&c}k@xZ**{{;h$Obh@3 literal 0 HcmV?d00001 diff --git a/game/assets/textures/kenney_prototype/PNG/Purple/texture_06.png.import b/game/assets/textures/kenney_prototype/PNG/Purple/texture_06.png.import new file mode 100644 index 0000000..70d9793 --- /dev/null +++ b/game/assets/textures/kenney_prototype/PNG/Purple/texture_06.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://da3n7ntfgyuuc" +path="res://.godot/imported/texture_06.png-dbd9b3c0cc103c99d7c97418eec406ec.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/textures/kenney_prototype/PNG/Purple/texture_06.png" +dest_files=["res://.godot/imported/texture_06.png-dbd9b3c0cc103c99d7c97418eec406ec.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/game/assets/textures/kenney_prototype/PNG/Purple/texture_07.png b/game/assets/textures/kenney_prototype/PNG/Purple/texture_07.png new file mode 100644 index 0000000000000000000000000000000000000000..b71ce4e6af126231de7672e2e877c6c39a67d3c9 GIT binary patch literal 2739 zcmeAS@N?(olHy`uVBq!ia0y~yU;#2&7+9ErRIjnw1`sdZ(btiIVPik{pF~z5Un0OK z#C3oE?}H`3w?_Ux)&A#5)t~?W|1Y=rHCO4Ec@;fM6w50sQT&42m)d;Rle@;mDp85$TF z4HOvISPnEWNC+@6GbK1M@Nf_ktYBbx!FYjr0lNc#gB*h`Llwi9fe`?P5wUJY@!bao z2BMt*p2I=Q@4@7~jDJ{A^b;Fo>RYv13OIZ)ikyWs0zMvxyy2>9`a z`HkMx^mV-7Vwol0{#&m()%ASl*J3@}`4`{KpI*nD6ZW4iXLlWQPg(tc#y{*MBvioO ze84ULpsoXyAZ9ZYl{9hWy;|OekU0m`tC@dr5}Qa-N&tR_fy~c{VgwW@M3qJ8`BIL7 z*y5;~aYC2ykCc1{dqxt=Kd_w-7#Rk>00adXD5waR+34W}^fEI8k>z)-K0{C;)BHEQ z57bGjCt!BkFrZfu`SXt(eq+w4{r`+%UU3evJOrk@5d#jS%O{ktv?1O9{>Gq6O8l7&W43+KR9&f0$rR&QT@W0l@G9TW$iu6{1-oD!M< D)S2}Y literal 0 HcmV?d00001 diff --git a/game/assets/textures/kenney_prototype/PNG/Purple/texture_07.png.import b/game/assets/textures/kenney_prototype/PNG/Purple/texture_07.png.import new file mode 100644 index 0000000..23eb9a1 --- /dev/null +++ b/game/assets/textures/kenney_prototype/PNG/Purple/texture_07.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bjjhenmemfa8f" +path="res://.godot/imported/texture_07.png-60422afc6ddacac994c30400cfe6db1f.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/textures/kenney_prototype/PNG/Purple/texture_07.png" +dest_files=["res://.godot/imported/texture_07.png-60422afc6ddacac994c30400cfe6db1f.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/game/assets/textures/kenney_prototype/PNG/Purple/texture_08.png b/game/assets/textures/kenney_prototype/PNG/Purple/texture_08.png new file mode 100644 index 0000000000000000000000000000000000000000..470cc5c4e95deca069225ffaeda9c412932dab23 GIT binary patch literal 2743 zcmeAS@N?(olHy`uVBq!ia0y~yU;#2&7+9ErRIjnw1`sdZ(btiIVPik{pF~z5pFhAS z#C5UvvkiW~|NsBrEB9co(yyCBuYNNya0Pq1IEGZ*dV9^0_lN@zi({}s>tX?}hy5=d zeh5Yfs~NlswcS>y_v@7K66T7u?|konmhIQxEe|wv6p$JM3DOO>8882R^`?$gouleu zA<$sUkjL)xefOr{j4+{5n$!^Z#;`-y;O_c!@7PJzIjSBQ0yo$eq=z5Q{vH30nW2H* z=N>yl!|nMqUe<+|*^h<~86j}MjA1+Tvfo#4{v|{6s1`^FR5RS+oAItZ^*g8;Fbc>D xfj5i=)(N}f=icQfOZ!OIw1Kyw+m7MTd;Wm6k$T6x#Oy!;;_2$=vd$@?2>{SvWGesw literal 0 HcmV?d00001 diff --git a/game/assets/textures/kenney_prototype/PNG/Purple/texture_08.png.import b/game/assets/textures/kenney_prototype/PNG/Purple/texture_08.png.import new file mode 100644 index 0000000..94d1649 --- /dev/null +++ b/game/assets/textures/kenney_prototype/PNG/Purple/texture_08.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dh24lgsew55r2" +path="res://.godot/imported/texture_08.png-76485ebf48adfbd14b539454c181fcb4.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/textures/kenney_prototype/PNG/Purple/texture_08.png" +dest_files=["res://.godot/imported/texture_08.png-76485ebf48adfbd14b539454c181fcb4.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/game/assets/textures/kenney_prototype/PNG/Purple/texture_09.png b/game/assets/textures/kenney_prototype/PNG/Purple/texture_09.png new file mode 100644 index 0000000000000000000000000000000000000000..4a3f689861759c61d43c8e0844d0e3d958c14adf GIT binary patch literal 637 zcmeAS@N?(olHy`uVBq!ia0y~yU;#2&7#Nv>lE)e-c@Ne6|3e z5Z7M02XmEvF@9e#nSp^x$Hg{Pjq@V3Oa_CQSo w2pr@U3i#=T&Ln>~)y>@UV zlc7MvL)%-8vNxJ}J7hb|`Gxj$x9siGiL*WNX;-Z+hqKVL-`*!`JkwU4)IK@;+5RhQ zx0k;X1KKtU1~vpFcn^G^D1G4dESUpQ#mo_)lrmy~GLyyC7w2M`EvCHat7YbxUq5#@ zn}FT_qSw*~%w!Ji%VyYJz#whiAUk3L1nAL*iwrgIb~4)NpJd#!&a~kg<4E%SVD#%B zmIZ3-Rq{{OG2GNYFy$}jnSZQIgVCKM%S{I|7~-zqVc6IIgkjnw=>t(CDVs15PJ53I)iGZY32W*mtqphypI-uoapK5=d#Wzp$P!?*pC(f literal 0 HcmV?d00001 diff --git a/game/assets/textures/kenney_prototype/PNG/Purple/texture_10.png.import b/game/assets/textures/kenney_prototype/PNG/Purple/texture_10.png.import new file mode 100644 index 0000000..ef38e5d --- /dev/null +++ b/game/assets/textures/kenney_prototype/PNG/Purple/texture_10.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bcsggsf33ue5x" +path="res://.godot/imported/texture_10.png-651d51fdf5cede652ae65f03d71c8335.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/textures/kenney_prototype/PNG/Purple/texture_10.png" +dest_files=["res://.godot/imported/texture_10.png-651d51fdf5cede652ae65f03d71c8335.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/game/assets/textures/kenney_prototype/PNG/Purple/texture_11.png b/game/assets/textures/kenney_prototype/PNG/Purple/texture_11.png new file mode 100644 index 0000000000000000000000000000000000000000..ad7bebc8c65c9c1b64046aefa6599f2dc2e2e872 GIT binary patch literal 9192 zcmeHNcUV(tmwywfGNO(Jm1Z4S5$qsB07o5E6zr%}8>qA}l!TgC!3GKfDjftw483C@ zbdW02LkUHSgb)LyL-yXx>^?I)pPw@h&hzX(n?DXWx#gVS@0|CP_j32Bq5gvTtL6g$ z792dV?>GP=(4h#BmxrM-QLeKRYv<^q_3|6T2X~ zo;Agpq%k{dKa{7m+H4O>d0fF5XTFJT$bMdP^Hf4=K;`940R;c@lB8xnccw7zo&V*O zaBSX(uJPJja@@_LAiK;^m)yw-R{U+!&)U!FW7Cxx?NOd@V)4YEQK5aUA1hK@ZFh!b zhP(~7&rG^s+Fm^{&_TU(Cb8$;u$z7qb@0AZd{t}?ytnNtp%$$Mm#ir)Rqa)V#& z^+N9>v9)>R`ZwJjZwI>@hbz+BF8#+NdyS_ahoaL0D`RlP>dcNXOdg*%lO9}Moz-E! z=7H_b;IY9^_Pd_?T}r_peG!7rBG(T&YClhTRB_w*<$Vi6N6p|nQcti$R>|vT9*6(p zM&ScXg8ABqukMw8qB1diBS}Dp{b0};;a|uZkGR2+s0Zd`f)}trs%92C*sqdRH3z=HxRqu zmr&e(ioA9DrTf8XmmkB=|KNXR^OI=?JKFnAb6HBnOb15yOb@}8-kAmV??;o5eqz6@fAX8u6ExBj@`nhvXPt!<*d%n-vM6biKwBgCw zSwUCBaMrW84=*HlH4K%$ZoaJY_{EJP%)ZE`;@-BZflp)8)DH}6wZLoJf`+?k0aw%W zBI`4szP+II=z@~J&$(B`xW?AXe)`9$;U3!6El={J>J#slSg!XQ?W21ez8LBrw^;Y^ zCeF8go@_T1C6bVJfk_=g7W2kK>h>i+qYX_NeE{g=h(hefK1)=3nq#ijZ+& zxiK10MZ?b+wbV@)%yYB`>Uf-W+LP2;PxanmmK$`iiMF)EHaouCbsI92kcjXd%g-uj zjO7pmZHFw1R8P_|E?v;t1b~DDc+R|kKtj4!D?$SA39DrwAW4=xR+kM zcrJY=N6WrLCb_;>xi^EcRo;+9F7@~H90XE}0Jw4#6k?c{r9Ae(TlPMp%g*sQWu-|{ zj-Z~#a(5jo3s}`LuIk7SWq3KP%5>~yw37{IYlyT%6==4BzZ@o9R04n<3P7W9X;6+^ zD|an$)Jc=#M_E8DPJpCVEW289yvk zaR5kfG;435v5GTxi&CB^_6?o7?W&lH0_h>MetrXvacwfZFy3STb9eys<`ph@%InZ^ zAH`>dgDuhY&e>qEl1Kx0j5MjLb*kcGHEldEAtKxAy3i6iU}rEn(Y%0r#SS#FfQI0# zTx5uXh1nAPaG+gl&**IIXsr5-BQ4Ry{};k|%Je-3l_56VlShDpp#$L{Gs1|a_F7cW zn|FYj`^>n$UNV)0gv#71ddPKYBCdk^ipAcDV0(`mXe1DdFkB{L#qr&Uq|=*s7h$Iq zg!ncAwR3H{JSVHuj4LM=faP7G#C?mh6<-vD*vsG_%BBxLeHM;)vf7^)DJAsyd4Sb< zJ`+vFU_GphmS(1j0b|$PvR;Q4SCFgDBSaeOWH%@->jAYQXLMVIwn*Z$3`*{EL!}S9 zrf9y-P{9|EX@NyvFDvfjlZ;c$18LI+ipzC&)2AwWP0iX}pgIh8tOB{;ES?O zfyzUA{U6?SGaGKwz6+7JB9&T!@Vi_1qC8jneTEQI#Ir^ROguoJ8F=WGJFOPk;(#SgUGI;k~AAv zs-H#B!XtUPQ&pMiNm|| z7U;fh@P%T+4NsTDccaf6s~(caCbLavZpw}EOkk^w5vdzH)Pq6pR?nJ{hX%|c+^!BD z>r{1*g-?t$=cJq>$2r}}yw5SxOFi$?(1sSHoFDF)A6n?m$x_~3h(`Wc!TlceE?8Mp z(j!ySGh1CxQBv@YajTX>k`0geO?49amyS(shn+Igl!K@N+5uFQ)0KSQk8GNCd_h8; ziNbo{whj8yD%w`3*^Ka(2Ircr>URq32C&W4OV-sJ;+D`)OX7pkYd#UEBW0H`jI*Os z^Ar38=eP_@Y^T|LUH4lvCaQW+wFw1hva(4MUs^mmi$Uj^jCc{Zs1Loyw+IqwCib#g0%wJ~{tUIW_k=&t;6*&v6>Baw3EH>(P-hrds{8DgPY zc;O0+(d;|Y{XQ-8qr2RV(sk`ljT&n7$l6=$rsCAPCKmR00^5VV>S4Q5mjLhY&DSgU zXz*XsS#kQz@x=hzZ%mMiMU`&b27`c$CrTTb>(r7Z zNfx)I?mBk73oZ4KtdyZ`)Ank?U1jdocUS#BXzgj?0t}g#x4`za!^q|0g zInWY0RF^F-*rACYZ?peSalJMMtqN%0g)F#jBvs!)97A{eq6Y?g?>m7f>O#2mJyB?m z&Q{}kq}cXS507^;{TNZpK~DAf?P`6l;fi3YX;!otm~>j`7Q=sDx^vX$(S(}$7@S&1 zyg}=eUNLM8e@(b1;aEA@1>>M*+eaU&(*!zM+V^yr==M;L153Sdb_+n$LfP>&b*i6~ z%u0i%lpOy0jkC><5Jy+S?PZiKcp5nCqJ`?vT0`|xLSbv0Q*~_&&fg!gNd9rVZtaEHE3#q51v|3z`c{irS)ty-*SOS~91AtFPimKD8bWOg% z3G_=E$wb@{0Sjn+mRv@T$^oLgb`%*BeVN zUEX(uz6;Jm^j^^~l{oNJ7i~S`syc{r*RBy->o{9H6&dAaD=?onyIqNVF(r zKFJ@3~_^i$yZ(t2_OpZVnpHL!=(@z zUvn{h@1L{gOHIJ%`wdvb-?Q?|_+cG?vC;Xr)VJe5&n&TDm8OQvs zp89v*`ByDDjN|{82+YE76B((Z&VQ99RBYkgGK~}l@;cCHpF|#-Pg;go0lG+K%kA?Z z;vlC%D-*gG%8{ZXP-sIzG3P%+3Dy%T4&Ok)!2cl#kS1s=i-GtC0!HzTT_AMtH-sR} zR&Yj{i{R)F&jpRGWhPJ-Hm_8LQn5{E9h``bfwu^Kt!akZFW&h_0^#c$(mxdij4`0_>MiwB~mv#Dzsa+a}RUO=KxG(uf%Nzd*bIU!R literal 0 HcmV?d00001 diff --git a/game/assets/textures/kenney_prototype/PNG/Purple/texture_11.png.import b/game/assets/textures/kenney_prototype/PNG/Purple/texture_11.png.import new file mode 100644 index 0000000..c908a05 --- /dev/null +++ b/game/assets/textures/kenney_prototype/PNG/Purple/texture_11.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://c58lqvxgahxiv" +path="res://.godot/imported/texture_11.png-115b6e8468e65b6c0fc6a0bee7624fdc.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/textures/kenney_prototype/PNG/Purple/texture_11.png" +dest_files=["res://.godot/imported/texture_11.png-115b6e8468e65b6c0fc6a0bee7624fdc.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/game/assets/textures/kenney_prototype/PNG/Purple/texture_12.png b/game/assets/textures/kenney_prototype/PNG/Purple/texture_12.png new file mode 100644 index 0000000000000000000000000000000000000000..979ac5a6ce706dc01feb1bf55f430e65b510743c GIT binary patch literal 9059 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 literal 0 HcmV?d00001 diff --git a/game/assets/textures/kenney_prototype/PNG/Purple/texture_12.png.import b/game/assets/textures/kenney_prototype/PNG/Purple/texture_12.png.import new file mode 100644 index 0000000..f0bd767 --- /dev/null +++ b/game/assets/textures/kenney_prototype/PNG/Purple/texture_12.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://3inljjn1dar8" +path="res://.godot/imported/texture_12.png-da0360b498f0cc20461ee7d37e76396f.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/textures/kenney_prototype/PNG/Purple/texture_12.png" +dest_files=["res://.godot/imported/texture_12.png-da0360b498f0cc20461ee7d37e76396f.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/game/assets/textures/kenney_prototype/PNG/Purple/texture_13.png b/game/assets/textures/kenney_prototype/PNG/Purple/texture_13.png new file mode 100644 index 0000000000000000000000000000000000000000..2a9df22a249603586d4858e51d6b2461f2ec1866 GIT binary patch literal 9592 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 Tl=xO8e(l?RXjl3UrwjiH{!D^u literal 0 HcmV?d00001 diff --git a/game/assets/textures/kenney_prototype/PNG/Red/texture_01.png.import b/game/assets/textures/kenney_prototype/PNG/Red/texture_01.png.import new file mode 100644 index 0000000..54180f0 --- /dev/null +++ b/game/assets/textures/kenney_prototype/PNG/Red/texture_01.png.import @@ -0,0 +1,41 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://obvqs5j7ktas" +path.s3tc="res://.godot/imported/texture_01.png-59f0738b795d1de18217b3c8dbde69c8.s3tc.ctex" +metadata={ +"imported_formats": ["s3tc_bptc"], +"vram_texture": true +} + +[deps] + +source_file="res://assets/textures/kenney_prototype/PNG/Red/texture_01.png" +dest_files=["res://.godot/imported/texture_01.png-59f0738b795d1de18217b3c8dbde69c8.s3tc.ctex"] + +[params] + +compress/mode=2 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=true +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=0 diff --git a/game/assets/textures/kenney_prototype/PNG/Red/texture_02.png b/game/assets/textures/kenney_prototype/PNG/Red/texture_02.png new file mode 100644 index 0000000000000000000000000000000000000000..bf1cb173ba132270f0d3e2a0d98a487927b652f0 GIT binary patch literal 2774 zcmeAS@N?(olHy`uVBq!ia0y~yU;#2&7+9ErRIjnw1`sdZ(btiIVPik{pF~z5UnsyQ z#Pz>n+<*7{|HkqErF{Ma0fWVkpkgKl2CjTh7srr_TW_x&{~b2ezck)J2^D;GT2PAsyFaGBrzopr0Ij8R*Z=?k literal 0 HcmV?d00001 diff --git a/game/assets/textures/kenney_prototype/PNG/Red/texture_02.png.import b/game/assets/textures/kenney_prototype/PNG/Red/texture_02.png.import new file mode 100644 index 0000000..fce5104 --- /dev/null +++ b/game/assets/textures/kenney_prototype/PNG/Red/texture_02.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://wcyl2f5pkwr2" +path="res://.godot/imported/texture_02.png-2675158ec58674de8125e440cd805fdd.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/textures/kenney_prototype/PNG/Red/texture_02.png" +dest_files=["res://.godot/imported/texture_02.png-2675158ec58674de8125e440cd805fdd.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/game/assets/textures/kenney_prototype/PNG/Red/texture_03.png b/game/assets/textures/kenney_prototype/PNG/Red/texture_03.png new file mode 100644 index 0000000000000000000000000000000000000000..ff09c22c2b1c6a0047418bff6f990f96038c6706 GIT binary patch literal 1338 zcmeAS@N?(olHy`uVBq!ia0y~yU;#2&7?_xW6jSkG0T3_U(btiIVPik{pF~z5pEJNG z#Pxsa)1a@YbU z2NV6h4eRHFlE`2I4MGeTZMX-EYryUhWmr`ClJ(44eT(w?K^1`?SR8b$+}3$~`}S9C qP=%NlgUjbj+&_L<4klNvD5zuRE$b_Z+ah2La+jy8pUXO@geCynmQBF` literal 0 HcmV?d00001 diff --git a/game/assets/textures/kenney_prototype/PNG/Red/texture_03.png.import b/game/assets/textures/kenney_prototype/PNG/Red/texture_03.png.import new file mode 100644 index 0000000..4551133 --- /dev/null +++ b/game/assets/textures/kenney_prototype/PNG/Red/texture_03.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dybj163h6bb27" +path="res://.godot/imported/texture_03.png-5a870c4bbb35c520362d877c5128cb8e.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/textures/kenney_prototype/PNG/Red/texture_03.png" +dest_files=["res://.godot/imported/texture_03.png-5a870c4bbb35c520362d877c5128cb8e.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/game/assets/textures/kenney_prototype/PNG/Red/texture_04.png b/game/assets/textures/kenney_prototype/PNG/Red/texture_04.png new file mode 100644 index 0000000000000000000000000000000000000000..b5b77ff295eaf3b0a532da09e1ddb670cdbd3371 GIT binary patch literal 2727 zcmeAS@N?(olHy`uVBq!ia0y~yU;#2&7+9ErRIjnw1`sdZ(btiIVPik{pF~z5pFhAS z#Pxsgvi}Wp{sV!O&wmCBt1Zkk7#O&mJzX3_DsH{K?#SB`AmDP)jY({SfyaUUYAywm zm%hIHZ!p^{{p8YDkJK~RKh(Vb_x<$npbM}vgC5J=!3tx(7dIk>LT3I!e%WH7cd29z>P`Ofsk VO6PwD$Bjsk5uUDoF6*2UngGl5VF>^L literal 0 HcmV?d00001 diff --git a/game/assets/textures/kenney_prototype/PNG/Red/texture_04.png.import b/game/assets/textures/kenney_prototype/PNG/Red/texture_04.png.import new file mode 100644 index 0000000..f862948 --- /dev/null +++ b/game/assets/textures/kenney_prototype/PNG/Red/texture_04.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bcysuh5pf4a46" +path="res://.godot/imported/texture_04.png-097a57695a228b64e379ff06f4c97dfc.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/textures/kenney_prototype/PNG/Red/texture_04.png" +dest_files=["res://.godot/imported/texture_04.png-097a57695a228b64e379ff06f4c97dfc.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/game/assets/textures/kenney_prototype/PNG/Red/texture_05.png b/game/assets/textures/kenney_prototype/PNG/Red/texture_05.png new file mode 100644 index 0000000000000000000000000000000000000000..7827035ad5242b77c6e55558ee9cdc8a40ceaf60 GIT binary patch literal 13212 zcmeHu`Ck-Q*8Z(7pi!XP#EmG@%)|tDOoD=Im17pO7#KC~+9WZGYZHy)0#vCW`c3>(|KS@JO);DixnH6R7oHH_ z?{o4o4%p0j-XRSYQXtJ$V4kRVIZfdK-#e8>vXtB8l~n(|HGwPAY+Qqiqq0zSu)zJ- z7Fz`#hU#^3XcbQ5%Hd@JveTD>Uc~c*W?mfR;5N78r%`ZTs}zL}A-#ATFGMZ2D>w}u z3Qt8%s#9mjU#k)?52UJz$d~pI4?_`klUX!^<4i#LELH z@=x%xMtTap#~I{f*b4p(#lIm${V|7$_-vp^w^^Ycd;lK&hKHkv+RJbe{}8Z*C9I*y zI#erc!Fy5fBw|*27R**lFQLO!*V$24n>|j0_=viY0xl%0*}Bb#soe&EZp6n?ZyL5l zV!11&pj8?)N>-P7oJR2mg=Pb^i)z$u{+U9909}v2MZL9169DSMgV8Vw6@c}gUoeR0 zDAWkhMm35%Ggamj-1tM(V!9>uMIESa5`_9ousdI#N2B={*gc4sqOWK)N-PTIx0#=k zuW7pQnf@nO5oUiv?e>RH;ZS$$%2!b65E#OlcsZAOgnIaIu(SuCLkDIOR%sTnUX>Q3 z9yC_vMdUL+Qih|3ZZ34jZ|;eLr7dQYJeTqm8Dw>=&k`x_rk}h5XrBs}gxN1r+MYlw zt2=b%b1CgWpdE=9bD2L;+V6q(YkV3VputKrfcCt!5cQxRU3md$A1K36Yj;BH>;be* z&UpC|rL_=RuRBs~ptL0<+CY1ly@}F}09sK!s!PwNw4;DF4(D=(TC_g`?dSLcx}rsE z2HI1S1@+USeFe4@;;#d${R6U>mJ{8{wv0ip`qm^ZBeC&VYht(qQDXRpFJ$ zpoHmV)#%AYEyB;zCnzrWDR@87a|hK*b8!zY)$<~mqg{b|LvVMPt1{|Cn86j1vRczx z)L9;zbP6)v{2W-jrc6Lz9E*i%D(wXDWIUZqZCpygTLJufaCdkHj#^59^@1eF6eF*qCfM3O5ah2YmC^KYihv4pr3}@6b0*(f7b5T!uR?>L_9s=MC z%2L#JER}$70eC3B!BswKqRaq38`!PS@JD?_z%aZuO+_a8e9}b%9tGfY${2L;#5e+m zi6lLbyK$AC7kh!*F(l@|jH5B>UA3KMm{{4J(yKgG1 z&^8lUgy7$O?G4V+Xrq;+xg{R3ZE2B?OJm6jS_KLAkKjwX;>K9A@_meIo%^IWP`vON zSQ23UYOk|(mh-K50h-o9R&V(d!(A6o66i9WT`E$iaVr~B3G_RF{vb_9kA=+y+8>|~ zZQbRg)@lNU^=p@a{f1JtT+=MFVbCD8u>^c!gbS|WT&pfEw&YivE`9o7c~ z8Uw7}M7`_UNdjHQ+a-&7ojdeoC4p80bi1?~{b(wOSZ%#f(BD*MbX^Y9wT8Rg{0IR40Kj~qyDV7i0ayya?rH|Q9e)ED%fdw*A2^GSjXnrw zOz;tVdA{XVuF8ThETt)FDfm-iv_Ih6Z?#H#S&I5yHMvR^;f`gklBUkE zpAC+PM1lN_T9oH6xDFXr&t>2qpT{}2D6n3&!EbToH76`pxu`rmtj>a3Qc$&SU26*R z^+Zd#U*NyN7<5?92*MYLkY|d;YJ@1k&vL?4_-R$Rgzla8fFUQ^tl6=kGk=)*V{HD& z8#1Z>?@xx&`$EfstGVnw*b@&!FFdK(Rb~^;2LeyZgm3UM^L|O+=x>+sEKgvi!k0Up zx@e!t^{`C3n|KtFCBzkw@Q_aI*{1#}@<{04ZMbir!=Yz$UToM*nXEKfYLQ?#H_$=G zHx-wpeC+6!L6)trv909ef3jz1$|oPQ=c6T`%w^Ah^MbqJR#*24#@Cy(j zH!Cm6$HHMV9fN9MS2#Zkc49rz1^gKO#JmV{u$9*g>-jU&LWZpon|}%oiOG=ge#o#8 zFa8=bY>pNEA;U_t{2*jl`Vj5y9vY@5)Ps54mCs}YUlDD8$V?28w=vu;vOm|n*ve;? zgs3YF_UlY}lsuU!2T>2^atxojKcrj|Z9f}Qb|%Z+m~s`_f@_vH@r4RgHrRbkd8B-U zDf>}B=5sH;konvmZGXg+hsa+sWhdEXYnFHNh0N!6gZ&0m9wkp_${6)yKJ$Db^Vu40 zKNnIKlI0#DWn78+F`w7-sV71{TMe#8raV&qmMMFXfw|Fg-VN@6{I{3XS3pW5)bY?w6PxEcer59rr@H zZ+k(`4_OmFK-SQtk}jZlX81eqra5GI8h?nT)a8gQOUQ6djO#+kx3oA%12a5K-oXqn zMV(_n3ceL%DUivB`0`#G~HOLE!jwsuwIIq zSqr<$0Xcbrawk`7^q=Hb`kHOm^^J9jM^G~IT~-&Nf8ap2kL&UgHwU$p1}~yxfuNNa zyCYZtZ`-0Bbxx?7e8kO!(}}|r?Wj^0!G^>!=0&=K@J*?SwqU2uL)1zY35)+t*DN4^cJ6t%j~z}6<=Y1t~^hp?wbT)ASB z{*1Z{xB6Sc_(!!0W-S&2SJ}L(d9+h1j|d+Wm10nyKI|NCLD)@Z{#`~6cSA?t0FN^?d8^D@?e@8c0;cSQ_ zAqgC>wZ+P7Y}f_9d`C_O!Dd}nd$TzX9g+8d=l>#yCrPE`U4Xo$tfOOnnMMwyvP*rP zTiN2J1&tgIrnh{%!dy>kD0v4UH{;LIfE@KGgi<~l$m?yLU}DH3Zg^~u{Bg&0TqWZHHI&~L@l3(1MxF~s_=}x8ZQjNL{CbT zV}a(Cc0TSZx2guaJu0&^3Z~t4_CY-Zy~Huy%gI^$lrkP2^o)?#4YI$2T7*r~7PP1- z8->pj*Td;Ko}AksP+}htzpTdSinWlgLi%qH)af&JQ{n{>@I>zvqhl^5o}`roddUrx zxDZY~X%Ec9&8^cpd#s9aUvMqg;euLAL2X)B7;h(7`1 z*`zw7MSKs4|D$%*Wx?!(kC;y)4qElDLQ4Ea1Q7d82FJUUI1X~PrcLM}-=oB--GKNp z)PuTG;w(7d+HT>gXaOa5!5kBg<8RQUCuFD{Yk@cqKg$(r84!fU1Yw>ltfnJ>3&b!S zd6&M80dXWA$YpBrwt^_)7%o$b_bP}l<5n(Hi}z;`$HA1$ z)Z*O=;#>GnwlIf&_aE0?Lo`wobcNQqR7cL<16@jG0m7H?M&XW}7TrWWsgSmulI z-%xTJ{R*(*HeHv7p}j#eJBnesfXZyNxQu?^0bwHE7c9_~-=@i6g=BC+#dlmIg`NaU zNANu~NBg{g1xvT_yJ!Oa_>E8%vAS^|G>oRkAt;$7HcFl3-qi3-C5t>DgRv6BM)IouCD)O2C(Tjn)KBsi%PCJ1(p z+MPpMI8fIwdw^d+A5%lOVdg&!2w_M|WvICcHta`(sUZ(c{KOWiJ32!RNkIBJv=&4! z^%qK%&{{}DUs6M}f#qw}0_PVp{Eg6}NNkm2koH|`!0c}PCj2Io)pjHd(tN1f$XeXl z;5=!3XcO~9sWDj7Dj6JQchU2?stv2|T~aGma9%9Rki2f3WAl1(4fy#QUS$K|3#}Ex zL?I{%lKLGSv67_7+7h`l?&ebPBf)FoDxq%dF>=x)!Ee(2lh%}l;1Ijo>{9|`6F#D) z;2J6NJA6Pb!d5CnrmF*=tBm|wicr+So7F8o?ENrf2}P8c^w*@fv0{l_r}Y?W zV#c)CF5z1<*8P{Jp)Lma5&iyG(+zt#E8$>V8^__m_lMz*=cFMX%F( zE_c?0i3|Adx4(QwYu!R#@|Ws`(GNb+eQ3E{rw*CnTW=3o!V^}}0D3|;{u%G!;FJcXI84&76t6%N zXz5>pTHLNDN@w|ZYS#kLX#sb5!iN+(f+q4&?#v7doej{FI1gQ-<$DFPW*3Yym z+(x5Gf-Hh5&6h**9;%-3vm+dU)!@KvVi(o{pS50j9&Mu0n4dyHeVe(fe2_wmpn7@F zR}>{)rXEfKOYa7!MA+|B);dV@LUkcuo<$9B1&7ng0#-u5zzyK}9{W%-4P9Ce{$G;D zqUkgT6xdc+YnA8FCasat320lKUF4yZ)tJCus@)*exU86uHn#%c?#_s`PbXBHr(-=;&BmaF2lDrvi2v z1CifM%Jd3M1Ys9+TQ=tE<`f0Pu4BKq!r=I#poV~9Lk%0NQK-snC*TzTE`W~9 zqPz_R{0P94$eykB6;h9{BQbkRA|0m-9s<}xVy=dcOV#W`0w()ED|B2It^R?4p9gTV zx=B}j{}cgNk(fOt9UY$*)DbX=`7U%^>deIi{0@Ngq2sbA?<@h&1#lO#O>KLH6!fb| z%$|~H$GL(A0wyuLoXMze_8|g>Umv$qS&Swh|A_Q$F2lzCxO5NgS@ne2BHQI`e2ts> zq>1)`U^88#p681Lh`hZ9Z!Nfuo0=0wu+4z|S^5jw7XK@(ZqT9ewb$F8l0PXWIg*KdlHOb*MDTX-vMvj+ zCD3UAO~c2~&D`DuIvt>wgcneI{5b;c4$zjeXvfY{(wR$yZ)ONiBW9p72ItWj$8YP&*FTGD%l!Mfm3b`>_3~{28f_oKNi!|#%UonG z_s@eaO+%XA)vh~new1u8U-ZLHTd2ozvbnmVpvYNn##8KyFD3BgdQF8bHzzOx1!iQl zVI-)*4pLMgx5=p+|JXSOxrDH>`o=2dcNmL#M&z%^s7C(?!1ijtUY)vO7`4h98=Do18HNUz9dwj zRF3~Cj1`aZvFEz{94g!56McIh2t7NG4@_p|cBeErjI}j{oa8S1LOMcTYVYFEbJFPe z;Zn%HIXdCLkA{R?_OCH;154|)n2oUK4>et4#m6BRl_Bz#kms5cQEA-(0Hc&JqMSgG|N>HupQSdTjInZQ(lg)GB+M@S6D&5N}tX~ z*&Qq1V#@Q-J52dU4(>l`mi-a1X7sEjIITt$6ZDji@(O`V$t!uhc%iua5*f^&Y;^NHfb($hkStUpc3-T z*27^V1F_49YOOJ@#Xy0t^P+DVzmg2M)P(G+3(Y1#+X%Er7$(<*zXip$8iOO{nyHuL zvTiO^<(KJQrBklidO6(TIXgxmUo+r&e2##!8614 z7uZ#PaHsiRzG@JqN+|JOw&CAL%VyzXxScDvwaw!j12xKJBb3w=$Q2`NgzLUrf|dh< zW>K>`2hGM%L9s`{5o{%?Z=unFKmphiVH3Y3@INRg;H51cDA)x(ow-9EuZ46* z;9Q+uZ47fY1x=(A(n5{{x&nmI5EgXlr3nUa48I4NdmbMhldz;HZUMO3P)`&^OEk&{NPK}sETx(83YcyiGsR*}Er=t}b@dO~= zCGAD^8u3mbo`B!rQniTt0r4Jnxi0HJ8Zn8O+=|_-5tE30P^o!=633B<+lo5L>nU+6 ze8jSPX(W10D|$oQ)OG`!pax3pg0(>?!52{+C3frs;-z>!SEv!g`4(>T!d>5!lo)O( z;)g+FxczUG*g%N=rVe5+N?Z@bJh?^uoF>8~de-AMiUTzf(q*j2Z4ifOBIL*W9(Rm5 zN)utU)_dI1;wzd6rL1pBL2bMyLZR!V$K6qUM-w5Z?|IxE#935aM0m-iX)R3`5nivw zC@$9C5?-&xATHNL!t1rfh`E|bc)gZrk=I1ROX`PFnn-xPmX2a)O(eWtO9!zh755Nc za!34GO(eX&BBR(}6A7=c$RNI?iG6l zkPLcK{ar_)@sP3?gC>1~_Ia)Fc^g$DzgcTSkveh?evLb$H7?+qvalAfN4>S)#1i;X z`2{M{Khc#V3tG)-ci=Av=2M@gTJ{2x6b4PT|IB*$V|a z_$!GQk(WB*fuF|2W+f77xoiZxL*cJ1614US6u#1G;4d>iqlRvWi`W}*>SZlfazXVQ zd=!bAA&6#P3+{=|(OF;tLvLV#b7+R3T2s>ke=4Fipb7x_1N^~=NCO`UpK4mrtP{09 zOkd!v!*S>ewWEOZ$J8=Tq>(j_%BvNM@G=x=`mJc15-pqa#s^yQ_p8S^e>*d71pIjo Pdi|BRU;gng8SDNZR^^!5 literal 0 HcmV?d00001 diff --git a/game/assets/textures/kenney_prototype/PNG/Red/texture_05.png.import b/game/assets/textures/kenney_prototype/PNG/Red/texture_05.png.import new file mode 100644 index 0000000..dfe4840 --- /dev/null +++ b/game/assets/textures/kenney_prototype/PNG/Red/texture_05.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://by2o1oydwmorb" +path="res://.godot/imported/texture_05.png-53c0dfef02ec13aba7e455a457e8870a.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/textures/kenney_prototype/PNG/Red/texture_05.png" +dest_files=["res://.godot/imported/texture_05.png-53c0dfef02ec13aba7e455a457e8870a.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/game/assets/textures/kenney_prototype/PNG/Red/texture_06.png b/game/assets/textures/kenney_prototype/PNG/Red/texture_06.png new file mode 100644 index 0000000000000000000000000000000000000000..914a6f14539002083063e0ca45cbd67fe71b1515 GIT binary patch literal 19065 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 MnbSXic){BL0mH6EB>(^b literal 0 HcmV?d00001 diff --git a/game/assets/textures/kenney_prototype/PNG/Red/texture_06.png.import b/game/assets/textures/kenney_prototype/PNG/Red/texture_06.png.import new file mode 100644 index 0000000..b129245 --- /dev/null +++ b/game/assets/textures/kenney_prototype/PNG/Red/texture_06.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dv8yi804matr4" +path="res://.godot/imported/texture_06.png-58405bde1f5c3e8a5b8c94c4d9c0e280.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/textures/kenney_prototype/PNG/Red/texture_06.png" +dest_files=["res://.godot/imported/texture_06.png-58405bde1f5c3e8a5b8c94c4d9c0e280.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/game/assets/textures/kenney_prototype/PNG/Red/texture_07.png b/game/assets/textures/kenney_prototype/PNG/Red/texture_07.png new file mode 100644 index 0000000000000000000000000000000000000000..47d517bfdaa19580e697dc318e04d57dfc00050e GIT binary patch literal 2739 zcmeAS@N?(olHy`uVBq!ia0y~yU;#2&7+9ErRIjnw1`sdZ(btiIVPik{pF~z5Un0OK z#Pxq|u|Mr>xODF$NYyS@fQa=9~EYhR$k{B4c+&o~)y>_tokb#KnMV%Lo zY!f1w1w}6~&Ev}1#?iR!ZziKL=eDo?-@^~-w;w1eb(;V3`S<$g%j9>~Gcq(VG8!l_ zu(2FyV2}`CU}j2iVBp~(Bv`?~@PhFI^8$7U{suV)TZSrzF9Rb03?pLQjN-cw3=Bj$ z|2>C;mfwTPdl~<*py($y$k-Xs!so%;&lbn(7}mbOFLR){k9Wb>zl3pv(DS7n1F^+X zHRFUX;U6ja4EBs9mVaP7A22cud;tgwFi=ntF0;|Y3Fu{J1|rMvT78C~LZf zR8PR{v|&K6AoAxQH~hw&QTzWH!@S}gV0j2kcOwQINS9A2UujdEyWzdmfsF6zopr05lE)e-c@Ne6|3e z5Z9*+M*kTs^uzj>GcYhIdAc};RNQ)dVIwaC0|%4i_xLFH1&cnt@YJ&x-j?{*9;j&m vfrGq);Q(3>w7S7*VC`oR0!8P*fj#Up$N%$vvOU7O2;>M)S3j3^P6l zSQei+z7gg5LFm~B>I|xtrj`GLUW!R1^FCSta-yfJpUXO@geCy;r;B0$ literal 0 HcmV?d00001 diff --git a/game/assets/textures/kenney_prototype/PNG/Red/texture_10.png.import b/game/assets/textures/kenney_prototype/PNG/Red/texture_10.png.import new file mode 100644 index 0000000..8d1f8ff --- /dev/null +++ b/game/assets/textures/kenney_prototype/PNG/Red/texture_10.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://vbxv0wpgyavo" +path="res://.godot/imported/texture_10.png-4af4040ef1a09b6dec402975d7048bcd.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/textures/kenney_prototype/PNG/Red/texture_10.png" +dest_files=["res://.godot/imported/texture_10.png-4af4040ef1a09b6dec402975d7048bcd.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/game/assets/textures/kenney_prototype/PNG/Red/texture_11.png b/game/assets/textures/kenney_prototype/PNG/Red/texture_11.png new file mode 100644 index 0000000000000000000000000000000000000000..2acc544a9f048de0e4934f939afa60c18a2127df GIT binary patch literal 9207 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 Cs~N!n literal 0 HcmV?d00001 diff --git a/game/assets/textures/kenney_prototype/PNG/Red/texture_11.png.import b/game/assets/textures/kenney_prototype/PNG/Red/texture_11.png.import new file mode 100644 index 0000000..d548cf8 --- /dev/null +++ b/game/assets/textures/kenney_prototype/PNG/Red/texture_11.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://curyyr46mm17g" +path="res://.godot/imported/texture_11.png-2efd38aeed2a42bef39f9b7fe5558dc2.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/textures/kenney_prototype/PNG/Red/texture_11.png" +dest_files=["res://.godot/imported/texture_11.png-2efd38aeed2a42bef39f9b7fe5558dc2.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/game/assets/textures/kenney_prototype/PNG/Red/texture_12.png b/game/assets/textures/kenney_prototype/PNG/Red/texture_12.png new file mode 100644 index 0000000000000000000000000000000000000000..7054c4d5a58bd3f7ced2d5a8dead971074169532 GIT binary patch literal 9072 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 literal 0 HcmV?d00001 diff --git a/game/assets/textures/kenney_prototype/PNG/Red/texture_12.png.import b/game/assets/textures/kenney_prototype/PNG/Red/texture_12.png.import new file mode 100644 index 0000000..6526cfe --- /dev/null +++ b/game/assets/textures/kenney_prototype/PNG/Red/texture_12.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dlsxiqd34kceq" +path="res://.godot/imported/texture_12.png-46f405e6a14076fad5024d6740c63b6c.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/textures/kenney_prototype/PNG/Red/texture_12.png" +dest_files=["res://.godot/imported/texture_12.png-46f405e6a14076fad5024d6740c63b6c.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/game/assets/textures/kenney_prototype/PNG/Red/texture_13.png b/game/assets/textures/kenney_prototype/PNG/Red/texture_13.png new file mode 100644 index 0000000000000000000000000000000000000000..ab8c7b9ea34d477b02bc467f2aee0d645f16002d GIT binary patch literal 9590 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 literal 0 HcmV?d00001 diff --git a/game/assets/textures/kenney_prototype/PNG/Red/texture_13.png.import b/game/assets/textures/kenney_prototype/PNG/Red/texture_13.png.import new file mode 100644 index 0000000..7b46d9c --- /dev/null +++ b/game/assets/textures/kenney_prototype/PNG/Red/texture_13.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dejlhsj3a6lnb" +path="res://.godot/imported/texture_13.png-fd7cb86e05607e70b74988c38c00d4bc.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/textures/kenney_prototype/PNG/Red/texture_13.png" +dest_files=["res://.godot/imported/texture_13.png-fd7cb86e05607e70b74988c38c00d4bc.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/game/scenes/Levels/level.tscn b/game/scenes/Levels/level.tscn index 6d56063..e99cc85 100644 --- a/game/scenes/Levels/level.tscn +++ b/game/scenes/Levels/level.tscn @@ -11,6 +11,7 @@ [ext_resource type="Script" uid="uid://bk53njt7i3kmv" path="res://scenes/Interaction/dialog_trigger_area.gd" id="6_dialog"] [ext_resource type="Script" uid="uid://cshtdpjp4xy2f" path="res://scenes/Quests/quest_trigger_area.gd" id="7_qtrigger"] [ext_resource type="PackedScene" path="res://scenes/Interaction/scene_teleporter.tscn" id="8_teleporter"] +[ext_resource type="Material" path="res://assets/materials/kenney_prototype_ground_green.tres" id="9_ground_mat"] [sub_resource type="PhysicsMaterial" id="PhysicsMaterial_2q6dc"] bounce = 0.5 @@ -274,6 +275,7 @@ height = 6.0 size = Vector3(1080, 2, 1080) [sub_resource type="BoxMesh" id="BoxMesh_w7c3h"] +material = ExtResource("9_ground_mat") size = Vector3(1080, 2, 1080) [sub_resource type="ProceduralSkyMaterial" id="ProceduralSkyMaterial_fi66n"] diff --git a/game/scenes/Levels/transportation_level.tscn b/game/scenes/Levels/transportation_level.tscn index a2c3f74..fa95054 100644 --- a/game/scenes/Levels/transportation_level.tscn +++ b/game/scenes/Levels/transportation_level.tscn @@ -4,17 +4,15 @@ [ext_resource type="Script" path="res://scenes/player.gd" id="2_player"] [ext_resource type="PackedScene" path="res://assets/models/TestCharAnimated.glb" id="3_model"] [ext_resource type="PackedScene" path="res://scenes/Interaction/scene_teleporter.tscn" id="4_teleporter"] +[ext_resource type="Material" path="res://assets/materials/kenney_prototype_ground_green.tres" id="5_ground_mat"] [sub_resource type="SphereShape3D" id="SphereShape3D_player"] [sub_resource type="BoxShape3D" id="BoxShape3D_ground"] size = Vector3(1080, 2, 1080) -[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_ground"] -albedo_color = Color(0.194, 0.575, 0.194, 1) - [sub_resource type="BoxMesh" id="BoxMesh_ground"] -material = SubResource("StandardMaterial3D_ground") +material = ExtResource("5_ground_mat") size = Vector3(1080, 2, 1080) [node name="TransportationLevel" type="Node3D"] diff --git a/game/scenes/Vehicles/car.tscn b/game/scenes/Vehicles/car.tscn index 9d1fd51..d22c84b 100644 --- a/game/scenes/Vehicles/car.tscn +++ b/game/scenes/Vehicles/car.tscn @@ -1,6 +1,7 @@ [gd_scene load_steps=6 format=3] [ext_resource type="Script" path="res://scenes/Vehicles/car.gd" id="1_kbd20"] +[ext_resource type="Material" path="res://assets/materials/kenney_prototype_prop_red.tres" id="2_car_mat"] [sub_resource type="BoxShape3D" id="BoxShape3D_7r1j6"] size = Vector3(1.4, 0.9, 2.6) @@ -11,9 +12,6 @@ size = Vector3(2.2, 2.0, 3.8) [sub_resource type="BoxMesh" id="BoxMesh_4y8xk"] size = Vector3(1.4, 0.9, 2.6) -[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_red"] -albedo_color = Color(0.85, 0.1, 0.1, 1) - [node name="Car" type="RigidBody3D"] script = ExtResource("1_kbd20") seat_path = NodePath("Seat") @@ -26,7 +24,7 @@ shape = SubResource("BoxShape3D_7r1j6") [node name="MeshInstance3D" type="MeshInstance3D" parent="."] mesh = SubResource("BoxMesh_4y8xk") -surface_material_override/0 = SubResource("StandardMaterial3D_red") +surface_material_override/0 = ExtResource("2_car_mat") [node name="InteractArea" type="Area3D" parent="."] diff --git a/game/scenes/block.tscn b/game/scenes/block.tscn index b96d3be..0f4c680 100644 --- a/game/scenes/block.tscn +++ b/game/scenes/block.tscn @@ -1,21 +1,20 @@ -[gd_scene load_steps=4 format=3 uid="uid://c5of6aaxop1hl"] - -[sub_resource type="BoxShape3D" id="BoxShape3D_4du60"] - -[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_alp5v"] -albedo_color = Color(0.290196, 0.698039, 0.227451, 1) - -[sub_resource type="BoxMesh" id="BoxMesh_kryjk"] -material = SubResource("StandardMaterial3D_alp5v") - -[node name="Block" type="Node3D"] - -[node name="RigidBody3D" type="RigidBody3D" parent="."] -collision_layer = 3 -collision_mask = 3 - -[node name="CollisionShape3D" type="CollisionShape3D" parent="RigidBody3D"] -shape = SubResource("BoxShape3D_4du60") - -[node name="MeshInstance3D" type="MeshInstance3D" parent="RigidBody3D"] -mesh = SubResource("BoxMesh_kryjk") +[gd_scene load_steps=4 format=3 uid="uid://c5of6aaxop1hl"] + +[ext_resource type="Material" path="res://assets/materials/kenney_prototype_block_dark.tres" id="1_block_mat"] + +[sub_resource type="BoxShape3D" id="BoxShape3D_4du60"] + +[sub_resource type="BoxMesh" id="BoxMesh_kryjk"] +material = ExtResource("1_block_mat") + +[node name="Block" type="Node3D"] + +[node name="RigidBody3D" type="RigidBody3D" parent="."] +collision_layer = 3 +collision_mask = 3 + +[node name="CollisionShape3D" type="CollisionShape3D" parent="RigidBody3D"] +shape = SubResource("BoxShape3D_4du60") + +[node name="MeshInstance3D" type="MeshInstance3D" parent="RigidBody3D"] +mesh = SubResource("BoxMesh_kryjk") From e5dd8a7d04729fd64fb1e7154f4dcbc3fb06e047 Mon Sep 17 00:00:00 2001 From: Zeeshaun Date: Fri, 13 Mar 2026 10:02:03 -0500 Subject: [PATCH 05/19] Changing teleporters to be physical arches --- .../PNG/Orange/texture_08.png.import | 13 +++++++------ game/scenes/Levels/level.tscn | 4 ++-- game/scenes/Levels/transportation_level.tscn | 4 ++-- 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/game/assets/textures/kenney_prototype/PNG/Orange/texture_08.png.import b/game/assets/textures/kenney_prototype/PNG/Orange/texture_08.png.import index 6ef4b7a..62fb5b9 100644 --- a/game/assets/textures/kenney_prototype/PNG/Orange/texture_08.png.import +++ b/game/assets/textures/kenney_prototype/PNG/Orange/texture_08.png.import @@ -3,19 +3,20 @@ importer="texture" type="CompressedTexture2D" uid="uid://bgeqtevr8mq0q" -path="res://.godot/imported/texture_08.png-6def30fa8b996cc3afd9972a61b642e8.ctex" +path.s3tc="res://.godot/imported/texture_08.png-6def30fa8b996cc3afd9972a61b642e8.s3tc.ctex" metadata={ -"vram_texture": false +"imported_formats": ["s3tc_bptc"], +"vram_texture": true } [deps] source_file="res://assets/textures/kenney_prototype/PNG/Orange/texture_08.png" -dest_files=["res://.godot/imported/texture_08.png-6def30fa8b996cc3afd9972a61b642e8.ctex"] +dest_files=["res://.godot/imported/texture_08.png-6def30fa8b996cc3afd9972a61b642e8.s3tc.ctex"] [params] -compress/mode=0 +compress/mode=2 compress/high_quality=false compress/lossy_quality=0.7 compress/uastc_level=0 @@ -23,7 +24,7 @@ compress/rdo_quality_loss=0.0 compress/hdr_compression=1 compress/normal_map=0 compress/channel_pack=0 -mipmaps/generate=false +mipmaps/generate=true mipmaps/limit=-1 roughness/mode=0 roughness/src_normal="" @@ -37,4 +38,4 @@ process/normal_map_invert_y=false process/hdr_as_srgb=false process/hdr_clamp_exposure=false process/size_limit=0 -detect_3d/compress_to=1 +detect_3d/compress_to=0 diff --git a/game/scenes/Levels/level.tscn b/game/scenes/Levels/level.tscn index e99cc85..23daa61 100644 --- a/game/scenes/Levels/level.tscn +++ b/game/scenes/Levels/level.tscn @@ -10,7 +10,7 @@ [ext_resource type="PackedScene" uid="uid://bnqaqbgynoyys" path="res://assets/models/TestCharAnimated.glb" id="5_fi66n"] [ext_resource type="Script" uid="uid://bk53njt7i3kmv" path="res://scenes/Interaction/dialog_trigger_area.gd" id="6_dialog"] [ext_resource type="Script" uid="uid://cshtdpjp4xy2f" path="res://scenes/Quests/quest_trigger_area.gd" id="7_qtrigger"] -[ext_resource type="PackedScene" path="res://scenes/Interaction/scene_teleporter.tscn" id="8_teleporter"] +[ext_resource type="PackedScene" path="res://scenes/Interaction/prototype_gateway.tscn" id="8_teleporter"] [ext_resource type="Material" path="res://assets/materials/kenney_prototype_ground_green.tres" id="9_ground_mat"] [sub_resource type="PhysicsMaterial" id="PhysicsMaterial_2q6dc"] @@ -613,7 +613,7 @@ scroll_active = false environment = SubResource("Environment_a4mo8") [node name="LevelExitTeleporter" parent="." instance=ExtResource("8_teleporter")] -transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 5.5, 0.5, 0) +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 5.5, 0, 0) target_scene_path = "res://scenes/Levels/transportation_level.tscn" [connection signal="pressed" from="Menu/Control/VBoxContainer/ContinueButton" to="Menu" method="_on_continue_button_pressed"] diff --git a/game/scenes/Levels/transportation_level.tscn b/game/scenes/Levels/transportation_level.tscn index fa95054..d3fd0ef 100644 --- a/game/scenes/Levels/transportation_level.tscn +++ b/game/scenes/Levels/transportation_level.tscn @@ -3,7 +3,7 @@ [ext_resource type="Script" path="res://scenes/Levels/transportation_level.gd" id="1_6y4q1"] [ext_resource type="Script" path="res://scenes/player.gd" id="2_player"] [ext_resource type="PackedScene" path="res://assets/models/TestCharAnimated.glb" id="3_model"] -[ext_resource type="PackedScene" path="res://scenes/Interaction/scene_teleporter.tscn" id="4_teleporter"] +[ext_resource type="PackedScene" path="res://scenes/Interaction/prototype_gateway.tscn" id="4_teleporter"] [ext_resource type="Material" path="res://assets/materials/kenney_prototype_ground_green.tres" id="5_ground_mat"] [sub_resource type="SphereShape3D" id="SphereShape3D_player"] @@ -56,5 +56,5 @@ transform = Transform3D(1, 0, 0, 0, 0.819152, 0.573576, 0, -0.573576, 0.819152, shadow_enabled = true [node name="ReturnTeleporter" parent="." instance=ExtResource("4_teleporter")] -transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -5.5, 0.5, 0) +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -5.5, 0, 0) target_scene_path = "res://scenes/Levels/level.tscn" From 4ba06bf7e0ecce176c5773719001f3324d801825 Mon Sep 17 00:00:00 2001 From: Zeeshaun Date: Fri, 13 Mar 2026 10:25:43 -0500 Subject: [PATCH 06/19] Fixing data driven level, that was blown away --- game/scenes/UI/character_screen.gd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/game/scenes/UI/character_screen.gd b/game/scenes/UI/character_screen.gd index 2bc6502..7723b95 100644 --- a/game/scenes/UI/character_screen.gd +++ b/game/scenes/UI/character_screen.gd @@ -110,7 +110,7 @@ func _on_select_button_pressed() -> void: var character: Dictionary = _characters[index] SelectedCharacter.set_character(character) - get_tree().change_scene_to_file("res://scenes/Levels/transportation_level.tscn") + get_tree().change_scene_to_file("res://scenes/Levels/location_level.tscn") func _on_refresh_button_pressed() -> void: _load_characters() From 84f808764762f38204b3cbd43c31025436ea4a74 Mon Sep 17 00:00:00 2001 From: Zeeshaun Date: Fri, 13 Mar 2026 10:49:57 -0500 Subject: [PATCH 07/19] Adding endpoint to only get locations visible to character --- .../kenney_prototype_gateway_orange.tres | 8 + game/scenes/Characters/location_player.gd | 249 +++++++++++++++++ game/scenes/Characters/location_player.gd.uid | 1 + game/scenes/Characters/location_player.tscn | 28 ++ game/scenes/Interaction/prototype_gateway.gd | 31 +++ .../Interaction/prototype_gateway.gd.uid | 1 + .../scenes/Interaction/prototype_gateway.tscn | 117 ++++++++ game/scenes/Levels/location_level.gd | 258 ++++++++++++++++++ game/scenes/Levels/location_level.gd.uid | 1 + game/scenes/Levels/location_level.tscn | 32 +++ .../Controllers/CharactersController.cs | 50 ++-- microservices/CharacterApi/DOCUMENTS.md | 42 ++- .../CharacterApi/Models/Character.cs | 2 + .../CharacterApi/Models/VisibleLocation.cs | 17 ++ microservices/CharacterApi/README.md | 1 + .../CharacterApi/Services/CharacterStore.cs | 78 ++++-- 16 files changed, 865 insertions(+), 51 deletions(-) create mode 100644 game/assets/materials/kenney_prototype_gateway_orange.tres create mode 100644 game/scenes/Characters/location_player.gd create mode 100644 game/scenes/Characters/location_player.gd.uid create mode 100644 game/scenes/Characters/location_player.tscn create mode 100644 game/scenes/Interaction/prototype_gateway.gd create mode 100644 game/scenes/Interaction/prototype_gateway.gd.uid create mode 100644 game/scenes/Interaction/prototype_gateway.tscn create mode 100644 game/scenes/Levels/location_level.gd create mode 100644 game/scenes/Levels/location_level.gd.uid create mode 100644 game/scenes/Levels/location_level.tscn create mode 100644 microservices/CharacterApi/Models/VisibleLocation.cs diff --git a/game/assets/materials/kenney_prototype_gateway_orange.tres b/game/assets/materials/kenney_prototype_gateway_orange.tres new file mode 100644 index 0000000..f2caac3 --- /dev/null +++ b/game/assets/materials/kenney_prototype_gateway_orange.tres @@ -0,0 +1,8 @@ +[gd_resource type="StandardMaterial3D" load_steps=2 format=3] + +[ext_resource type="Texture2D" path="res://assets/textures/kenney_prototype/PNG/Orange/texture_08.png" id="1_gateway"] + +[resource] +albedo_texture = ExtResource("1_gateway") +uv1_triplanar = true +uv1_scale = Vector3(1, 1, 1) diff --git a/game/scenes/Characters/location_player.gd b/game/scenes/Characters/location_player.gd new file mode 100644 index 0000000..36ad8df --- /dev/null +++ b/game/scenes/Characters/location_player.gd @@ -0,0 +1,249 @@ +extends RigidBody3D +# Initially I used a CharacterBody3D, however, I wanted the player to bounce off +# other objects in the environment and that would have required manual handling +# of collisions. So that's why we're using a RigidBody3D instead. +signal vehicle_entered(vehicle: Node) +signal vehicle_exited(vehicle: Node) + +const MOVE_SPEED := 8.0 +const SPRINT_MOVE_SPEED :=13 +const ACCELLERATION := 30.0 +const DECELLERATION := 40.0 +const JUMP_SPEED := 4.0 +const MAX_NUMBER_OF_JUMPS := 2 +const MIN_FOV := 10.0 +const MAX_FOV := 179.0 +const ZOOM_FACTOR := 1.1 # Zoom out when >1, in when < 1 +var mouse_sensitivity := 0.005 +var rotation_x := 0.0 +var rotation_y := 0.0 +var cameraMoveMode := false +var current_number_of_jumps := 0 +var _pending_mouse_delta := Vector2.ZERO +var _last_move_forward := Vector3(0, 0, 1) +var _last_move_right := Vector3(1, 0, 0) +var _camera_offset_local := Vector3.ZERO +var _camera_yaw := 0.0 +var _camera_pitch := 0.0 +var _in_vehicle := false +var _vehicle_collision_layer := 0 +var _vehicle_collision_mask := 0 +var _vehicle_original_parent: Node = null +var _light_was_on := false +var _jump_triggered := false +@onready var _flashlight: SpotLight3D = $SpotLight3D +@onready var _anim_player: AnimationPlayer = find_child("AnimationPlayer", true, false) as AnimationPlayer +@onready var _anim_tree: AnimationTree = find_child("AnimationTree", true, false) as AnimationTree +@onready var _model_root: Node3D = find_child("TestCharAnimated", true, false) as Node3D + +@export var camera_follow_speed := 10.0 +@export var anim_idle_name := "Idle" +@export var anim_walk_name := "Walk" +@export var anim_jump_name := "Jump" +@export var anim_run_name := "Run" +@export var anim_walk_speed_threshold := 0.25 +@export var anim_sprint_speed_threshold := 10.0 + +var jump_sound = preload("res://assets/audio/jump.ogg") +var audio_player = AudioStreamPlayer.new() + +@export var camera_path: NodePath +@onready var cam: Camera3D = get_node(camera_path) if camera_path != NodePath("") else null +@export var phone_path: NodePath +@onready var phone: CanvasLayer = get_node(phone_path) if phone_path != NodePath("") else null +var phone_visible := false + +func _ready() -> void: + add_to_group("player") + if _anim_tree: + _anim_tree.active = false + axis_lock_angular_x = true + axis_lock_angular_z = true + angular_damp = 6.0 + contact_monitor = true + max_contacts_reported = 4 + add_child(audio_player) + audio_player.stream = jump_sound + audio_player.volume_db = -20 + if cam: + _camera_offset_local = cam.transform.origin + _camera_pitch = cam.rotation.x + _camera_yaw = global_transform.basis.get_euler().y + cam.set_as_top_level(true) + cam.global_position = global_position + (Basis(Vector3.UP, _camera_yaw) * _camera_offset_local) + cam.global_rotation = Vector3(_camera_pitch, _camera_yaw, 0.0) + var move_basis := cam.global_transform.basis if cam else global_transform.basis + var forward := move_basis.z + var right := move_basis.x + forward.y = 0.0 + right.y = 0.0 + if forward.length() > 0.0001: + _last_move_forward = forward.normalized() + if right.length() > 0.0001: + _last_move_right = right.normalized() + _vehicle_collision_layer = collision_layer + _vehicle_collision_mask = collision_mask + +func _integrate_forces(state): + if _in_vehicle: + linear_velocity = Vector3.ZERO + return + if cameraMoveMode and _pending_mouse_delta != Vector2.ZERO: + rotation_x -= _pending_mouse_delta.y * mouse_sensitivity + rotation_y -= _pending_mouse_delta.x * mouse_sensitivity + rotation_x = clamp(rotation_x, deg_to_rad(-90), deg_to_rad(90)) + _camera_pitch = rotation_x + rotation.y = rotation_y + _pending_mouse_delta = Vector2.ZERO + + var input2v := Input.get_vector("ui_left", "ui_right", "ui_up", "ui_down") + var forward := Vector3.FORWARD * -1.0 + var right := Vector3.RIGHT + if cam: + forward = cam.global_transform.basis.z + right = cam.global_transform.basis.x + forward.y = 0.0 + right.y = 0.0 + if forward.length() > 0.0001: + forward = forward.normalized() + _last_move_forward = forward + else: + forward = _last_move_forward + if right.length() > 0.0001: + right = right.normalized() + _last_move_right = right + else: + right = _last_move_right + + var dir := (right * input2v.x + forward * input2v.y).normalized() + var target_v := dir * MOVE_SPEED + if Input.is_key_pressed(KEY_SHIFT): + target_v = dir * SPRINT_MOVE_SPEED + + var ax := ACCELLERATION if dir != Vector3.ZERO else DECELLERATION + linear_velocity.x = move_toward(linear_velocity.x, target_v.x, ax * state.step) + linear_velocity.z = move_toward(linear_velocity.z, target_v.z, ax * state.step) + + var on_floor = false + for i in state.get_contact_count(): + var normal = state.get_contact_local_normal(i) + if normal.y > 0.5: + on_floor = true + break + + if Input.is_action_just_pressed("ui_accept") and (on_floor or current_number_of_jumps == 1): + current_number_of_jumps = (current_number_of_jumps + 1) % 2 + linear_velocity.y = JUMP_SPEED + audio_player.play() + _jump_triggered = true + + if cam: + var target_yaw := global_transform.basis.get_euler().y + _camera_yaw = lerp_angle(_camera_yaw, target_yaw, camera_follow_speed * state.step) + var target_basis := Basis(Vector3.UP, _camera_yaw) + var target_pos := global_position + (target_basis * _camera_offset_local) + cam.global_position = cam.global_position.lerp(target_pos, camera_follow_speed * state.step) + cam.global_rotation = Vector3(_camera_pitch, _camera_yaw, 0.0) + + _update_animation(on_floor, state.linear_velocity) + _jump_triggered = false + +func _input(event): + if event.is_action_pressed("player_phone"): + phone_visible = !phone_visible + if phone: + phone.visible = phone_visible + return + + if _in_vehicle: + return + if event is InputEventMouseButton: + if event.button_index == MOUSE_BUTTON_MIDDLE: + if event.pressed: + cameraMoveMode = true + Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED) + else: + cameraMoveMode = false + Input.set_mouse_mode(Input.MOUSE_MODE_VISIBLE) + + if event is InputEventMouseMotion and cameraMoveMode: + _pending_mouse_delta += event.relative + + if event is InputEventMouseButton and event.pressed: + if event.button_index == MOUSE_BUTTON_WHEEL_UP: + zoom_camera(1.0 / ZOOM_FACTOR) + elif event.button_index == MOUSE_BUTTON_WHEEL_DOWN: + zoom_camera(ZOOM_FACTOR) + + if event.is_action_pressed("player_light"): + _flashlight.visible = !_flashlight.visible + +func zoom_camera(factor): + if cam == null: + return + var new_fov = cam.fov * factor + cam.fov = clamp(new_fov, MIN_FOV, MAX_FOV) + +func _update_animation(on_floor: bool, velocity: Vector3) -> void: + if _anim_player == null: + return + var horizontal_speed := Vector3(velocity.x, 0.0, velocity.z).length() + if _jump_triggered and _anim_player.has_animation(anim_jump_name): + if _anim_player.current_animation != anim_jump_name: + _anim_player.play(anim_jump_name) + return + if not on_floor and _anim_player.has_animation(anim_jump_name): + if _anim_player.current_animation != anim_jump_name: + _anim_player.play(anim_jump_name) + return + if on_floor and horizontal_speed > anim_sprint_speed_threshold and _anim_player.has_animation(anim_run_name): + if _anim_player.current_animation != anim_run_name: + _anim_player.play(anim_run_name) + return + if horizontal_speed > anim_walk_speed_threshold and _anim_player.has_animation(anim_walk_name): + if _anim_player.current_animation != anim_walk_name: + _anim_player.play(anim_walk_name) + return + if _anim_player.has_animation(anim_idle_name): + if _anim_player.current_animation != anim_idle_name: + _anim_player.play(anim_idle_name) + +func enter_vehicle(_vehicle: Node, seat: Node3D, vehicle_camera: Camera3D) -> void: + _in_vehicle = true + freeze = true + sleeping = true + collision_layer = 0 + collision_mask = 0 + _vehicle_original_parent = get_parent() + _light_was_on = _flashlight.visible + _flashlight.visible = false + if _model_root: + _model_root.visible = false + if seat: + reparent(seat, true) + global_transform = seat.global_transform + if cam: + cam.current = false + if vehicle_camera: + vehicle_camera.current = true + vehicle_entered.emit(_vehicle) + +func exit_vehicle(exit_point: Node3D, vehicle_camera: Camera3D) -> void: + _in_vehicle = false + freeze = false + sleeping = false + collision_layer = _vehicle_collision_layer + collision_mask = _vehicle_collision_mask + if _vehicle_original_parent: + reparent(_vehicle_original_parent, true) + _vehicle_original_parent = null + _flashlight.visible = _light_was_on + if _model_root: + _model_root.visible = true + if exit_point: + global_transform = exit_point.global_transform + if vehicle_camera: + vehicle_camera.current = false + if cam: + cam.current = true + vehicle_exited.emit(null) diff --git a/game/scenes/Characters/location_player.gd.uid b/game/scenes/Characters/location_player.gd.uid new file mode 100644 index 0000000..df1190e --- /dev/null +++ b/game/scenes/Characters/location_player.gd.uid @@ -0,0 +1 @@ +uid://kgqaeqappow3 diff --git a/game/scenes/Characters/location_player.tscn b/game/scenes/Characters/location_player.tscn new file mode 100644 index 0000000..84e4288 --- /dev/null +++ b/game/scenes/Characters/location_player.tscn @@ -0,0 +1,28 @@ +[gd_scene load_steps=4 format=3] + +[ext_resource type="Script" path="res://scenes/Characters/location_player.gd" id="1_player_script"] +[ext_resource type="PackedScene" path="res://assets/models/TestCharAnimated.glb" id="2_model"] + +[sub_resource type="SphereShape3D" id="SphereShape3D_player"] + +[node name="LocationPlayer" type="RigidBody3D"] +script = ExtResource("1_player_script") +camera_path = NodePath("Camera3D") + +[node name="CollisionShape3D" type="CollisionShape3D" parent="."] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.5, 0) +shape = SubResource("SphereShape3D_player") + +[node name="TestCharAnimated" parent="." instance=ExtResource("2_model")] +transform = Transform3D(-0.9998549, 0, 0.01703362, 0, 1, 0, -0.01703362, 0, -0.9998549, 0, 0, 0) + +[node name="Camera3D" type="Camera3D" parent="."] +transform = Transform3D(0.9998477, 0, -0.017452406, 0.0066714617, 0.9238795, 0.38262552, 0.016124869, -0.38268343, 0.92373866, 0, 6, 10) +current = true +fov = 49.0 + +[node name="SpotLight3D" type="SpotLight3D" parent="."] +transform = Transform3D(1, 0, 0, 0, 0.906308, -0.422618, 0, 0.422618, 0.906308, 0, 1.7, -0.35) +visible = false +spot_range = 30.0 +spot_angle = 25.0 diff --git a/game/scenes/Interaction/prototype_gateway.gd b/game/scenes/Interaction/prototype_gateway.gd new file mode 100644 index 0000000..c9fb601 --- /dev/null +++ b/game/scenes/Interaction/prototype_gateway.gd @@ -0,0 +1,31 @@ +@tool +extends Node3D + +@export_file("*.tscn") var target_scene_path := "res://scenes/Levels/transportation_level.tscn": + set(value): + target_scene_path = value + _sync_teleporter() + +@export var target_group: StringName = &"player": + set(value): + target_group = value + _sync_teleporter() + +@export var one_shot := true: + set(value): + one_shot = value + _sync_teleporter() + +@onready var teleporter: Area3D = $Teleporter + + +func _ready() -> void: + _sync_teleporter() + + +func _sync_teleporter() -> void: + if teleporter == null: + return + teleporter.set("target_scene_path", target_scene_path) + teleporter.set("target_group", target_group) + teleporter.set("one_shot", one_shot) diff --git a/game/scenes/Interaction/prototype_gateway.gd.uid b/game/scenes/Interaction/prototype_gateway.gd.uid new file mode 100644 index 0000000..5c8c348 --- /dev/null +++ b/game/scenes/Interaction/prototype_gateway.gd.uid @@ -0,0 +1 @@ +uid://1c0reto6vt6m diff --git a/game/scenes/Interaction/prototype_gateway.tscn b/game/scenes/Interaction/prototype_gateway.tscn new file mode 100644 index 0000000..e7e9be5 --- /dev/null +++ b/game/scenes/Interaction/prototype_gateway.tscn @@ -0,0 +1,117 @@ +[gd_scene load_steps=6 format=3] + +[ext_resource type="Script" path="res://scenes/Interaction/prototype_gateway.gd" id="1_gateway_script"] +[ext_resource type="PackedScene" path="res://scenes/Interaction/scene_teleporter.tscn" id="2_teleporter"] +[ext_resource type="Material" path="res://assets/materials/kenney_prototype_gateway_orange.tres" id="3_gateway_mat"] + +[sub_resource type="BoxShape3D" id="BoxShape3D_gateway"] +size = Vector3(1, 1, 1) + +[sub_resource type="BoxMesh" id="BoxMesh_gateway"] +material = ExtResource("3_gateway_mat") +size = Vector3(1, 1, 1) + +[node name="PrototypeGateway" type="Node3D"] +script = ExtResource("1_gateway_script") + +[node name="LeftBase" type="StaticBody3D" parent="."] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -2, 0.5, 0) + +[node name="CollisionShape3D" type="CollisionShape3D" parent="LeftBase"] +shape = SubResource("BoxShape3D_gateway") + +[node name="MeshInstance3D" type="MeshInstance3D" parent="LeftBase"] +mesh = SubResource("BoxMesh_gateway") + +[node name="LeftMidLow" type="StaticBody3D" parent="."] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -2, 1.5, 0) + +[node name="CollisionShape3D" type="CollisionShape3D" parent="LeftMidLow"] +shape = SubResource("BoxShape3D_gateway") + +[node name="MeshInstance3D" type="MeshInstance3D" parent="LeftMidLow"] +mesh = SubResource("BoxMesh_gateway") + +[node name="LeftMidHigh" type="StaticBody3D" parent="."] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -2, 2.5, 0) + +[node name="CollisionShape3D" type="CollisionShape3D" parent="LeftMidHigh"] +shape = SubResource("BoxShape3D_gateway") + +[node name="MeshInstance3D" type="MeshInstance3D" parent="LeftMidHigh"] +mesh = SubResource("BoxMesh_gateway") + +[node name="LeftTop" type="StaticBody3D" parent="."] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -2, 3.5, 0) + +[node name="CollisionShape3D" type="CollisionShape3D" parent="LeftTop"] +shape = SubResource("BoxShape3D_gateway") + +[node name="MeshInstance3D" type="MeshInstance3D" parent="LeftTop"] +mesh = SubResource("BoxMesh_gateway") + +[node name="RightBase" type="StaticBody3D" parent="."] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 2, 0.5, 0) + +[node name="CollisionShape3D" type="CollisionShape3D" parent="RightBase"] +shape = SubResource("BoxShape3D_gateway") + +[node name="MeshInstance3D" type="MeshInstance3D" parent="RightBase"] +mesh = SubResource("BoxMesh_gateway") + +[node name="RightMidLow" type="StaticBody3D" parent="."] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 2, 1.5, 0) + +[node name="CollisionShape3D" type="CollisionShape3D" parent="RightMidLow"] +shape = SubResource("BoxShape3D_gateway") + +[node name="MeshInstance3D" type="MeshInstance3D" parent="RightMidLow"] +mesh = SubResource("BoxMesh_gateway") + +[node name="RightMidHigh" type="StaticBody3D" parent="."] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 2, 2.5, 0) + +[node name="CollisionShape3D" type="CollisionShape3D" parent="RightMidHigh"] +shape = SubResource("BoxShape3D_gateway") + +[node name="MeshInstance3D" type="MeshInstance3D" parent="RightMidHigh"] +mesh = SubResource("BoxMesh_gateway") + +[node name="RightTop" type="StaticBody3D" parent="."] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 2, 3.5, 0) + +[node name="CollisionShape3D" type="CollisionShape3D" parent="RightTop"] +shape = SubResource("BoxShape3D_gateway") + +[node name="MeshInstance3D" type="MeshInstance3D" parent="RightTop"] +mesh = SubResource("BoxMesh_gateway") + +[node name="TopLeft" type="StaticBody3D" parent="."] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -1, 4.5, 0) + +[node name="CollisionShape3D" type="CollisionShape3D" parent="TopLeft"] +shape = SubResource("BoxShape3D_gateway") + +[node name="MeshInstance3D" type="MeshInstance3D" parent="TopLeft"] +mesh = SubResource("BoxMesh_gateway") + +[node name="TopCenter" type="StaticBody3D" parent="."] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 4.5, 0) + +[node name="CollisionShape3D" type="CollisionShape3D" parent="TopCenter"] +shape = SubResource("BoxShape3D_gateway") + +[node name="MeshInstance3D" type="MeshInstance3D" parent="TopCenter"] +mesh = SubResource("BoxMesh_gateway") + +[node name="TopRight" type="StaticBody3D" parent="."] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 4.5, 0) + +[node name="CollisionShape3D" type="CollisionShape3D" parent="TopRight"] +shape = SubResource("BoxShape3D_gateway") + +[node name="MeshInstance3D" type="MeshInstance3D" parent="TopRight"] +mesh = SubResource("BoxMesh_gateway") + +[node name="Teleporter" parent="." instance=ExtResource("2_teleporter")] +transform = Transform3D(1.15, 0, 0, 0, 1.33, 0, 0, 0, 0.7, 0, 1.5, 0) diff --git a/game/scenes/Levels/location_level.gd b/game/scenes/Levels/location_level.gd new file mode 100644 index 0000000..38858af --- /dev/null +++ b/game/scenes/Levels/location_level.gd @@ -0,0 +1,258 @@ +extends Node3D + +const CHARACTER_API_URL := "https://pchar.ranaze.com/api/Characters" + +@export var tile_size := 4.0 +@export var block_height := 1.0 +@export_range(1, 8, 1) var tile_radius := 3 +@export var tracked_node_path: NodePath +@export var player_spawn_height := 2.0 +@export var border_color: Color = Color(0.05, 0.05, 0.05, 1.0) +@export var border_height_bias := 0.005 +@export var show_tile_labels := true +@export var tile_label_height := 0.01 +@export var tile_label_color: Color = Color(1, 1, 1, 1) + +@onready var _block: MeshInstance3D = $TerrainBlock +@onready var _player: RigidBody3D = $Player +@onready var _camera: Camera3D = $Player/Camera3D + +var _center_coord := Vector2i.ZERO +var _tiles_root: Node3D +var _tracked_node: Node3D +var _tile_nodes: Dictionary = {} +var _camera_start_offset := Vector3(0.0, 6.0, 10.0) +var _border_material: StandardMaterial3D +var _known_locations: Dictionary = {} +var _locations_loaded := false + + +func _ready() -> void: + _tiles_root = Node3D.new() + _tiles_root.name = "GeneratedTiles" + add_child(_tiles_root) + + if _camera: + _camera_start_offset = _camera.position + + _tracked_node = get_node_or_null(tracked_node_path) as Node3D + if _tracked_node == null: + _tracked_node = _player + + var start_coord := SelectedCharacter.get_coord() + _center_coord = Vector2i(roundi(start_coord.x), roundi(start_coord.y)) + + _block.visible = false + await _load_existing_locations() + _ensure_selected_location_exists(_center_coord) + _rebuild_tiles(_center_coord) + _move_player_to_coord(_center_coord) + + +func _process(_delta: float) -> void: + if not _locations_loaded: + return + var target_world_pos := _get_stream_position() + var target_coord := _world_to_coord(target_world_pos) + if target_coord == _center_coord: + return + _center_coord = target_coord + _rebuild_tiles(_center_coord) + + +func _get_stream_position() -> Vector3: + if _tracked_node: + return _tracked_node.global_position + return _coord_to_world(_center_coord) + + +func _world_to_coord(world_pos: Vector3) -> Vector2i: + return Vector2i( + roundi(world_pos.x / tile_size), + roundi(world_pos.z / tile_size) + ) + + +func _coord_to_world(coord: Vector2i) -> Vector3: + return Vector3(coord.x * tile_size, block_height * 0.5, coord.y * tile_size) + + +func _move_player_to_coord(coord: Vector2i) -> void: + if _player == null: + return + _player.global_position = Vector3(coord.x * tile_size, player_spawn_height, coord.y * tile_size) + _player.linear_velocity = Vector3.ZERO + _player.angular_velocity = Vector3.ZERO + + +func _rebuild_tiles(center: Vector2i) -> void: + var wanted_keys: Dictionary = {} + for x in range(center.x - tile_radius, center.x + tile_radius + 1): + for y in range(center.y - tile_radius, center.y + tile_radius + 1): + var coord := Vector2i(x, y) + if not _known_locations.has(coord): + continue + wanted_keys[coord] = true + if _tile_nodes.has(coord): + continue + _spawn_tile(coord, String(_known_locations[coord])) + + for key in _tile_nodes.keys(): + if wanted_keys.has(key): + continue + var tile_node := _tile_nodes[key] as Node3D + if tile_node: + tile_node.queue_free() + _tile_nodes.erase(key) + + +func _spawn_tile(coord: Vector2i, location_name: String) -> void: + var tile_root := Node3D.new() + tile_root.name = "Tile_%d_%d" % [coord.x, coord.y] + tile_root.position = _coord_to_world(coord) + _tiles_root.add_child(tile_root) + + var tile_body := StaticBody3D.new() + tile_body.name = "TileBody" + tile_body.scale = Vector3(tile_size, block_height, tile_size) + tile_root.add_child(tile_body) + + var collision_shape := CollisionShape3D.new() + collision_shape.name = "CollisionShape3D" + collision_shape.shape = BoxShape3D.new() + tile_body.add_child(collision_shape) + + var tile := _block.duplicate() as MeshInstance3D + tile.name = "TileMesh" + tile.visible = true + tile_body.add_child(tile) + + tile.add_child(_create_tile_border()) + if show_tile_labels: + tile_root.add_child(_create_tile_label(location_name)) + + _tile_nodes[coord] = tile_root + + +func _create_tile_border() -> MeshInstance3D: + var top_y := 0.5 + border_height_bias + var corners := [ + Vector3(-0.5, top_y, -0.5), + Vector3(0.5, top_y, -0.5), + Vector3(0.5, top_y, 0.5), + Vector3(-0.5, top_y, 0.5), + ] + + var border_mesh := ImmediateMesh.new() + border_mesh.surface_begin(Mesh.PRIMITIVE_LINES, _get_border_material()) + for idx in range(corners.size()): + var current: Vector3 = corners[idx] + var next: Vector3 = corners[(idx + 1) % corners.size()] + border_mesh.surface_add_vertex(current) + border_mesh.surface_add_vertex(next) + border_mesh.surface_end() + + var border := MeshInstance3D.new() + border.name = "TileBorder" + border.mesh = border_mesh + return border + + +func _get_border_material() -> StandardMaterial3D: + if _border_material: + return _border_material + + _border_material = StandardMaterial3D.new() + _border_material.albedo_color = border_color + _border_material.shading_mode = BaseMaterial3D.SHADING_MODE_UNSHADED + _border_material.disable_receive_shadows = true + _border_material.no_depth_test = true + return _border_material + + +func _create_tile_label(location_name: String) -> Label3D: + var label := Label3D.new() + label.name = "LocationNameLabel" + label.text = location_name + label.position = Vector3(0.0, (block_height * 0.5) + border_height_bias + tile_label_height, 0.0) + label.rotation_degrees = Vector3(-90.0, 0.0, 0.0) + label.billboard = BaseMaterial3D.BILLBOARD_DISABLED + label.modulate = tile_label_color + label.pixel_size = 0.01 + label.outline_size = 12 + label.no_depth_test = false + return label + + +func _ensure_selected_location_exists(coord: Vector2i) -> void: + if _known_locations.has(coord): + return + _known_locations[coord] = _selected_location_name(coord) + + +func _selected_location_name(coord: Vector2i) -> String: + var selected_name := String(SelectedCharacter.character.get("locationName", "")).strip_edges() + if not selected_name.is_empty(): + return selected_name + var character_name := String(SelectedCharacter.character.get("name", "")).strip_edges() + if not character_name.is_empty(): + return "%s's Location" % character_name + return "Location %d,%d" % [coord.x, coord.y] + + +func _load_existing_locations() -> void: + _locations_loaded = false + _known_locations.clear() + + var character_id := String(SelectedCharacter.character.get("id", SelectedCharacter.character.get("Id", ""))).strip_edges() + if character_id.is_empty(): + push_warning("Selected character is missing an id; cannot load visible locations.") + _locations_loaded = true + return + + var request := HTTPRequest.new() + add_child(request) + + var headers := PackedStringArray() + if not AuthState.access_token.is_empty(): + headers.append("Authorization: Bearer %s" % AuthState.access_token) + + var err := request.request("%s/%s/visible-locations" % [CHARACTER_API_URL, character_id], headers, HTTPClient.METHOD_GET) + if err != OK: + push_warning("Failed to request visible locations: %s" % err) + request.queue_free() + _locations_loaded = true + return + + var result: Array = await request.request_completed + request.queue_free() + + var result_code: int = result[0] + var response_code: int = result[1] + var response_body: String = result[3].get_string_from_utf8() + if result_code != HTTPRequest.RESULT_SUCCESS or response_code < 200 or response_code >= 300: + push_warning("Failed to load visible locations (%s/%s): %s" % [result_code, response_code, response_body]) + _locations_loaded = true + return + + var parsed: Variant = JSON.parse_string(response_body) + if typeof(parsed) != TYPE_ARRAY: + push_warning("Visible locations response was not an array.") + _locations_loaded = true + return + + for item in parsed: + if typeof(item) != TYPE_DICTIONARY: + continue + var location := item as Dictionary + var coord_variant: Variant = location.get("coord", {}) + if typeof(coord_variant) != TYPE_DICTIONARY: + continue + var coord_dict := coord_variant as Dictionary + var coord := Vector2i(int(coord_dict.get("x", 0)), int(coord_dict.get("y", 0))) + var location_name := String(location.get("name", "")).strip_edges() + if location_name.is_empty(): + location_name = "Location %d,%d" % [coord.x, coord.y] + _known_locations[coord] = location_name + + _locations_loaded = true diff --git a/game/scenes/Levels/location_level.gd.uid b/game/scenes/Levels/location_level.gd.uid new file mode 100644 index 0000000..b39fb3a --- /dev/null +++ b/game/scenes/Levels/location_level.gd.uid @@ -0,0 +1 @@ +uid://ctbyn1gws2ahj diff --git a/game/scenes/Levels/location_level.tscn b/game/scenes/Levels/location_level.tscn new file mode 100644 index 0000000..acba1dd --- /dev/null +++ b/game/scenes/Levels/location_level.tscn @@ -0,0 +1,32 @@ +[gd_scene load_steps=8 format=3] + +[ext_resource type="Script" path="res://scenes/Levels/location_level.gd" id="1_level_script"] +[ext_resource type="PackedScene" path="res://scenes/Characters/location_player.tscn" id="2_player_scene"] +[ext_resource type="Material" path="res://assets/materials/kenney_prototype_block_dark.tres" id="3_block_mat"] + +[sub_resource type="BoxMesh" id="BoxMesh_tile"] +material = ExtResource("3_block_mat") +size = Vector3(1, 1, 1) + +[sub_resource type="Environment" id="Environment_location"] +background_mode = 1 +background_color = Color(0.55, 0.72, 0.92, 1) +ambient_light_source = 2 +ambient_light_color = Color(1, 1, 1, 1) +ambient_light_energy = 0.8 + +[node name="LocationLevel" type="Node3D"] +script = ExtResource("1_level_script") +tracked_node_path = NodePath("Player") + +[node name="TerrainBlock" type="MeshInstance3D" parent="."] +mesh = SubResource("BoxMesh_tile") + +[node name="Player" parent="." instance=ExtResource("2_player_scene")] + +[node name="DirectionalLight3D" type="DirectionalLight3D" parent="."] +transform = Transform3D(1, 0, 0, 0, 0.819152, 0.573576, 0, -0.573576, 0.819152, 0, 6, 0) +shadow_enabled = true + +[node name="WorldEnvironment" type="WorldEnvironment" parent="."] +environment = SubResource("Environment_location") diff --git a/microservices/CharacterApi/Controllers/CharactersController.cs b/microservices/CharacterApi/Controllers/CharactersController.cs index 060edc4..a28eeb9 100644 --- a/microservices/CharacterApi/Controllers/CharactersController.cs +++ b/microservices/CharacterApi/Controllers/CharactersController.cs @@ -19,10 +19,10 @@ public class CharactersController : ControllerBase [HttpPost] [Authorize(Roles = "USER,SUPER")] - public async Task Create([FromBody] CreateCharacterRequest req) - { - if (string.IsNullOrWhiteSpace(req.Name)) - return BadRequest("Name required"); + public async Task Create([FromBody] CreateCharacterRequest req) + { + if (string.IsNullOrWhiteSpace(req.Name)) + return BadRequest("Name required"); var userId = User.FindFirstValue(ClaimTypes.NameIdentifier); if (string.IsNullOrWhiteSpace(userId)) @@ -33,6 +33,7 @@ public class CharactersController : ControllerBase OwnerUserId = userId, Name = req.Name.Trim(), Coord = new Coord { X = 0, Y = 0 }, + VisionRadius = 3, CreatedUtc = DateTime.UtcNow }; @@ -42,19 +43,36 @@ public class CharactersController : ControllerBase [HttpGet] [Authorize(Roles = "USER,SUPER")] - public async Task ListMine() - { - var userId = User.FindFirstValue(ClaimTypes.NameIdentifier); - if (string.IsNullOrWhiteSpace(userId)) - return Unauthorized(); + public async Task ListMine() + { + var userId = User.FindFirstValue(ClaimTypes.NameIdentifier); + if (string.IsNullOrWhiteSpace(userId)) + return Unauthorized(); - var characters = await _characters.GetForOwnerAsync(userId); - return Ok(characters); - } - - [HttpDelete("{id}")] - [Authorize(Roles = "USER,SUPER")] - public async Task Delete(string id) + var characters = await _characters.GetForOwnerAsync(userId); + return Ok(characters); + } + + [HttpGet("{id}/visible-locations")] + [Authorize(Roles = "USER,SUPER")] + public async Task VisibleLocations(string id) + { + var userId = User.FindFirstValue(ClaimTypes.NameIdentifier); + if (string.IsNullOrWhiteSpace(userId)) + return Unauthorized(); + + var allowAnyOwner = User.IsInRole("SUPER"); + var character = await _characters.GetForOwnerByIdAsync(id, userId, allowAnyOwner); + if (character is null) + return NotFound(); + + var locations = await _characters.GetVisibleLocationsAsync(character); + return Ok(locations); + } + + [HttpDelete("{id}")] + [Authorize(Roles = "USER,SUPER")] + public async Task Delete(string id) { var userId = User.FindFirstValue(ClaimTypes.NameIdentifier); if (string.IsNullOrWhiteSpace(userId)) diff --git a/microservices/CharacterApi/DOCUMENTS.md b/microservices/CharacterApi/DOCUMENTS.md index 55315cf..9a1ea5e 100644 --- a/microservices/CharacterApi/DOCUMENTS.md +++ b/microservices/CharacterApi/DOCUMENTS.md @@ -12,16 +12,32 @@ Inbound JSON documents ``` Stored documents (MongoDB) -- Character - ```json - { - "id": "string (ObjectId)", - "ownerUserId": "string", - "name": "string", - "coord": { - "x": "number", - "y": "number" - }, - "createdUtc": "string (ISO-8601 datetime)" - } - ``` +- Character + ```json + { + "id": "string (ObjectId)", + "ownerUserId": "string", + "name": "string", + "coord": { + "x": "number", + "y": "number" + }, + "visionRadius": "number", + "createdUtc": "string (ISO-8601 datetime)" + } + ``` + +Outbound JSON documents +- VisibleLocation (`GET /api/characters/{id}/visible-locations`) + ```json + [ + { + "id": "string (ObjectId)", + "name": "string", + "coord": { + "x": "number", + "y": "number" + } + } + ] + ``` diff --git a/microservices/CharacterApi/Models/Character.cs b/microservices/CharacterApi/Models/Character.cs index d5ade03..2055e4a 100644 --- a/microservices/CharacterApi/Models/Character.cs +++ b/microservices/CharacterApi/Models/Character.cs @@ -15,5 +15,7 @@ public class Character public Coord Coord { get; set; } = new(); + public int VisionRadius { get; set; } = 3; + public DateTime CreatedUtc { get; set; } = DateTime.UtcNow; } diff --git a/microservices/CharacterApi/Models/VisibleLocation.cs b/microservices/CharacterApi/Models/VisibleLocation.cs new file mode 100644 index 0000000..36d1b26 --- /dev/null +++ b/microservices/CharacterApi/Models/VisibleLocation.cs @@ -0,0 +1,17 @@ +using MongoDB.Bson; +using MongoDB.Bson.Serialization.Attributes; + +namespace CharacterApi.Models; + +public class VisibleLocation +{ + [BsonId] + [BsonRepresentation(BsonType.ObjectId)] + public string? Id { get; set; } + + [BsonElement("name")] + public string Name { get; set; } = string.Empty; + + [BsonElement("coord")] + public Coord Coord { get; set; } = new(); +} diff --git a/microservices/CharacterApi/README.md b/microservices/CharacterApi/README.md index 4c9db47..0cea884 100644 --- a/microservices/CharacterApi/README.md +++ b/microservices/CharacterApi/README.md @@ -6,4 +6,5 @@ See `DOCUMENTS.md` for request payloads and stored document shapes. ## Endpoints - `POST /api/characters` Create a character. - `GET /api/characters` List characters for the current user. +- `GET /api/characters/{id}/visible-locations` List locations visible to that owned character. - `DELETE /api/characters/{id}` Delete a character owned by the current user. diff --git a/microservices/CharacterApi/Services/CharacterStore.cs b/microservices/CharacterApi/Services/CharacterStore.cs index 433b438..d159452 100644 --- a/microservices/CharacterApi/Services/CharacterStore.cs +++ b/microservices/CharacterApi/Services/CharacterStore.cs @@ -3,31 +3,65 @@ using MongoDB.Driver; namespace CharacterApi.Services; -public class CharacterStore -{ - private readonly IMongoCollection _col; - - public CharacterStore(IConfiguration cfg) - { - var cs = cfg["MongoDB:ConnectionString"] ?? "mongodb://127.0.0.1:27017"; - var dbName = cfg["MongoDB:DatabaseName"] ?? "GameDb"; - var client = new MongoClient(cs); - var db = client.GetDatabase(dbName); - _col = db.GetCollection("Characters"); - - var ownerIndex = Builders.IndexKeys.Ascending(c => c.OwnerUserId); - _col.Indexes.CreateOne(new CreateIndexModel(ownerIndex)); - } +public class CharacterStore +{ + private readonly IMongoCollection _col; + private readonly IMongoCollection _locations; + + public CharacterStore(IConfiguration cfg) + { + var cs = cfg["MongoDB:ConnectionString"] ?? "mongodb://127.0.0.1:27017"; + var dbName = cfg["MongoDB:DatabaseName"] ?? "GameDb"; + var client = new MongoClient(cs); + var db = client.GetDatabase(dbName); + _col = db.GetCollection("Characters"); + _locations = db.GetCollection("Locations"); + + var ownerIndex = Builders.IndexKeys.Ascending(c => c.OwnerUserId); + _col.Indexes.CreateOne(new CreateIndexModel(ownerIndex)); + } public Task CreateAsync(Character character) => _col.InsertOneAsync(character); - public Task> GetForOwnerAsync(string ownerUserId) => - _col.Find(c => c.OwnerUserId == ownerUserId).ToListAsync(); - - public async Task DeleteForOwnerAsync(string id, string ownerUserId, bool allowAnyOwner) - { - var filter = Builders.Filter.Eq(c => c.Id, id); - if (!allowAnyOwner) + public Task> GetForOwnerAsync(string ownerUserId) => + _col.Find(c => c.OwnerUserId == ownerUserId).ToListAsync(); + + public async Task GetForOwnerByIdAsync(string id, string ownerUserId, bool allowAnyOwner) + { + var filter = Builders.Filter.Eq(c => c.Id, id); + if (!allowAnyOwner) + { + filter = Builders.Filter.And( + filter, + Builders.Filter.Eq(c => c.OwnerUserId, ownerUserId) + ); + } + + return await _col.Find(filter).FirstOrDefaultAsync(); + } + + public Task> GetVisibleLocationsAsync(Character character) + { + var radius = character.VisionRadius > 0 ? character.VisionRadius : 3; + var minX = character.Coord.X - radius; + var maxX = character.Coord.X + radius; + var minY = character.Coord.Y - radius; + var maxY = character.Coord.Y + radius; + + var filter = Builders.Filter.And( + Builders.Filter.Gte(l => l.Coord.X, minX), + Builders.Filter.Lte(l => l.Coord.X, maxX), + Builders.Filter.Gte(l => l.Coord.Y, minY), + Builders.Filter.Lte(l => l.Coord.Y, maxY) + ); + + return _locations.Find(filter).ToListAsync(); + } + + public async Task DeleteForOwnerAsync(string id, string ownerUserId, bool allowAnyOwner) + { + var filter = Builders.Filter.Eq(c => c.Id, id); + if (!allowAnyOwner) { filter = Builders.Filter.And( filter, From 097ef4a22c5b70dce8244873e1c56233315cd2da Mon Sep 17 00:00:00 2001 From: Zeeshaun Date: Fri, 13 Mar 2026 12:46:30 -0500 Subject: [PATCH 08/19] Adding endpoint to only get locations visible to character --- .../Controllers/CharactersController.cs | 2 +- microservices/CharacterApi/DOCUMENTS.md | 1 + microservices/CharacterApi/README.md | 2 +- .../CharacterApi/Services/CharacterStore.cs | 54 ++++++++++++++++++- 4 files changed, 55 insertions(+), 4 deletions(-) diff --git a/microservices/CharacterApi/Controllers/CharactersController.cs b/microservices/CharacterApi/Controllers/CharactersController.cs index a28eeb9..bea7bf2 100644 --- a/microservices/CharacterApi/Controllers/CharactersController.cs +++ b/microservices/CharacterApi/Controllers/CharactersController.cs @@ -66,7 +66,7 @@ public class CharactersController : ControllerBase if (character is null) return NotFound(); - var locations = await _characters.GetVisibleLocationsAsync(character); + var locations = await _characters.GetOrCreateVisibleLocationsAsync(character); return Ok(locations); } diff --git a/microservices/CharacterApi/DOCUMENTS.md b/microservices/CharacterApi/DOCUMENTS.md index 9a1ea5e..12c13f5 100644 --- a/microservices/CharacterApi/DOCUMENTS.md +++ b/microservices/CharacterApi/DOCUMENTS.md @@ -41,3 +41,4 @@ Outbound JSON documents } ] ``` + Missing locations within the character's vision window are created automatically before this response is returned. diff --git a/microservices/CharacterApi/README.md b/microservices/CharacterApi/README.md index 0cea884..9eede41 100644 --- a/microservices/CharacterApi/README.md +++ b/microservices/CharacterApi/README.md @@ -6,5 +6,5 @@ See `DOCUMENTS.md` for request payloads and stored document shapes. ## Endpoints - `POST /api/characters` Create a character. - `GET /api/characters` List characters for the current user. -- `GET /api/characters/{id}/visible-locations` List locations visible to that owned character. +- `GET /api/characters/{id}/visible-locations` Ensure and list locations visible to that owned character. - `DELETE /api/characters/{id}` Delete a character owned by the current user. diff --git a/microservices/CharacterApi/Services/CharacterStore.cs b/microservices/CharacterApi/Services/CharacterStore.cs index d159452..97c6005 100644 --- a/microservices/CharacterApi/Services/CharacterStore.cs +++ b/microservices/CharacterApi/Services/CharacterStore.cs @@ -1,5 +1,6 @@ -using CharacterApi.Models; -using MongoDB.Driver; +using CharacterApi.Models; +using MongoDB.Bson; +using MongoDB.Driver; namespace CharacterApi.Services; @@ -41,6 +42,17 @@ public class CharacterStore } public Task> GetVisibleLocationsAsync(Character character) + { + return GetVisibleLocationsInternalAsync(character, ensureGenerated: false); + } + + public async Task> GetOrCreateVisibleLocationsAsync(Character character) + { + await EnsureVisibleLocationsExistAsync(character); + return await GetVisibleLocationsInternalAsync(character, ensureGenerated: true); + } + + private Task> GetVisibleLocationsInternalAsync(Character character, bool ensureGenerated) { var radius = character.VisionRadius > 0 ? character.VisionRadius : 3; var minX = character.Coord.X - radius; @@ -58,6 +70,44 @@ public class CharacterStore return _locations.Find(filter).ToListAsync(); } + private async Task EnsureVisibleLocationsExistAsync(Character character) + { + var radius = character.VisionRadius > 0 ? character.VisionRadius : 3; + + for (var x = character.Coord.X - radius; x <= character.Coord.X + radius; x++) + { + for (var y = character.Coord.Y - radius; y <= character.Coord.Y + radius; y++) + { + var filter = Builders.Filter.And( + Builders.Filter.Eq(l => l.Coord.X, x), + Builders.Filter.Eq(l => l.Coord.Y, y) + ); + + var update = Builders.Update + .SetOnInsert(l => l.Name, DefaultLocationName(x, y)) + .SetOnInsert(l => l.Coord, new Coord { X = x, Y = y }) + .SetOnInsert(l => l.Id, ObjectId.GenerateNewId().ToString()) + .SetOnInsert("createdUtc", DateTime.UtcNow); + + try + { + await _locations.UpdateOneAsync(filter, update, new UpdateOptions { IsUpsert = true }); + } + catch (MongoWriteException ex) when (ex.WriteError.Category == ServerErrorCategory.DuplicateKey) + { + // Another request or service instance created it first. + } + } + } + } + + private static string DefaultLocationName(int x, int y) + { + if (x == 0 && y == 0) + return "Origin"; + return $"Location {x},{y}"; + } + public async Task DeleteForOwnerAsync(string id, string ownerUserId, bool allowAnyOwner) { var filter = Builders.Filter.Eq(c => c.Id, id); From d615527dcc5682f947909f3d172ad36223b02d0d Mon Sep 17 00:00:00 2001 From: Zeeshaun Date: Fri, 13 Mar 2026 13:00:50 -0500 Subject: [PATCH 09/19] Fixing coord bug --- microservices/CharacterApi/Models/Coord.cs | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/microservices/CharacterApi/Models/Coord.cs b/microservices/CharacterApi/Models/Coord.cs index d709ac7..e360290 100644 --- a/microservices/CharacterApi/Models/Coord.cs +++ b/microservices/CharacterApi/Models/Coord.cs @@ -1,8 +1,12 @@ -namespace CharacterApi.Models; - -public class Coord -{ - public int X { get; set; } - - public int Y { get; set; } -} +using MongoDB.Bson.Serialization.Attributes; + +namespace CharacterApi.Models; + +public class Coord +{ + [BsonElement("x")] + public int X { get; set; } + + [BsonElement("y")] + public int Y { get; set; } +} From c296ebc9cb692201a6ee98bae356101452cdbd5f Mon Sep 17 00:00:00 2001 From: Zeeshaun Date: Fri, 13 Mar 2026 13:14:30 -0500 Subject: [PATCH 10/19] Fixing coord bug --- microservices/CharacterApi/Models/Coord.cs | 4 ---- microservices/CharacterApi/Models/LocationCoord.cs | 12 ++++++++++++ microservices/CharacterApi/Models/VisibleLocation.cs | 2 +- .../CharacterApi/Services/CharacterStore.cs | 2 +- 4 files changed, 14 insertions(+), 6 deletions(-) create mode 100644 microservices/CharacterApi/Models/LocationCoord.cs diff --git a/microservices/CharacterApi/Models/Coord.cs b/microservices/CharacterApi/Models/Coord.cs index e360290..d9d7544 100644 --- a/microservices/CharacterApi/Models/Coord.cs +++ b/microservices/CharacterApi/Models/Coord.cs @@ -1,12 +1,8 @@ -using MongoDB.Bson.Serialization.Attributes; - namespace CharacterApi.Models; public class Coord { - [BsonElement("x")] public int X { get; set; } - [BsonElement("y")] public int Y { get; set; } } diff --git a/microservices/CharacterApi/Models/LocationCoord.cs b/microservices/CharacterApi/Models/LocationCoord.cs new file mode 100644 index 0000000..7a58ef5 --- /dev/null +++ b/microservices/CharacterApi/Models/LocationCoord.cs @@ -0,0 +1,12 @@ +using MongoDB.Bson.Serialization.Attributes; + +namespace CharacterApi.Models; + +public class LocationCoord +{ + [BsonElement("x")] + public int X { get; set; } + + [BsonElement("y")] + public int Y { get; set; } +} diff --git a/microservices/CharacterApi/Models/VisibleLocation.cs b/microservices/CharacterApi/Models/VisibleLocation.cs index 36d1b26..2087abf 100644 --- a/microservices/CharacterApi/Models/VisibleLocation.cs +++ b/microservices/CharacterApi/Models/VisibleLocation.cs @@ -13,5 +13,5 @@ public class VisibleLocation public string Name { get; set; } = string.Empty; [BsonElement("coord")] - public Coord Coord { get; set; } = new(); + public LocationCoord Coord { get; set; } = new(); } diff --git a/microservices/CharacterApi/Services/CharacterStore.cs b/microservices/CharacterApi/Services/CharacterStore.cs index 97c6005..aa220e2 100644 --- a/microservices/CharacterApi/Services/CharacterStore.cs +++ b/microservices/CharacterApi/Services/CharacterStore.cs @@ -85,7 +85,7 @@ public class CharacterStore var update = Builders.Update .SetOnInsert(l => l.Name, DefaultLocationName(x, y)) - .SetOnInsert(l => l.Coord, new Coord { X = x, Y = y }) + .SetOnInsert(l => l.Coord, new LocationCoord { X = x, Y = y }) .SetOnInsert(l => l.Id, ObjectId.GenerateNewId().ToString()) .SetOnInsert("createdUtc", DateTime.UtcNow); From 3b2cc9721bd5c01baf103defbfa44acbdd2b1725 Mon Sep 17 00:00:00 2001 From: Zeeshaun Date: Fri, 13 Mar 2026 13:37:27 -0500 Subject: [PATCH 11/19] Fixing coord bug --- .../CharacterApi/Models/VisibleLocation.cs | 3 +- microservices/CharacterApi/Program.cs | 55 +++++++++++++++---- 2 files changed, 47 insertions(+), 11 deletions(-) diff --git a/microservices/CharacterApi/Models/VisibleLocation.cs b/microservices/CharacterApi/Models/VisibleLocation.cs index 2087abf..5aff51d 100644 --- a/microservices/CharacterApi/Models/VisibleLocation.cs +++ b/microservices/CharacterApi/Models/VisibleLocation.cs @@ -1,8 +1,9 @@ -using MongoDB.Bson; using MongoDB.Bson.Serialization.Attributes; +using MongoDB.Bson; namespace CharacterApi.Models; +[BsonIgnoreExtraElements] public class VisibleLocation { [BsonId] diff --git a/microservices/CharacterApi/Program.cs b/microservices/CharacterApi/Program.cs index bac4df0..7440d00 100644 --- a/microservices/CharacterApi/Program.cs +++ b/microservices/CharacterApi/Program.cs @@ -1,8 +1,9 @@ -using CharacterApi.Services; -using Microsoft.AspNetCore.Authentication.JwtBearer; -using Microsoft.IdentityModel.Tokens; -using Microsoft.OpenApi.Models; -using System.Text; +using CharacterApi.Services; +using Microsoft.AspNetCore.Diagnostics; +using Microsoft.AspNetCore.Authentication.JwtBearer; +using Microsoft.IdentityModel.Tokens; +using Microsoft.OpenApi.Models; +using System.Text; var builder = WebApplication.CreateBuilder(args); builder.Services.AddControllers(); @@ -57,11 +58,45 @@ builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) builder.Services.AddAuthorization(); -var app = builder.Build(); - -app.MapGet("/healthz", () => Results.Ok("ok")); -app.UseSwagger(); -app.UseSwaggerUI(o => +var app = builder.Build(); + +app.UseExceptionHandler(errorApp => +{ + errorApp.Run(async context => + { + var feature = context.Features.Get(); + var exception = feature?.Error; + var logger = context.RequestServices.GetRequiredService().CreateLogger("GlobalException"); + var traceId = context.TraceIdentifier; + + if (exception is not null) + { + logger.LogError( + exception, + "Unhandled exception for {Method} {Path}. TraceId={TraceId}", + context.Request.Method, + context.Request.Path, + traceId + ); + } + + context.Response.StatusCode = StatusCodes.Status500InternalServerError; + context.Response.ContentType = "application/problem+json"; + + await context.Response.WriteAsJsonAsync(new + { + type = "https://httpstatuses.com/500", + title = "Internal Server Error", + status = 500, + detail = exception?.Message ?? "An unexpected server error occurred.", + traceId + }); + }); +}); + +app.MapGet("/healthz", () => Results.Ok("ok")); +app.UseSwagger(); +app.UseSwaggerUI(o => { o.SwaggerEndpoint("/swagger/v1/swagger.json", "Character API v1"); o.RoutePrefix = "swagger"; From 9b646f501c5593c9aff5ddd9af3ee8a8fdafe490 Mon Sep 17 00:00:00 2001 From: Zeeshaun Date: Fri, 13 Mar 2026 13:59:04 -0500 Subject: [PATCH 12/19] Adding loggin to troubleshoot location generation issue --- game/scenes/Levels/location_level.gd | 6 +++ .../Controllers/CharactersController.cs | 38 ++++++++++++++----- .../CharacterApi/Services/CharacterStore.cs | 18 ++++++--- 3 files changed, 48 insertions(+), 14 deletions(-) diff --git a/game/scenes/Levels/location_level.gd b/game/scenes/Levels/location_level.gd index 38858af..992c8bb 100644 --- a/game/scenes/Levels/location_level.gd +++ b/game/scenes/Levels/location_level.gd @@ -241,6 +241,7 @@ func _load_existing_locations() -> void: _locations_loaded = true return + var loaded_count := 0 for item in parsed: if typeof(item) != TYPE_DICTIONARY: continue @@ -254,5 +255,10 @@ func _load_existing_locations() -> void: if location_name.is_empty(): location_name = "Location %d,%d" % [coord.x, coord.y] _known_locations[coord] = location_name + loaded_count += 1 + + print("LocationLevel loaded %d visible locations for character %s." % [loaded_count, character_id]) + if loaded_count == 0: + push_warning("Visible locations request succeeded but returned 0 locations for character %s." % character_id) _locations_loaded = true diff --git a/microservices/CharacterApi/Controllers/CharactersController.cs b/microservices/CharacterApi/Controllers/CharactersController.cs index bea7bf2..bc04546 100644 --- a/microservices/CharacterApi/Controllers/CharactersController.cs +++ b/microservices/CharacterApi/Controllers/CharactersController.cs @@ -8,14 +8,16 @@ namespace CharacterApi.Controllers; [ApiController] [Route("api/[controller]")] -public class CharactersController : ControllerBase -{ - private readonly CharacterStore _characters; - - public CharactersController(CharacterStore characters) - { - _characters = characters; - } +public class CharactersController : ControllerBase +{ + private readonly CharacterStore _characters; + private readonly ILogger _logger; + + public CharactersController(CharacterStore characters, ILogger logger) + { + _characters = characters; + _logger = logger; + } [HttpPost] [Authorize(Roles = "USER,SUPER")] @@ -66,7 +68,25 @@ public class CharactersController : ControllerBase if (character is null) return NotFound(); - var locations = await _characters.GetOrCreateVisibleLocationsAsync(character); + _logger.LogInformation( + "Visible locations requested for character {CharacterId} at ({X},{Y}) radius {VisionRadius} by user {UserId}", + character.Id, + character.Coord.X, + character.Coord.Y, + character.VisionRadius, + userId + ); + + var generation = await _characters.GetOrCreateVisibleLocationsAsync(character); + var locations = generation.Locations; + + _logger.LogInformation( + "Visible locations resolved for character {CharacterId}: generated {GeneratedCount}, returned {ReturnedCount}", + character.Id, + generation.GeneratedCount, + locations.Count + ); + return Ok(locations); } diff --git a/microservices/CharacterApi/Services/CharacterStore.cs b/microservices/CharacterApi/Services/CharacterStore.cs index aa220e2..f5cfd1a 100644 --- a/microservices/CharacterApi/Services/CharacterStore.cs +++ b/microservices/CharacterApi/Services/CharacterStore.cs @@ -9,6 +9,8 @@ public class CharacterStore private readonly IMongoCollection _col; private readonly IMongoCollection _locations; + public sealed record VisibleLocationResult(List Locations, int GeneratedCount); + public CharacterStore(IConfiguration cfg) { var cs = cfg["MongoDB:ConnectionString"] ?? "mongodb://127.0.0.1:27017"; @@ -46,10 +48,11 @@ public class CharacterStore return GetVisibleLocationsInternalAsync(character, ensureGenerated: false); } - public async Task> GetOrCreateVisibleLocationsAsync(Character character) + public async Task GetOrCreateVisibleLocationsAsync(Character character) { - await EnsureVisibleLocationsExistAsync(character); - return await GetVisibleLocationsInternalAsync(character, ensureGenerated: true); + var generatedCount = await EnsureVisibleLocationsExistAsync(character); + var locations = await GetVisibleLocationsInternalAsync(character, ensureGenerated: true); + return new VisibleLocationResult(locations, generatedCount); } private Task> GetVisibleLocationsInternalAsync(Character character, bool ensureGenerated) @@ -70,9 +73,10 @@ public class CharacterStore return _locations.Find(filter).ToListAsync(); } - private async Task EnsureVisibleLocationsExistAsync(Character character) + private async Task EnsureVisibleLocationsExistAsync(Character character) { var radius = character.VisionRadius > 0 ? character.VisionRadius : 3; + var generatedCount = 0; for (var x = character.Coord.X - radius; x <= character.Coord.X + radius; x++) { @@ -91,7 +95,9 @@ public class CharacterStore try { - await _locations.UpdateOneAsync(filter, update, new UpdateOptions { IsUpsert = true }); + var result = await _locations.UpdateOneAsync(filter, update, new UpdateOptions { IsUpsert = true }); + if (result.UpsertedId is not null) + generatedCount += 1; } catch (MongoWriteException ex) when (ex.WriteError.Category == ServerErrorCategory.DuplicateKey) { @@ -99,6 +105,8 @@ public class CharacterStore } } } + + return generatedCount; } private static string DefaultLocationName(int x, int y) From 6ca0f306bb831abb4ab794f3f3158fff29258372 Mon Sep 17 00:00:00 2001 From: Zeeshaun Date: Fri, 13 Mar 2026 21:26:36 -0500 Subject: [PATCH 13/19] Fixing bad location index --- .../Controllers/CharactersController.cs | 16 ++- .../CharacterApi/Services/CharacterStore.cs | 115 +++++++++++++----- .../LocationsApi/Services/LocationStore.cs | 102 +++++++++++----- 3 files changed, 170 insertions(+), 63 deletions(-) diff --git a/microservices/CharacterApi/Controllers/CharactersController.cs b/microservices/CharacterApi/Controllers/CharactersController.cs index bc04546..c48b879 100644 --- a/microservices/CharacterApi/Controllers/CharactersController.cs +++ b/microservices/CharacterApi/Controllers/CharactersController.cs @@ -64,9 +64,23 @@ public class CharactersController : ControllerBase return Unauthorized(); var allowAnyOwner = User.IsInRole("SUPER"); - var character = await _characters.GetForOwnerByIdAsync(id, userId, allowAnyOwner); + var character = await _characters.GetByIdAsync(id); if (character is null) + { + _logger.LogWarning("Visible locations request failed: character {CharacterId} was not found.", id); return NotFound(); + } + + if (!allowAnyOwner && character.OwnerUserId != userId) + { + _logger.LogWarning( + "Visible locations request denied: character {CharacterId} belongs to owner {OwnerUserId}, request user was {UserId}", + id, + character.OwnerUserId, + userId + ); + return Forbid(); + } _logger.LogInformation( "Visible locations requested for character {CharacterId} at ({X},{Y}) radius {VisionRadius} by user {UserId}", diff --git a/microservices/CharacterApi/Services/CharacterStore.cs b/microservices/CharacterApi/Services/CharacterStore.cs index f5cfd1a..f16e334 100644 --- a/microservices/CharacterApi/Services/CharacterStore.cs +++ b/microservices/CharacterApi/Services/CharacterStore.cs @@ -7,7 +7,8 @@ namespace CharacterApi.Services; public class CharacterStore { private readonly IMongoCollection _col; - private readonly IMongoCollection _locations; + private readonly IMongoCollection _locations; + private const string CoordIndexName = "coord_x_1_coord_y_1"; public sealed record VisibleLocationResult(List Locations, int GeneratedCount); @@ -18,7 +19,8 @@ public class CharacterStore var client = new MongoClient(cs); var db = client.GetDatabase(dbName); _col = db.GetCollection("Characters"); - _locations = db.GetCollection("Locations"); + _locations = db.GetCollection("Locations"); + EnsureLocationCoordIndexes(); var ownerIndex = Builders.IndexKeys.Ascending(c => c.OwnerUserId); _col.Indexes.CreateOne(new CreateIndexModel(ownerIndex)); @@ -29,19 +31,8 @@ public class CharacterStore public Task> GetForOwnerAsync(string ownerUserId) => _col.Find(c => c.OwnerUserId == ownerUserId).ToListAsync(); - public async Task GetForOwnerByIdAsync(string id, string ownerUserId, bool allowAnyOwner) - { - var filter = Builders.Filter.Eq(c => c.Id, id); - if (!allowAnyOwner) - { - filter = Builders.Filter.And( - filter, - Builders.Filter.Eq(c => c.OwnerUserId, ownerUserId) - ); - } - - return await _col.Find(filter).FirstOrDefaultAsync(); - } + public async Task GetByIdAsync(string id) => + await _col.Find(c => c.Id == id).FirstOrDefaultAsync(); public Task> GetVisibleLocationsAsync(Character character) { @@ -55,7 +46,7 @@ public class CharacterStore return new VisibleLocationResult(locations, generatedCount); } - private Task> GetVisibleLocationsInternalAsync(Character character, bool ensureGenerated) + private async Task> GetVisibleLocationsInternalAsync(Character character, bool ensureGenerated) { var radius = character.VisionRadius > 0 ? character.VisionRadius : 3; var minX = character.Coord.X - radius; @@ -63,14 +54,15 @@ public class CharacterStore var minY = character.Coord.Y - radius; var maxY = character.Coord.Y + radius; - var filter = Builders.Filter.And( - Builders.Filter.Gte(l => l.Coord.X, minX), - Builders.Filter.Lte(l => l.Coord.X, maxX), - Builders.Filter.Gte(l => l.Coord.Y, minY), - Builders.Filter.Lte(l => l.Coord.Y, maxY) + var filter = Builders.Filter.And( + Builders.Filter.Gte("coord.x", minX), + Builders.Filter.Lte("coord.x", maxX), + Builders.Filter.Gte("coord.y", minY), + Builders.Filter.Lte("coord.y", maxY) ); - return _locations.Find(filter).ToListAsync(); + var documents = await _locations.Find(filter).ToListAsync(); + return documents.Select(MapVisibleLocation).ToList(); } private async Task EnsureVisibleLocationsExistAsync(Character character) @@ -82,15 +74,19 @@ public class CharacterStore { for (var y = character.Coord.Y - radius; y <= character.Coord.Y + radius; y++) { - var filter = Builders.Filter.And( - Builders.Filter.Eq(l => l.Coord.X, x), - Builders.Filter.Eq(l => l.Coord.Y, y) + var filter = Builders.Filter.And( + Builders.Filter.Eq("coord.x", x), + Builders.Filter.Eq("coord.y", y) ); - var update = Builders.Update - .SetOnInsert(l => l.Name, DefaultLocationName(x, y)) - .SetOnInsert(l => l.Coord, new LocationCoord { X = x, Y = y }) - .SetOnInsert(l => l.Id, ObjectId.GenerateNewId().ToString()) + var update = Builders.Update + .SetOnInsert("_id", ObjectId.GenerateNewId()) + .SetOnInsert("name", DefaultLocationName(x, y)) + .SetOnInsert("coord", new BsonDocument + { + { "x", x }, + { "y", y } + }) .SetOnInsert("createdUtc", DateTime.UtcNow); try @@ -116,6 +112,67 @@ public class CharacterStore return $"Location {x},{y}"; } + private static VisibleLocation MapVisibleLocation(BsonDocument document) + { + var coord = document.GetValue("coord", new BsonDocument()).AsBsonDocument; + var idValue = document.GetValue("_id", BsonNull.Value); + string? id = null; + if (!idValue.IsBsonNull) + { + id = idValue.BsonType == BsonType.ObjectId + ? idValue.AsObjectId.ToString() + : idValue.ToString(); + } + + return new VisibleLocation + { + Id = id, + Name = document.GetValue("name", "").AsString, + Coord = new LocationCoord + { + X = coord.GetValue("x", 0).ToInt32(), + Y = coord.GetValue("y", 0).ToInt32() + } + }; + } + + private void EnsureLocationCoordIndexes() + { + var indexes = _locations.Indexes.List().ToList(); + foreach (var index in indexes) + { + var name = index.GetValue("name", "").AsString; + if (name == "_id_") + continue; + + var keyDoc = index.GetValue("key", new BsonDocument()).AsBsonDocument; + if (IsLegacyCoordIndex(keyDoc) || IsUnexpectedCoordIndex(keyDoc)) + _locations.Indexes.DropOne(name); + } + + var coordIndex = new BsonDocument + { + { "coord.x", 1 }, + { "coord.y", 1 } + }; + var coordIndexOptions = new CreateIndexOptions { Unique = true, Name = CoordIndexName }; + _locations.Indexes.CreateOne(new CreateIndexModel(coordIndex, coordIndexOptions)); + } + + private static bool IsLegacyCoordIndex(BsonDocument keyDoc) => + keyDoc.ElementCount == 2 && + keyDoc.TryGetValue("Coord.X", out var xValue) && + xValue.IsInt32 && xValue.AsInt32 == 1 && + keyDoc.TryGetValue("Coord.Y", out var yValue) && + yValue.IsInt32 && yValue.AsInt32 == 1; + + private static bool IsUnexpectedCoordIndex(BsonDocument keyDoc) + { + var hasLower = keyDoc.Contains("coord.x") || keyDoc.Contains("coord.y"); + var hasUpper = keyDoc.Contains("Coord.X") || keyDoc.Contains("Coord.Y"); + return hasUpper || (hasLower && !(keyDoc.Contains("coord.x") && keyDoc.Contains("coord.y"))); + } + public async Task DeleteForOwnerAsync(string id, string ownerUserId, bool allowAnyOwner) { var filter = Builders.Filter.Eq(c => c.Id, id); diff --git a/microservices/LocationsApi/Services/LocationStore.cs b/microservices/LocationsApi/Services/LocationStore.cs index 27e753f..1d589a1 100644 --- a/microservices/LocationsApi/Services/LocationStore.cs +++ b/microservices/LocationsApi/Services/LocationStore.cs @@ -4,28 +4,27 @@ using MongoDB.Driver; namespace LocationsApi.Services; -public class LocationStore -{ - private readonly IMongoCollection _col; - - public LocationStore(IConfiguration cfg) - { - var cs = cfg["MongoDB:ConnectionString"] ?? "mongodb://127.0.0.1:27017"; - var dbName = cfg["MongoDB:DatabaseName"] ?? "GameDb"; +public class LocationStore +{ + private readonly IMongoCollection _col; + private readonly IMongoCollection _rawCol; + private const string CoordIndexName = "coord_x_1_coord_y_1"; + + public LocationStore(IConfiguration cfg) + { + var cs = cfg["MongoDB:ConnectionString"] ?? "mongodb://127.0.0.1:27017"; + var dbName = cfg["MongoDB:DatabaseName"] ?? "GameDb"; var client = new MongoClient(cs); - var db = client.GetDatabase(dbName); - var collectionName = "Locations"; - EnsureLocationSchema(db, collectionName); - _col = db.GetCollection(collectionName); - - var coordIndex = Builders.IndexKeys - .Ascending(l => l.Coord.X) - .Ascending(l => l.Coord.Y); - var coordIndexOptions = new CreateIndexOptions { Unique = true }; - _col.Indexes.CreateOne(new CreateIndexModel(coordIndex, coordIndexOptions)); - - EnsureOriginLocation(); - } + var db = client.GetDatabase(dbName); + var collectionName = "Locations"; + EnsureLocationSchema(db, collectionName); + _col = db.GetCollection(collectionName); + _rawCol = db.GetCollection(collectionName); + + EnsureCoordIndexes(); + + EnsureOriginLocation(); + } private static void EnsureLocationSchema(IMongoDatabase db, string collectionName) { @@ -95,18 +94,55 @@ public class LocationStore return result.DeletedCount > 0; } - public async Task UpdateNameAsync(string id, string name) - { - var filter = Builders.Filter.Eq(l => l.Id, id); - var update = Builders.Update.Set(l => l.Name, name); - var result = await _col.UpdateOneAsync(filter, update); - return result.ModifiedCount > 0; - } - - private void EnsureOriginLocation() - { - var filter = Builders.Filter.And( - Builders.Filter.Eq(l => l.Coord.X, 0), + public async Task UpdateNameAsync(string id, string name) + { + var filter = Builders.Filter.Eq(l => l.Id, id); + var update = Builders.Update.Set(l => l.Name, name); + var result = await _col.UpdateOneAsync(filter, update); + return result.ModifiedCount > 0; + } + + private void EnsureCoordIndexes() + { + var indexes = _rawCol.Indexes.List().ToList(); + foreach (var index in indexes) + { + var name = index.GetValue("name", "").AsString; + if (name == "_id_") + continue; + + var keyDoc = index.GetValue("key", new BsonDocument()).AsBsonDocument; + if (IsLegacyCoordIndex(keyDoc) || IsUnexpectedCoordIndex(keyDoc)) + _rawCol.Indexes.DropOne(name); + } + + var coordIndex = new BsonDocument + { + { "coord.x", 1 }, + { "coord.y", 1 } + }; + var coordIndexOptions = new CreateIndexOptions { Unique = true, Name = CoordIndexName }; + _rawCol.Indexes.CreateOne(new CreateIndexModel(coordIndex, coordIndexOptions)); + } + + private static bool IsLegacyCoordIndex(BsonDocument keyDoc) => + keyDoc.ElementCount == 2 && + keyDoc.TryGetValue("Coord.X", out var xValue) && + xValue.IsInt32 && xValue.AsInt32 == 1 && + keyDoc.TryGetValue("Coord.Y", out var yValue) && + yValue.IsInt32 && yValue.AsInt32 == 1; + + private static bool IsUnexpectedCoordIndex(BsonDocument keyDoc) + { + var hasLower = keyDoc.Contains("coord.x") || keyDoc.Contains("coord.y"); + var hasUpper = keyDoc.Contains("Coord.X") || keyDoc.Contains("Coord.Y"); + return hasUpper || (hasLower && !(keyDoc.Contains("coord.x") && keyDoc.Contains("coord.y"))); + } + + private void EnsureOriginLocation() + { + var filter = Builders.Filter.And( + Builders.Filter.Eq(l => l.Coord.X, 0), Builders.Filter.Eq(l => l.Coord.Y, 0) ); var existing = _col.Find(filter).FirstOrDefault(); From e79f473ce4778208099f9de76a3d05f085a0c336 Mon Sep 17 00:00:00 2001 From: Zeeshaun Date: Fri, 13 Mar 2026 21:34:59 -0500 Subject: [PATCH 14/19] Updating character location based on occupied tile --- game/scenes/Levels/location_level.gd | 53 +++++++++++++++++-- game/scenes/UI/character_service.gd | 16 ++++-- game/scenes/UI/selected_character.gd | 6 +++ .../Controllers/CharactersController.cs | 25 +++++++++ microservices/CharacterApi/DOCUMENTS.md | 21 +++++--- .../Models/UpdateCharacterCoordRequest.cs | 6 +++ microservices/CharacterApi/README.md | 1 + .../CharacterApi/Services/CharacterStore.cs | 8 +++ 8 files changed, 122 insertions(+), 14 deletions(-) create mode 100644 microservices/CharacterApi/Models/UpdateCharacterCoordRequest.cs diff --git a/game/scenes/Levels/location_level.gd b/game/scenes/Levels/location_level.gd index 992c8bb..7da1abb 100644 --- a/game/scenes/Levels/location_level.gd +++ b/game/scenes/Levels/location_level.gd @@ -25,6 +25,10 @@ var _camera_start_offset := Vector3(0.0, 6.0, 10.0) var _border_material: StandardMaterial3D var _known_locations: Dictionary = {} var _locations_loaded := false +var _character_id := "" +var _persisted_coord := Vector2i.ZERO +var _coord_sync_in_flight := false +var _queued_coord_sync: Variant = null func _ready() -> void: @@ -41,6 +45,8 @@ func _ready() -> void: var start_coord := SelectedCharacter.get_coord() _center_coord = Vector2i(roundi(start_coord.x), roundi(start_coord.y)) + _persisted_coord = _center_coord + _character_id = String(SelectedCharacter.character.get("id", SelectedCharacter.character.get("Id", ""))).strip_edges() _block.visible = false await _load_existing_locations() @@ -58,6 +64,7 @@ func _process(_delta: float) -> void: return _center_coord = target_coord _rebuild_tiles(_center_coord) + _queue_coord_sync(_center_coord) func _get_stream_position() -> Vector3: @@ -204,8 +211,7 @@ func _load_existing_locations() -> void: _locations_loaded = false _known_locations.clear() - var character_id := String(SelectedCharacter.character.get("id", SelectedCharacter.character.get("Id", ""))).strip_edges() - if character_id.is_empty(): + if _character_id.is_empty(): push_warning("Selected character is missing an id; cannot load visible locations.") _locations_loaded = true return @@ -217,7 +223,7 @@ func _load_existing_locations() -> void: if not AuthState.access_token.is_empty(): headers.append("Authorization: Bearer %s" % AuthState.access_token) - var err := request.request("%s/%s/visible-locations" % [CHARACTER_API_URL, character_id], headers, HTTPClient.METHOD_GET) + var err := request.request("%s/%s/visible-locations" % [CHARACTER_API_URL, _character_id], headers, HTTPClient.METHOD_GET) if err != OK: push_warning("Failed to request visible locations: %s" % err) request.queue_free() @@ -257,8 +263,45 @@ func _load_existing_locations() -> void: _known_locations[coord] = location_name loaded_count += 1 - print("LocationLevel loaded %d visible locations for character %s." % [loaded_count, character_id]) + print("LocationLevel loaded %d visible locations for character %s." % [loaded_count, _character_id]) if loaded_count == 0: - push_warning("Visible locations request succeeded but returned 0 locations for character %s." % character_id) + push_warning("Visible locations request succeeded but returned 0 locations for character %s." % _character_id) _locations_loaded = true + + +func _queue_coord_sync(coord: Vector2i) -> void: + if coord == _persisted_coord: + return + if _coord_sync_in_flight: + _queued_coord_sync = coord + return + _sync_character_coord(coord) + + +func _sync_character_coord(coord: Vector2i) -> void: + if _character_id.is_empty(): + return + _coord_sync_in_flight = true + _queued_coord_sync = null + _sync_character_coord_async(coord) + + +func _sync_character_coord_async(coord: Vector2i) -> void: + var response := await CharacterService.update_character_coord(_character_id, coord) + if response.get("ok", false): + _persisted_coord = coord + SelectedCharacter.set_coord(coord) + else: + push_warning("Failed to persist character coord to %s,%s: status=%s error=%s body=%s" % [ + coord.x, + coord.y, + response.get("status", "n/a"), + response.get("error", ""), + response.get("body", "") + ]) + + _coord_sync_in_flight = false + if _queued_coord_sync != null and _queued_coord_sync is Vector2i and _queued_coord_sync != _persisted_coord: + var queued_coord: Vector2i = _queued_coord_sync + _sync_character_coord(queued_coord) diff --git a/game/scenes/UI/character_service.gd b/game/scenes/UI/character_service.gd index 56a05e5..ea57882 100644 --- a/game/scenes/UI/character_service.gd +++ b/game/scenes/UI/character_service.gd @@ -11,9 +11,19 @@ func create_character(character_name: String) -> Dictionary: }) return await _request(HTTPClient.METHOD_POST, CHARACTER_API_URL, payload) -func delete_character(character_id: String) -> Dictionary: - var url := "%s/%s" % [CHARACTER_API_URL, character_id] - return await _request(HTTPClient.METHOD_DELETE, url) +func delete_character(character_id: String) -> Dictionary: + var url := "%s/%s" % [CHARACTER_API_URL, character_id] + return await _request(HTTPClient.METHOD_DELETE, url) + +func update_character_coord(character_id: String, coord: Vector2i) -> Dictionary: + var url := "%s/%s/coord" % [CHARACTER_API_URL, character_id] + var payload := JSON.stringify({ + "coord": { + "x": coord.x, + "y": coord.y + } + }) + return await _request(HTTPClient.METHOD_PUT, url, payload) func _request(method: int, url: String, body: String = "") -> Dictionary: var request := HTTPRequest.new() diff --git a/game/scenes/UI/selected_character.gd b/game/scenes/UI/selected_character.gd index 179ac30..5a8336e 100644 --- a/game/scenes/UI/selected_character.gd +++ b/game/scenes/UI/selected_character.gd @@ -14,3 +14,9 @@ func get_coord() -> Vector2: float(coord.get("x", 0)), float(coord.get("y", 0)) ) + +func set_coord(coord: Vector2i) -> void: + character["coord"] = { + "x": coord.x, + "y": coord.y + } diff --git a/microservices/CharacterApi/Controllers/CharactersController.cs b/microservices/CharacterApi/Controllers/CharactersController.cs index c48b879..f9cc70a 100644 --- a/microservices/CharacterApi/Controllers/CharactersController.cs +++ b/microservices/CharacterApi/Controllers/CharactersController.cs @@ -104,6 +104,31 @@ public class CharactersController : ControllerBase return Ok(locations); } + [HttpPut("{id}/coord")] + [Authorize(Roles = "USER,SUPER")] + public async Task UpdateCoord(string id, [FromBody] UpdateCharacterCoordRequest req) + { + var userId = User.FindFirstValue(ClaimTypes.NameIdentifier); + if (string.IsNullOrWhiteSpace(userId)) + return Unauthorized(); + if (req.Coord is null) + return BadRequest("Coord required"); + + var allowAnyOwner = User.IsInRole("SUPER"); + var character = await _characters.GetByIdAsync(id); + if (character is null) + return NotFound(); + if (!allowAnyOwner && character.OwnerUserId != userId) + return Forbid(); + + character.Coord = req.Coord; + var updated = await _characters.UpdateCoordAsync(id, req.Coord); + if (!updated) + return NotFound(); + + return Ok(character); + } + [HttpDelete("{id}")] [Authorize(Roles = "USER,SUPER")] public async Task Delete(string id) diff --git a/microservices/CharacterApi/DOCUMENTS.md b/microservices/CharacterApi/DOCUMENTS.md index 12c13f5..cf4733e 100644 --- a/microservices/CharacterApi/DOCUMENTS.md +++ b/microservices/CharacterApi/DOCUMENTS.md @@ -4,12 +4,21 @@ This service expects JSON request bodies for character creation and stores character documents in MongoDB. Inbound JSON documents -- CreateCharacterRequest (`POST /api/characters`) - ```json - { - "name": "string" - } - ``` +- CreateCharacterRequest (`POST /api/characters`) + ```json + { + "name": "string" + } + ``` +- UpdateCharacterCoordRequest (`PUT /api/characters/{id}/coord`) + ```json + { + "coord": { + "x": "number", + "y": "number" + } + } + ``` Stored documents (MongoDB) - Character diff --git a/microservices/CharacterApi/Models/UpdateCharacterCoordRequest.cs b/microservices/CharacterApi/Models/UpdateCharacterCoordRequest.cs new file mode 100644 index 0000000..b6d265a --- /dev/null +++ b/microservices/CharacterApi/Models/UpdateCharacterCoordRequest.cs @@ -0,0 +1,6 @@ +namespace CharacterApi.Models; + +public class UpdateCharacterCoordRequest +{ + public required Coord Coord { get; set; } +} diff --git a/microservices/CharacterApi/README.md b/microservices/CharacterApi/README.md index 9eede41..bcbf8df 100644 --- a/microservices/CharacterApi/README.md +++ b/microservices/CharacterApi/README.md @@ -6,5 +6,6 @@ See `DOCUMENTS.md` for request payloads and stored document shapes. ## Endpoints - `POST /api/characters` Create a character. - `GET /api/characters` List characters for the current user. +- `PUT /api/characters/{id}/coord` Update the current location coord for an owned character. - `GET /api/characters/{id}/visible-locations` Ensure and list locations visible to that owned character. - `DELETE /api/characters/{id}` Delete a character owned by the current user. diff --git a/microservices/CharacterApi/Services/CharacterStore.cs b/microservices/CharacterApi/Services/CharacterStore.cs index f16e334..4705e03 100644 --- a/microservices/CharacterApi/Services/CharacterStore.cs +++ b/microservices/CharacterApi/Services/CharacterStore.cs @@ -34,6 +34,14 @@ public class CharacterStore public async Task GetByIdAsync(string id) => await _col.Find(c => c.Id == id).FirstOrDefaultAsync(); + public async Task UpdateCoordAsync(string id, Coord coord) + { + var filter = Builders.Filter.Eq(c => c.Id, id); + var update = Builders.Update.Set(c => c.Coord, coord); + var result = await _col.UpdateOneAsync(filter, update); + return result.ModifiedCount > 0 || result.MatchedCount > 0; + } + public Task> GetVisibleLocationsAsync(Character character) { return GetVisibleLocationsInternalAsync(character, ensureGenerated: false); From 9809869cbeac85be62607f1ed4b4481c3372fe5d Mon Sep 17 00:00:00 2001 From: Zeeshaun Date: Fri, 13 Mar 2026 21:55:18 -0500 Subject: [PATCH 15/19] Endless location generation --- game/scenes/Levels/location_level.gd | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/game/scenes/Levels/location_level.gd b/game/scenes/Levels/location_level.gd index 7da1abb..7d4f7aa 100644 --- a/game/scenes/Levels/location_level.gd +++ b/game/scenes/Levels/location_level.gd @@ -29,6 +29,8 @@ var _character_id := "" var _persisted_coord := Vector2i.ZERO var _coord_sync_in_flight := false var _queued_coord_sync: Variant = null +var _locations_refresh_in_flight := false +var _queued_locations_refresh := false func _ready() -> void: @@ -63,8 +65,8 @@ func _process(_delta: float) -> void: if target_coord == _center_coord: return _center_coord = target_coord - _rebuild_tiles(_center_coord) _queue_coord_sync(_center_coord) + _queue_locations_refresh() func _get_stream_position() -> Vector3: @@ -208,6 +210,7 @@ func _selected_location_name(coord: Vector2i) -> String: func _load_existing_locations() -> void: + _locations_refresh_in_flight = true _locations_loaded = false _known_locations.clear() @@ -268,6 +271,28 @@ func _load_existing_locations() -> void: push_warning("Visible locations request succeeded but returned 0 locations for character %s." % _character_id) _locations_loaded = true + _locations_refresh_in_flight = false + _rebuild_tiles(_center_coord) + if _queued_locations_refresh: + _queued_locations_refresh = false + _queue_locations_refresh() + + +func _queue_locations_refresh() -> void: + if _locations_refresh_in_flight: + _queued_locations_refresh = true + return + _refresh_visible_locations() + + +func _refresh_visible_locations() -> void: + if _character_id.is_empty(): + return + _refresh_visible_locations_async() + + +func _refresh_visible_locations_async() -> void: + await _load_existing_locations() func _queue_coord_sync(coord: Vector2i) -> void: From 9a7d6544ef33d7d1d5e13d59cb054f489083ca12 Mon Sep 17 00:00:00 2001 From: Zeeshaun Date: Sun, 15 Mar 2026 10:21:49 -0500 Subject: [PATCH 16/19] Adding inventory microservice --- game/scenes/Levels/location_level.gd | 2 +- .../Controllers/InventoryController.cs | 248 +++++++++ microservices/InventoryApi/DOCUMENTS.md | 186 +++++++ microservices/InventoryApi/Dockerfile | 19 + .../InventoryApi/InventoryApi.csproj | 16 + .../Models/ConsumeInventoryItemRequest.cs | 6 + .../Models/EquipInventoryItemRequest.cs | 8 + .../Models/GrantInventoryItemRequest.cs | 10 + .../InventoryApi/Models/InventoryItem.cs | 38 ++ .../Models/InventoryItemResponse.cs | 32 ++ .../Models/InventoryMutationResult.cs | 22 + .../Models/InventoryOwnerResponse.cs | 10 + .../Models/MoveInventoryItemRequest.cs | 10 + .../InventoryApi/Models/OwnerAccessResult.cs | 16 + .../Models/TransferInventoryItemRequest.cs | 18 + .../Models/TransferInventoryResponse.cs | 18 + .../Models/UnequipInventoryItemRequest.cs | 8 + microservices/InventoryApi/Program.cs | 106 ++++ .../Properties/launchSettings.json | 14 + microservices/InventoryApi/README.md | 116 ++++ .../InventoryApi/Services/InventoryStore.cs | 509 ++++++++++++++++++ .../InventoryApi/appsettings.Development.json | 8 + microservices/InventoryApi/appsettings.json | 7 + .../InventoryApi/k8s/deployment.yaml | 28 + microservices/InventoryApi/k8s/service.yaml | 15 + microservices/README.md | 2 + microservices/micro-services.sln | 18 +- 27 files changed, 1483 insertions(+), 7 deletions(-) create mode 100644 microservices/InventoryApi/Controllers/InventoryController.cs create mode 100644 microservices/InventoryApi/DOCUMENTS.md create mode 100644 microservices/InventoryApi/Dockerfile create mode 100644 microservices/InventoryApi/InventoryApi.csproj create mode 100644 microservices/InventoryApi/Models/ConsumeInventoryItemRequest.cs create mode 100644 microservices/InventoryApi/Models/EquipInventoryItemRequest.cs create mode 100644 microservices/InventoryApi/Models/GrantInventoryItemRequest.cs create mode 100644 microservices/InventoryApi/Models/InventoryItem.cs create mode 100644 microservices/InventoryApi/Models/InventoryItemResponse.cs create mode 100644 microservices/InventoryApi/Models/InventoryMutationResult.cs create mode 100644 microservices/InventoryApi/Models/InventoryOwnerResponse.cs create mode 100644 microservices/InventoryApi/Models/MoveInventoryItemRequest.cs create mode 100644 microservices/InventoryApi/Models/OwnerAccessResult.cs create mode 100644 microservices/InventoryApi/Models/TransferInventoryItemRequest.cs create mode 100644 microservices/InventoryApi/Models/TransferInventoryResponse.cs create mode 100644 microservices/InventoryApi/Models/UnequipInventoryItemRequest.cs create mode 100644 microservices/InventoryApi/Program.cs create mode 100644 microservices/InventoryApi/Properties/launchSettings.json create mode 100644 microservices/InventoryApi/README.md create mode 100644 microservices/InventoryApi/Services/InventoryStore.cs create mode 100644 microservices/InventoryApi/appsettings.Development.json create mode 100644 microservices/InventoryApi/appsettings.json create mode 100644 microservices/InventoryApi/k8s/deployment.yaml create mode 100644 microservices/InventoryApi/k8s/service.yaml diff --git a/game/scenes/Levels/location_level.gd b/game/scenes/Levels/location_level.gd index 7d4f7aa..48d01b2 100644 --- a/game/scenes/Levels/location_level.gd +++ b/game/scenes/Levels/location_level.gd @@ -2,7 +2,7 @@ extends Node3D const CHARACTER_API_URL := "https://pchar.ranaze.com/api/Characters" -@export var tile_size := 4.0 +@export var tile_size := 16.0 @export var block_height := 1.0 @export_range(1, 8, 1) var tile_radius := 3 @export var tracked_node_path: NodePath diff --git a/microservices/InventoryApi/Controllers/InventoryController.cs b/microservices/InventoryApi/Controllers/InventoryController.cs new file mode 100644 index 0000000..85c3c0b --- /dev/null +++ b/microservices/InventoryApi/Controllers/InventoryController.cs @@ -0,0 +1,248 @@ +using InventoryApi.Models; +using InventoryApi.Services; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using System.Security.Claims; + +namespace InventoryApi.Controllers; + +[ApiController] +[Route("api/[controller]")] +public class InventoryController : ControllerBase +{ + private readonly InventoryStore _inventory; + + public InventoryController(InventoryStore inventory) + { + _inventory = inventory; + } + + [HttpGet("by-owner/{ownerType}/{ownerId}")] + [Authorize(Roles = "USER,SUPER")] + public async Task GetByOwner(string ownerType, string ownerId) + { + var userId = User.FindFirstValue(ClaimTypes.NameIdentifier); + if (string.IsNullOrWhiteSpace(userId)) + return Unauthorized(); + + var access = await _inventory.ResolveOwnerAsync(ownerType, ownerId, userId, User.IsInRole("SUPER")); + if (!access.IsSupported) + return BadRequest("Unsupported ownerType"); + if (!access.Exists) + return NotFound(); + if (!access.IsAuthorized) + return Forbid(); + + var items = await _inventory.GetByOwnerAsync(access.OwnerType, access.OwnerId); + return Ok(new InventoryOwnerResponse + { + OwnerType = access.OwnerType, + OwnerId = access.OwnerId, + Items = items.Select(InventoryItemResponse.FromModel).ToList() + }); + } + + [HttpPost("by-owner/{ownerType}/{ownerId}/grant")] + [Authorize(Roles = "USER,SUPER")] + public async Task Grant(string ownerType, string ownerId, [FromBody] GrantInventoryItemRequest req) + { + if (string.IsNullOrWhiteSpace(req.ItemKey)) + return BadRequest("itemKey required"); + if (req.Quantity <= 0) + return BadRequest("quantity must be greater than 0"); + + var userId = User.FindFirstValue(ClaimTypes.NameIdentifier); + if (string.IsNullOrWhiteSpace(userId)) + return Unauthorized(); + + var access = await _inventory.ResolveOwnerAsync(ownerType, ownerId, userId, User.IsInRole("SUPER")); + if (!access.IsSupported) + return BadRequest("Unsupported ownerType"); + if (!access.Exists) + return NotFound(); + if (!access.IsAuthorized) + return Forbid(); + + var items = await _inventory.GrantAsync(access, req); + return Ok(new InventoryOwnerResponse + { + OwnerType = access.OwnerType, + OwnerId = access.OwnerId, + Items = items.Select(InventoryItemResponse.FromModel).ToList() + }); + } + + [HttpPost("by-owner/{ownerType}/{ownerId}/move")] + [Authorize(Roles = "USER,SUPER")] + public async Task Move(string ownerType, string ownerId, [FromBody] MoveInventoryItemRequest req) + { + if (string.IsNullOrWhiteSpace(req.ItemId)) + return BadRequest("itemId required"); + if (req.ToSlot < 0) + return BadRequest("toSlot must be >= 0"); + if (req.Quantity is <= 0) + return BadRequest("quantity must be greater than 0"); + + var userId = User.FindFirstValue(ClaimTypes.NameIdentifier); + if (string.IsNullOrWhiteSpace(userId)) + return Unauthorized(); + + var access = await _inventory.ResolveOwnerAsync(ownerType, ownerId, userId, User.IsInRole("SUPER")); + if (!access.IsSupported) + return BadRequest("Unsupported ownerType"); + if (!access.Exists) + return NotFound(); + if (!access.IsAuthorized) + return Forbid(); + + var result = await _inventory.MoveAsync(access, req); + return result.Status switch + { + InventoryMutationStatus.ItemNotFound => NotFound(), + InventoryMutationStatus.Invalid => BadRequest("Invalid move"), + InventoryMutationStatus.Conflict => Conflict("Target slot is not available"), + _ => Ok(new InventoryOwnerResponse + { + OwnerType = access.OwnerType, + OwnerId = access.OwnerId, + Items = result.Items.Select(InventoryItemResponse.FromModel).ToList() + }) + }; + } + + [HttpPost("transfer")] + [Authorize(Roles = "USER,SUPER")] + public async Task Transfer([FromBody] TransferInventoryItemRequest req) + { + if (string.IsNullOrWhiteSpace(req.ItemId)) + return BadRequest("itemId required"); + if (string.IsNullOrWhiteSpace(req.FromOwnerType) || string.IsNullOrWhiteSpace(req.FromOwnerId)) + return BadRequest("from owner required"); + if (string.IsNullOrWhiteSpace(req.ToOwnerType) || string.IsNullOrWhiteSpace(req.ToOwnerId)) + return BadRequest("to owner required"); + if (req.ToSlot is < 0) + return BadRequest("toSlot must be >= 0"); + if (req.Quantity is <= 0) + return BadRequest("quantity must be greater than 0"); + + var userId = User.FindFirstValue(ClaimTypes.NameIdentifier); + if (string.IsNullOrWhiteSpace(userId)) + return Unauthorized(); + + var fromAccess = await _inventory.ResolveOwnerAsync(req.FromOwnerType, req.FromOwnerId, userId, User.IsInRole("SUPER")); + if (!fromAccess.IsSupported) + return BadRequest("Unsupported fromOwnerType"); + if (!fromAccess.Exists) + return NotFound("Source owner not found"); + if (!fromAccess.IsAuthorized) + return Forbid(); + + var toAccess = await _inventory.ResolveOwnerAsync(req.ToOwnerType, req.ToOwnerId, userId, User.IsInRole("SUPER")); + if (!toAccess.IsSupported) + return BadRequest("Unsupported toOwnerType"); + if (!toAccess.Exists) + return NotFound("Target owner not found"); + if (!toAccess.IsAuthorized) + return Forbid(); + + var result = await _inventory.TransferAsync(fromAccess, toAccess, req); + return result.Status switch + { + InventoryMutationStatus.ItemNotFound => NotFound(), + InventoryMutationStatus.Invalid => BadRequest("Invalid transfer"), + InventoryMutationStatus.Conflict => Conflict("Target slot is not available"), + _ => Ok(new TransferInventoryResponse + { + MovedItemId = req.ItemId, + FromOwnerType = fromAccess.OwnerType, + FromOwnerId = fromAccess.OwnerId, + ToOwnerType = toAccess.OwnerType, + ToOwnerId = toAccess.OwnerId, + FromItems = result.Items.Select(InventoryItemResponse.FromModel).Where(x => x.OwnerType == fromAccess.OwnerType && x.OwnerId == fromAccess.OwnerId).ToList(), + ToItems = result.Items.Select(InventoryItemResponse.FromModel).Where(x => x.OwnerType == toAccess.OwnerType && x.OwnerId == toAccess.OwnerId).ToList() + }) + }; + } + + [HttpPost("items/{itemId}/consume")] + [Authorize(Roles = "USER,SUPER")] + public async Task Consume(string itemId, [FromBody] ConsumeInventoryItemRequest req) + { + if (req.Quantity <= 0) + return BadRequest("quantity must be greater than 0"); + + var userId = User.FindFirstValue(ClaimTypes.NameIdentifier); + if (string.IsNullOrWhiteSpace(userId)) + return Unauthorized(); + + var result = await _inventory.ConsumeAsync(itemId, req.Quantity, userId, User.IsInRole("SUPER")); + return result.Status switch + { + InventoryMutationStatus.ItemNotFound => NotFound(), + InventoryMutationStatus.Invalid => BadRequest("Invalid consume request"), + InventoryMutationStatus.Conflict => Conflict(), + _ => Ok(new InventoryOwnerResponse + { + OwnerType = result.OwnerType, + OwnerId = result.OwnerId, + Items = result.Items.Select(InventoryItemResponse.FromModel).ToList() + }) + }; + } + + [HttpPost("items/{itemId}/equip")] + [Authorize(Roles = "USER,SUPER")] + public async Task Equip(string itemId, [FromBody] EquipInventoryItemRequest req) + { + if (string.IsNullOrWhiteSpace(req.OwnerId)) + return BadRequest("ownerId required"); + if (string.IsNullOrWhiteSpace(req.EquipmentSlot)) + return BadRequest("equipmentSlot required"); + + var userId = User.FindFirstValue(ClaimTypes.NameIdentifier); + if (string.IsNullOrWhiteSpace(userId)) + return Unauthorized(); + + var result = await _inventory.EquipAsync(itemId, req.OwnerId, req.EquipmentSlot, userId, User.IsInRole("SUPER")); + return result.Status switch + { + InventoryMutationStatus.ItemNotFound => NotFound(), + InventoryMutationStatus.Invalid => BadRequest("Invalid equip request"), + InventoryMutationStatus.Conflict => Conflict("Equipment slot is not available"), + _ => Ok(new InventoryOwnerResponse + { + OwnerType = result.OwnerType, + OwnerId = result.OwnerId, + Items = result.Items.Select(InventoryItemResponse.FromModel).ToList() + }) + }; + } + + [HttpPost("items/{itemId}/unequip")] + [Authorize(Roles = "USER,SUPER")] + public async Task Unequip(string itemId, [FromBody] UnequipInventoryItemRequest req) + { + if (string.IsNullOrWhiteSpace(req.OwnerId)) + return BadRequest("ownerId required"); + if (req.PreferredSlot is < 0) + return BadRequest("preferredSlot must be >= 0"); + + var userId = User.FindFirstValue(ClaimTypes.NameIdentifier); + if (string.IsNullOrWhiteSpace(userId)) + return Unauthorized(); + + var result = await _inventory.UnequipAsync(itemId, req.OwnerId, req.PreferredSlot, userId, User.IsInRole("SUPER")); + return result.Status switch + { + InventoryMutationStatus.ItemNotFound => NotFound(), + InventoryMutationStatus.Invalid => BadRequest("Invalid unequip request"), + InventoryMutationStatus.Conflict => Conflict("Inventory slot is not available"), + _ => Ok(new InventoryOwnerResponse + { + OwnerType = result.OwnerType, + OwnerId = result.OwnerId, + Items = result.Items.Select(InventoryItemResponse.FromModel).ToList() + }) + }; + } +} diff --git a/microservices/InventoryApi/DOCUMENTS.md b/microservices/InventoryApi/DOCUMENTS.md new file mode 100644 index 0000000..88d0c86 --- /dev/null +++ b/microservices/InventoryApi/DOCUMENTS.md @@ -0,0 +1,186 @@ +# InventoryApi document shapes + +This service stores one MongoDB document per inventory item record. + +Inbound JSON documents +- GrantInventoryItemRequest (`POST /api/inventory/by-owner/{ownerType}/{ownerId}/grant`) + ```json + { + "itemKey": "string", + "quantity": 1, + "preferredSlot": 0 + } + ``` + `preferredSlot` is optional. If omitted, the service finds a valid destination slot. + +- MoveInventoryItemRequest (`POST /api/inventory/by-owner/{ownerType}/{ownerId}/move`) + ```json + { + "itemId": "uuid-string", + "toSlot": 1, + "quantity": 1 + } + ``` + `quantity` is optional. If omitted, move the full stack. + +- TransferInventoryItemRequest (`POST /api/inventory/transfer`) + ```json + { + "itemId": "uuid-string", + "fromOwnerType": "character", + "fromOwnerId": "string", + "toOwnerType": "location", + "toOwnerId": "string", + "toSlot": 0, + "quantity": 1 + } + ``` + `toSlot` and `quantity` are optional. If omitted, the service finds a valid destination and transfers the full stack. + +- ConsumeInventoryItemRequest (`POST /api/inventory/items/{itemId}/consume`) + ```json + { + "quantity": 1 + } + ``` + +- EquipInventoryItemRequest (`POST /api/inventory/items/{itemId}/equip`) + ```json + { + "ownerId": "string", + "equipmentSlot": "weapon" + } + ``` + Only valid for items currently owned by a character inventory. + +- UnequipInventoryItemRequest (`POST /api/inventory/items/{itemId}/unequip`) + ```json + { + "ownerId": "string", + "preferredSlot": 0 + } + ``` + Only valid for items currently equipped by a character. + +Stored documents (MongoDB) +- InventoryItem + ```json + { + "id": "string (UUID)", + "itemKey": "wood", + "quantity": 12, + "ownerType": "character", + "ownerId": "string (ObjectId or stable external id)", + "ownerUserId": "string (ObjectId from auth token, null for public world owners)", + "slot": 0, + "equippedSlot": null, + "createdUtc": "string (ISO-8601 datetime)", + "updatedUtc": "string (ISO-8601 datetime)" + } + ``` + +Equipped character item example: +```json +{ + "id": "string (UUID)", + "itemKey": "pistol", + "quantity": 1, + "ownerType": "character", + "ownerId": "string (Character ObjectId)", + "ownerUserId": "string (ObjectId from auth token)", + "slot": null, + "equippedSlot": "weapon", + "createdUtc": "string (ISO-8601 datetime)", + "updatedUtc": "string (ISO-8601 datetime)" +} +``` + +Location stack example: +```json +{ + "id": "string (UUID)", + "itemKey": "wood", + "quantity": 12, + "ownerType": "location", + "ownerId": "string (Location ObjectId)", + "ownerUserId": null, + "slot": 3, + "equippedSlot": null, + "createdUtc": "string (ISO-8601 datetime)", + "updatedUtc": "string (ISO-8601 datetime)" +} +``` + +Outbound JSON documents +- InventoryItemResponse + ```json + { + "id": "string (UUID)", + "itemKey": "wood", + "quantity": 12, + "ownerType": "character", + "ownerId": "string", + "slot": 0, + "equippedSlot": null, + "updatedUtc": "string (ISO-8601 datetime)" + } + ``` + +- InventoryOwnerResponse (`GET /api/inventory/by-owner/{ownerType}/{ownerId}`) + ```json + { + "ownerType": "character", + "ownerId": "string", + "items": [ + { + "id": "string (UUID)", + "itemKey": "wood", + "quantity": 12, + "ownerType": "character", + "ownerId": "string", + "slot": 0, + "equippedSlot": null, + "updatedUtc": "string (ISO-8601 datetime)" + } + ] + } + ``` + +- TransferInventoryResponse (`POST /api/inventory/transfer`) + ```json + { + "movedItemId": "string (UUID)", + "fromOwnerType": "character", + "fromOwnerId": "string", + "toOwnerType": "location", + "toOwnerId": "string", + "fromItems": [], + "toItems": [] + } + ``` + +Validation rules +- `ownerType` must be a supported container type +- `ownerId` must map to an existing owning entity where applicable +- non-`SUPER` callers may only access owned character items unless explicit gameplay rules allow a world container read/write +- `quantity` must be greater than `0` +- non-stackable items must have `quantity = 1` +- equipped items must have `slot = null` +- unequipped bag items must have `equippedSlot = null` +- an item must not have both `slot` and `equippedSlot` populated +- slot occupancy must be unique for `(ownerType, ownerId, slot)` where `slot != null` +- equipment occupancy must be unique for `(ownerType, ownerId, equippedSlot)` where `equippedSlot != null` + +Recommended indexes +- unique on `id` +- index on `(ownerType, ownerId)` +- unique on `(ownerType, ownerId, slot)` for bag slots +- unique on `(ownerType, ownerId, equippedSlot)` for equipped slots +- index on `itemKey` + +Behavior rules +- moving a full non-stackable item should update its owner and slot in place +- moving part of a stack should split the stack and create a new item record with a new UUID for the moved quantity +- moving into a compatible stack should merge quantities and delete or reduce the source record +- cross-owner transfer should be transactional when it mutates multiple records +- auctions should reference `itemId` values directly instead of copying item state into the auction document diff --git a/microservices/InventoryApi/Dockerfile b/microservices/InventoryApi/Dockerfile new file mode 100644 index 0000000..49087c6 --- /dev/null +++ b/microservices/InventoryApi/Dockerfile @@ -0,0 +1,19 @@ +FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build +WORKDIR /src + +COPY ["InventoryApi.csproj", "./"] +RUN dotnet restore "InventoryApi.csproj" + +COPY . . +RUN dotnet publish "InventoryApi.csproj" -c Release -o /app/publish /p:UseAppHost=false + +FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS final +WORKDIR /app +COPY --from=build /app/publish . + +ENV ASPNETCORE_URLS=http://+:8080 \ + ASPNETCORE_ENVIRONMENT=Production + +EXPOSE 8080 + +ENTRYPOINT ["dotnet", "InventoryApi.dll"] diff --git a/microservices/InventoryApi/InventoryApi.csproj b/microservices/InventoryApi/InventoryApi.csproj new file mode 100644 index 0000000..0cb0950 --- /dev/null +++ b/microservices/InventoryApi/InventoryApi.csproj @@ -0,0 +1,16 @@ + + + + net8.0 + enable + enable + + + + + + + + + + diff --git a/microservices/InventoryApi/Models/ConsumeInventoryItemRequest.cs b/microservices/InventoryApi/Models/ConsumeInventoryItemRequest.cs new file mode 100644 index 0000000..48d234a --- /dev/null +++ b/microservices/InventoryApi/Models/ConsumeInventoryItemRequest.cs @@ -0,0 +1,6 @@ +namespace InventoryApi.Models; + +public class ConsumeInventoryItemRequest +{ + public int Quantity { get; set; } = 1; +} diff --git a/microservices/InventoryApi/Models/EquipInventoryItemRequest.cs b/microservices/InventoryApi/Models/EquipInventoryItemRequest.cs new file mode 100644 index 0000000..303860f --- /dev/null +++ b/microservices/InventoryApi/Models/EquipInventoryItemRequest.cs @@ -0,0 +1,8 @@ +namespace InventoryApi.Models; + +public class EquipInventoryItemRequest +{ + public string OwnerId { get; set; } = string.Empty; + + public string EquipmentSlot { get; set; } = string.Empty; +} diff --git a/microservices/InventoryApi/Models/GrantInventoryItemRequest.cs b/microservices/InventoryApi/Models/GrantInventoryItemRequest.cs new file mode 100644 index 0000000..ad96551 --- /dev/null +++ b/microservices/InventoryApi/Models/GrantInventoryItemRequest.cs @@ -0,0 +1,10 @@ +namespace InventoryApi.Models; + +public class GrantInventoryItemRequest +{ + public string ItemKey { get; set; } = string.Empty; + + public int Quantity { get; set; } = 1; + + public int? PreferredSlot { get; set; } +} diff --git a/microservices/InventoryApi/Models/InventoryItem.cs b/microservices/InventoryApi/Models/InventoryItem.cs new file mode 100644 index 0000000..6bd1703 --- /dev/null +++ b/microservices/InventoryApi/Models/InventoryItem.cs @@ -0,0 +1,38 @@ +using MongoDB.Bson.Serialization.Attributes; + +namespace InventoryApi.Models; + +public class InventoryItem +{ + [BsonId] + public string Id { get; set; } = Guid.NewGuid().ToString(); + + [BsonElement("itemKey")] + public string ItemKey { get; set; } = string.Empty; + + [BsonElement("quantity")] + public int Quantity { get; set; } = 1; + + [BsonElement("ownerType")] + public string OwnerType { get; set; } = string.Empty; + + [BsonElement("ownerId")] + public string OwnerId { get; set; } = string.Empty; + + [BsonElement("ownerUserId")] + public string? OwnerUserId { get; set; } + + [BsonElement("slot")] + [BsonIgnoreIfNull] + public int? Slot { get; set; } + + [BsonElement("equippedSlot")] + [BsonIgnoreIfNull] + public string? EquippedSlot { get; set; } + + [BsonElement("createdUtc")] + public DateTime CreatedUtc { get; set; } = DateTime.UtcNow; + + [BsonElement("updatedUtc")] + public DateTime UpdatedUtc { get; set; } = DateTime.UtcNow; +} diff --git a/microservices/InventoryApi/Models/InventoryItemResponse.cs b/microservices/InventoryApi/Models/InventoryItemResponse.cs new file mode 100644 index 0000000..d4b4d6f --- /dev/null +++ b/microservices/InventoryApi/Models/InventoryItemResponse.cs @@ -0,0 +1,32 @@ +namespace InventoryApi.Models; + +public class InventoryItemResponse +{ + public string Id { get; set; } = string.Empty; + + public string ItemKey { get; set; } = string.Empty; + + public int Quantity { get; set; } + + public string OwnerType { get; set; } = string.Empty; + + public string OwnerId { get; set; } = string.Empty; + + public int? Slot { get; set; } + + public string? EquippedSlot { get; set; } + + public DateTime UpdatedUtc { get; set; } + + public static InventoryItemResponse FromModel(InventoryItem item) => new() + { + Id = item.Id, + ItemKey = item.ItemKey, + Quantity = item.Quantity, + OwnerType = item.OwnerType, + OwnerId = item.OwnerId, + Slot = item.Slot, + EquippedSlot = item.EquippedSlot, + UpdatedUtc = item.UpdatedUtc + }; +} diff --git a/microservices/InventoryApi/Models/InventoryMutationResult.cs b/microservices/InventoryApi/Models/InventoryMutationResult.cs new file mode 100644 index 0000000..09946f4 --- /dev/null +++ b/microservices/InventoryApi/Models/InventoryMutationResult.cs @@ -0,0 +1,22 @@ +namespace InventoryApi.Models; + +public enum InventoryMutationStatus +{ + Ok, + ItemNotFound, + Invalid, + Conflict +} + +public class InventoryMutationResult +{ + public InventoryMutationStatus Status { get; init; } = InventoryMutationStatus.Ok; + + public string OwnerType { get; init; } = string.Empty; + + public string OwnerId { get; init; } = string.Empty; + + public List Items { get; init; } = []; + + public static implicit operator InventoryMutationStatus(InventoryMutationResult result) => result.Status; +} diff --git a/microservices/InventoryApi/Models/InventoryOwnerResponse.cs b/microservices/InventoryApi/Models/InventoryOwnerResponse.cs new file mode 100644 index 0000000..e3af042 --- /dev/null +++ b/microservices/InventoryApi/Models/InventoryOwnerResponse.cs @@ -0,0 +1,10 @@ +namespace InventoryApi.Models; + +public class InventoryOwnerResponse +{ + public string OwnerType { get; set; } = string.Empty; + + public string OwnerId { get; set; } = string.Empty; + + public List Items { get; set; } = []; +} diff --git a/microservices/InventoryApi/Models/MoveInventoryItemRequest.cs b/microservices/InventoryApi/Models/MoveInventoryItemRequest.cs new file mode 100644 index 0000000..f7c8419 --- /dev/null +++ b/microservices/InventoryApi/Models/MoveInventoryItemRequest.cs @@ -0,0 +1,10 @@ +namespace InventoryApi.Models; + +public class MoveInventoryItemRequest +{ + public string ItemId { get; set; } = string.Empty; + + public int ToSlot { get; set; } + + public int? Quantity { get; set; } +} diff --git a/microservices/InventoryApi/Models/OwnerAccessResult.cs b/microservices/InventoryApi/Models/OwnerAccessResult.cs new file mode 100644 index 0000000..6453864 --- /dev/null +++ b/microservices/InventoryApi/Models/OwnerAccessResult.cs @@ -0,0 +1,16 @@ +namespace InventoryApi.Models; + +public class OwnerAccessResult +{ + public bool IsSupported { get; init; } + + public bool Exists { get; init; } + + public bool IsAuthorized { get; init; } + + public string OwnerType { get; init; } = string.Empty; + + public string OwnerId { get; init; } = string.Empty; + + public string? OwnerUserId { get; init; } +} diff --git a/microservices/InventoryApi/Models/TransferInventoryItemRequest.cs b/microservices/InventoryApi/Models/TransferInventoryItemRequest.cs new file mode 100644 index 0000000..ad89bfb --- /dev/null +++ b/microservices/InventoryApi/Models/TransferInventoryItemRequest.cs @@ -0,0 +1,18 @@ +namespace InventoryApi.Models; + +public class TransferInventoryItemRequest +{ + public string ItemId { get; set; } = string.Empty; + + public string FromOwnerType { get; set; } = string.Empty; + + public string FromOwnerId { get; set; } = string.Empty; + + public string ToOwnerType { get; set; } = string.Empty; + + public string ToOwnerId { get; set; } = string.Empty; + + public int? ToSlot { get; set; } + + public int? Quantity { get; set; } +} diff --git a/microservices/InventoryApi/Models/TransferInventoryResponse.cs b/microservices/InventoryApi/Models/TransferInventoryResponse.cs new file mode 100644 index 0000000..a211c13 --- /dev/null +++ b/microservices/InventoryApi/Models/TransferInventoryResponse.cs @@ -0,0 +1,18 @@ +namespace InventoryApi.Models; + +public class TransferInventoryResponse +{ + public string MovedItemId { get; set; } = string.Empty; + + public string FromOwnerType { get; set; } = string.Empty; + + public string FromOwnerId { get; set; } = string.Empty; + + public string ToOwnerType { get; set; } = string.Empty; + + public string ToOwnerId { get; set; } = string.Empty; + + public List FromItems { get; set; } = []; + + public List ToItems { get; set; } = []; +} diff --git a/microservices/InventoryApi/Models/UnequipInventoryItemRequest.cs b/microservices/InventoryApi/Models/UnequipInventoryItemRequest.cs new file mode 100644 index 0000000..d63122a --- /dev/null +++ b/microservices/InventoryApi/Models/UnequipInventoryItemRequest.cs @@ -0,0 +1,8 @@ +namespace InventoryApi.Models; + +public class UnequipInventoryItemRequest +{ + public string OwnerId { get; set; } = string.Empty; + + public int? PreferredSlot { get; set; } +} diff --git a/microservices/InventoryApi/Program.cs b/microservices/InventoryApi/Program.cs new file mode 100644 index 0000000..33e9252 --- /dev/null +++ b/microservices/InventoryApi/Program.cs @@ -0,0 +1,106 @@ +using InventoryApi.Services; +using Microsoft.AspNetCore.Authentication.JwtBearer; +using Microsoft.AspNetCore.Diagnostics; +using Microsoft.IdentityModel.Tokens; +using Microsoft.OpenApi.Models; +using System.Text; + +var builder = WebApplication.CreateBuilder(args); +builder.Services.AddControllers(); + +builder.Services.AddSingleton(); + +builder.Services.AddEndpointsApiExplorer(); +builder.Services.AddSwaggerGen(c => +{ + c.SwaggerDoc("v1", new OpenApiInfo { Title = "Inventory API", Version = "v1" }); + c.AddSecurityDefinition("bearerAuth", new OpenApiSecurityScheme + { + Type = SecuritySchemeType.Http, + Scheme = "bearer", + BearerFormat = "JWT", + Description = "Paste your access token here (no 'Bearer ' prefix needed)." + }); + c.AddSecurityRequirement(new OpenApiSecurityRequirement + { + { + new OpenApiSecurityScheme + { + Reference = new OpenApiReference + { Type = ReferenceType.SecurityScheme, Id = "bearerAuth" } + }, + Array.Empty() + } + }); +}); + +var cfg = builder.Configuration; +var jwtKey = cfg["Jwt:Key"] ?? throw new Exception("Jwt:Key missing"); +var issuer = cfg["Jwt:Issuer"] ?? "promiscuity"; +var aud = cfg["Jwt:Audience"] ?? issuer; + +builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) + .AddJwtBearer(o => + { + o.TokenValidationParameters = new TokenValidationParameters + { + ValidateIssuer = true, + ValidIssuer = issuer, + ValidateAudience = true, + ValidAudience = aud, + ValidateIssuerSigningKey = true, + IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtKey)), + ValidateLifetime = true, + ClockSkew = TimeSpan.FromSeconds(30) + }; + }); + +builder.Services.AddAuthorization(); + +var app = builder.Build(); + +app.UseExceptionHandler(errorApp => +{ + errorApp.Run(async context => + { + var feature = context.Features.Get(); + var exception = feature?.Error; + var logger = context.RequestServices.GetRequiredService().CreateLogger("GlobalException"); + var traceId = context.TraceIdentifier; + + if (exception is not null) + { + logger.LogError( + exception, + "Unhandled exception for {Method} {Path}. TraceId={TraceId}", + context.Request.Method, + context.Request.Path, + traceId + ); + } + + context.Response.StatusCode = StatusCodes.Status500InternalServerError; + context.Response.ContentType = "application/problem+json"; + + await context.Response.WriteAsJsonAsync(new + { + type = "https://httpstatuses.com/500", + title = "Internal Server Error", + status = 500, + detail = exception?.Message ?? "An unexpected server error occurred.", + traceId + }); + }); +}); + +app.MapGet("/healthz", () => Results.Ok("ok")); +app.UseSwagger(); +app.UseSwaggerUI(o => +{ + o.SwaggerEndpoint("/swagger/v1/swagger.json", "Inventory API v1"); + o.RoutePrefix = "swagger"; +}); +app.UseAuthentication(); +app.UseAuthorization(); +app.MapControllers(); +app.Run(); diff --git a/microservices/InventoryApi/Properties/launchSettings.json b/microservices/InventoryApi/Properties/launchSettings.json new file mode 100644 index 0000000..b70cfb5 --- /dev/null +++ b/microservices/InventoryApi/Properties/launchSettings.json @@ -0,0 +1,14 @@ +{ + "$schema": "http://json.schemastore.org/launchsettings.json", + "profiles": { + "http": { + "commandName": "Project", + "launchBrowser": true, + "launchUrl": "swagger", + "applicationUrl": "http://localhost:5184", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + } + } +} diff --git a/microservices/InventoryApi/README.md b/microservices/InventoryApi/README.md new file mode 100644 index 0000000..9afa356 --- /dev/null +++ b/microservices/InventoryApi/README.md @@ -0,0 +1,116 @@ +# InventoryApi + +## Purpose +Owns item-instance state. + +This service should answer: +- what item records currently belong to a character, location, or other container owner +- where each item currently is +- whether an item move, split, merge, equip, or consume action is valid +- which specific item instance is being traded, auctioned, or transferred + +This service should not own: +- auth/token issuance +- character identity creation +- location generation +- auction bidding logic + +## Ownership model +- every inventory record has an `ownerType` and `ownerId` +- `USER` can read and mutate items owned by their own characters +- `USER` can read and mutate location/container items only when gameplay rules allow it +- `SUPER` can read and mutate any inventory item +- access should be resolved through the current owner, not from the item id alone + +## Initial design +Use one MongoDB document per inventory item record. + +Practical interpretation: +- non-stackable items: one document per item instance +- stackable items: one document per stack + +Reasons: +- every item or stack gets a stable UUID, which is useful for auctions, trade, mail, and auditing +- ownership transfer is explicit and cheap: update `ownerType`, `ownerId`, and slot fields +- future item metadata like durability, rarity rolls, or provenance can live on the item document +- auction listings can point to specific item ids instead of vague stack descriptions + +Tradeoffs: +- inventory reads are queries over many documents instead of one aggregate read +- stack merging and slot enforcement need careful indexes and mutation logic +- transfers should use transactions when they touch multiple item documents + +## Suggested endpoints +- `GET /api/inventory/by-owner/{ownerType}/{ownerId}` + Return all item records currently owned by that container owner. +- `POST /api/inventory/by-owner/{ownerType}/{ownerId}/grant` + Create a new item record or add quantity into an existing compatible stack. +- `POST /api/inventory/by-owner/{ownerType}/{ownerId}/move` + Move an item or stack within the same owner inventory. +- `POST /api/inventory/transfer` + Move quantity from one owner inventory to another. +- `POST /api/inventory/items/{itemId}/consume` + Consume quantity from a specific item record. +- `POST /api/inventory/items/{itemId}/equip` + Equip a specific item into a character equipment slot. +- `POST /api/inventory/items/{itemId}/unequip` + Return an equipped item to a character inventory slot. + +Notes: +- `equip` and `unequip` only make sense for character-owned items +- `transfer` is the core world interaction primitive for looting, dropping, trading, chest interaction, and auction handoff +- a future AuctionApi can reserve or re-own specific item ids without redesigning InventoryApi + +## Item identity +Every inventory record should have a stable UUID string such as: +- `a8d4218b-5e20-4e47-8b5f-0f0f0b9d7e10` + +Each record also carries an `itemKey` such as: +- `wood` +- `stone` +- `pistol` +- `small_health_potion` + +Recommended distinction: +- `id`: unique item-record identifier used for ownership changes, auctions, and references +- `itemKey`: item definition identifier used to decide stackability and gameplay behavior + +## Recommended stored shape +Each item document should include: +- `id` +- `itemKey` +- `quantity` +- `ownerType` +- `ownerId` +- `slot` +- `equippedSlot` +- `ownerUserId` when applicable +- `createdUtc` +- `updatedUtc` + +Optional future fields: +- `durability` +- `rarity` +- `instanceData` +- `listingId` +- `reservedUntilUtc` + +## MVP rules +- an item record must belong to exactly one owner at a time +- stackable items may share `itemKey` but should still be represented by one stack record per occupied slot +- non-stackable items must always have `quantity = 1` +- equipped items should set `equippedSlot` and clear `slot` +- unequipped bag items should set `slot` and clear `equippedSlot` +- slot occupancy must be unique per `(ownerType, ownerId, slot)` +- all mutating endpoints should be idempotent where practical + +## Client shape +The Godot client should fetch all items for the currently relevant owner and group them into a bag view locally. + +Good pattern: +- login/select character +- `GET /api/inventory/by-owner/character/{characterId}` +- when opening a stash or world container: `GET /api/inventory/by-owner/location/{locationId}` +- cache the returned item records locally +- call transfer/equip/consume endpoints using specific `itemId` values +- replace local state with the server response after each mutation diff --git a/microservices/InventoryApi/Services/InventoryStore.cs b/microservices/InventoryApi/Services/InventoryStore.cs new file mode 100644 index 0000000..823ec97 --- /dev/null +++ b/microservices/InventoryApi/Services/InventoryStore.cs @@ -0,0 +1,509 @@ +using InventoryApi.Models; +using MongoDB.Bson; +using MongoDB.Driver; + +namespace InventoryApi.Services; + +public class InventoryStore +{ + private const string CharacterOwnerType = "character"; + private const string LocationOwnerType = "location"; + private const string ItemIdIndexName = "item_id_unique"; + private const string OwnerIndexName = "owner_type_1_owner_id_1"; + private const string SlotIndexName = "owner_type_1_owner_id_1_slot_1"; + private const string EquippedSlotIndexName = "owner_type_1_owner_id_1_equipped_slot_1"; + + private readonly IMongoCollection _items; + private readonly IMongoCollection _characters; + private readonly IMongoCollection _locations; + private readonly IMongoClient _client; + private readonly string _dbName; + private readonly HashSet _stackableItemKeys = ["wood", "stone", "small_health_potion"]; + + public InventoryStore(IConfiguration cfg) + { + var cs = cfg["MongoDB:ConnectionString"] ?? "mongodb://127.0.0.1:27017"; + _dbName = cfg["MongoDB:DatabaseName"] ?? "promiscuity"; + _client = new MongoClient(cs); + var db = _client.GetDatabase(_dbName); + _items = db.GetCollection("InventoryItems"); + _characters = db.GetCollection("Characters"); + _locations = db.GetCollection("Locations"); + + EnsureIndexes(); + } + + public async Task ResolveOwnerAsync(string ownerType, string ownerId, string userId, bool allowAnyOwner) + { + var normalizedOwnerType = NormalizeOwnerType(ownerType); + if (normalizedOwnerType is null) + return new OwnerAccessResult { IsSupported = false }; + + if (normalizedOwnerType == CharacterOwnerType) + { + var character = await _characters.Find(c => c.Id == ownerId).FirstOrDefaultAsync(); + if (character is null) + { + return new OwnerAccessResult + { + IsSupported = true, + Exists = false, + OwnerType = normalizedOwnerType, + OwnerId = ownerId + }; + } + + var authorized = allowAnyOwner || character.OwnerUserId == userId; + return new OwnerAccessResult + { + IsSupported = true, + Exists = true, + IsAuthorized = authorized, + OwnerType = normalizedOwnerType, + OwnerId = ownerId, + OwnerUserId = character.OwnerUserId + }; + } + + var location = await _locations.Find(l => l.Id == ownerId).FirstOrDefaultAsync(); + return new OwnerAccessResult + { + IsSupported = true, + Exists = location is not null, + IsAuthorized = location is not null, + OwnerType = normalizedOwnerType, + OwnerId = ownerId, + OwnerUserId = null + }; + } + + public Task> GetByOwnerAsync(string ownerType, string ownerId) => + _items.Find(i => i.OwnerType == ownerType && i.OwnerId == ownerId) + .SortBy(i => i.EquippedSlot) + .ThenBy(i => i.Slot) + .ThenBy(i => i.ItemKey) + .ToListAsync(); + + public async Task> GrantAsync(OwnerAccessResult owner, GrantInventoryItemRequest req) + { + var normalizedKey = req.ItemKey.Trim(); + if (IsStackable(normalizedKey)) + { + var targetSlot = req.PreferredSlot ?? await FindFirstOpenSlotAsync(owner.OwnerType, owner.OwnerId); + var existing = await FindStackAsync(owner.OwnerType, owner.OwnerId, normalizedKey, targetSlot); + if (existing is not null) + { + existing.Quantity += req.Quantity; + existing.UpdatedUtc = DateTime.UtcNow; + await ReplaceItemAsync(existing); + return await GetByOwnerAsync(owner.OwnerType, owner.OwnerId); + } + + await InsertItemAsync(new InventoryItem + { + ItemKey = normalizedKey, + Quantity = req.Quantity, + OwnerType = owner.OwnerType, + OwnerId = owner.OwnerId, + OwnerUserId = owner.OwnerUserId, + Slot = targetSlot + }); + return await GetByOwnerAsync(owner.OwnerType, owner.OwnerId); + } + + var nextPreferredSlot = req.PreferredSlot; + for (var index = 0; index < req.Quantity; index += 1) + { + var slot = nextPreferredSlot ?? await FindFirstOpenSlotAsync(owner.OwnerType, owner.OwnerId); + await InsertItemAsync(new InventoryItem + { + ItemKey = normalizedKey, + Quantity = 1, + OwnerType = owner.OwnerType, + OwnerId = owner.OwnerId, + OwnerUserId = owner.OwnerUserId, + Slot = slot + }); + nextPreferredSlot = null; + } + return await GetByOwnerAsync(owner.OwnerType, owner.OwnerId); + } + + public async Task MoveAsync(OwnerAccessResult owner, MoveInventoryItemRequest req) + { + var item = await _items.Find(i => i.Id == req.ItemId).FirstOrDefaultAsync(); + if (item is null) + return new InventoryMutationResult { Status = InventoryMutationStatus.ItemNotFound }; + if (item.OwnerType != owner.OwnerType || item.OwnerId != owner.OwnerId || item.EquippedSlot is not null) + return new InventoryMutationResult { Status = InventoryMutationStatus.Invalid }; + + var quantity = req.Quantity ?? item.Quantity; + if (quantity <= 0 || quantity > item.Quantity) + return new InventoryMutationResult { Status = InventoryMutationStatus.Invalid }; + + var existing = await FindItemBySlotAsync(owner.OwnerType, owner.OwnerId, req.ToSlot); + if (existing is not null && existing.Id != item.Id) + { + if (!CanMerge(item, existing)) + return new InventoryMutationResult { Status = InventoryMutationStatus.Conflict }; + + existing.Quantity += quantity; + existing.UpdatedUtc = DateTime.UtcNow; + await ReplaceItemAsync(existing); + + if (quantity == item.Quantity) + await DeleteItemAsync(item.Id); + else + { + item.Quantity -= quantity; + item.UpdatedUtc = DateTime.UtcNow; + await ReplaceItemAsync(item); + } + } + else if (quantity == item.Quantity) + { + item.Slot = req.ToSlot; + item.UpdatedUtc = DateTime.UtcNow; + await ReplaceItemAsync(item); + } + else + { + item.Quantity -= quantity; + item.UpdatedUtc = DateTime.UtcNow; + await ReplaceItemAsync(item); + + await InsertItemAsync(new InventoryItem + { + ItemKey = item.ItemKey, + Quantity = quantity, + OwnerType = item.OwnerType, + OwnerId = item.OwnerId, + OwnerUserId = item.OwnerUserId, + Slot = req.ToSlot + }); + } + + return new InventoryMutationResult + { + Status = InventoryMutationStatus.Ok, + OwnerType = owner.OwnerType, + OwnerId = owner.OwnerId, + Items = await GetByOwnerAsync(owner.OwnerType, owner.OwnerId) + }; + } + + public async Task TransferAsync(OwnerAccessResult fromOwner, OwnerAccessResult toOwner, TransferInventoryItemRequest req) + { + using var session = await _client.StartSessionAsync(); + session.StartTransaction(); + + try + { + var item = await _items.Find(session, i => i.Id == req.ItemId).FirstOrDefaultAsync(); + if (item is null) + { + await session.AbortTransactionAsync(); + return new InventoryMutationResult { Status = InventoryMutationStatus.ItemNotFound }; + } + + if (item.OwnerType != fromOwner.OwnerType || item.OwnerId != fromOwner.OwnerId || item.EquippedSlot is not null) + { + await session.AbortTransactionAsync(); + return new InventoryMutationResult { Status = InventoryMutationStatus.Invalid }; + } + + var quantity = req.Quantity ?? item.Quantity; + if (quantity <= 0 || quantity > item.Quantity) + { + await session.AbortTransactionAsync(); + return new InventoryMutationResult { Status = InventoryMutationStatus.Invalid }; + } + + var toSlot = req.ToSlot ?? await FindFirstOpenSlotAsync(toOwner.OwnerType, toOwner.OwnerId, session); + var target = await FindItemBySlotAsync(toOwner.OwnerType, toOwner.OwnerId, toSlot, session); + if (target is not null && !CanMerge(item, target)) + { + await session.AbortTransactionAsync(); + return new InventoryMutationResult { Status = InventoryMutationStatus.Conflict }; + } + + if (target is not null) + { + target.Quantity += quantity; + target.UpdatedUtc = DateTime.UtcNow; + await ReplaceItemAsync(target, session); + + if (quantity == item.Quantity) + await DeleteItemAsync(item.Id, session); + else + { + item.Quantity -= quantity; + item.UpdatedUtc = DateTime.UtcNow; + await ReplaceItemAsync(item, session); + } + } + else if (quantity == item.Quantity) + { + item.OwnerType = toOwner.OwnerType; + item.OwnerId = toOwner.OwnerId; + item.OwnerUserId = toOwner.OwnerUserId; + item.Slot = toSlot; + item.EquippedSlot = null; + item.UpdatedUtc = DateTime.UtcNow; + await ReplaceItemAsync(item, session); + } + else + { + item.Quantity -= quantity; + item.UpdatedUtc = DateTime.UtcNow; + await ReplaceItemAsync(item, session); + + await InsertItemAsync(new InventoryItem + { + ItemKey = item.ItemKey, + Quantity = quantity, + OwnerType = toOwner.OwnerType, + OwnerId = toOwner.OwnerId, + OwnerUserId = toOwner.OwnerUserId, + Slot = toSlot + }, session); + } + + await session.CommitTransactionAsync(); + var fromItems = await GetByOwnerAsync(fromOwner.OwnerType, fromOwner.OwnerId); + var toItems = await GetByOwnerAsync(toOwner.OwnerType, toOwner.OwnerId); + return new InventoryMutationResult + { + Status = InventoryMutationStatus.Ok, + Items = fromItems.Concat(toItems).ToList() + }; + } + catch + { + await session.AbortTransactionAsync(); + throw; + } + } + + public async Task ConsumeAsync(string itemId, int quantity, string userId, bool allowAnyOwner) + { + var item = await _items.Find(i => i.Id == itemId).FirstOrDefaultAsync(); + if (item is null) + return new InventoryMutationResult { Status = InventoryMutationStatus.ItemNotFound }; + + var access = await ResolveOwnerAsync(item.OwnerType, item.OwnerId, userId, allowAnyOwner); + if (!access.Exists || !access.IsAuthorized) + return new InventoryMutationResult { Status = InventoryMutationStatus.Invalid }; + if (quantity > item.Quantity) + return new InventoryMutationResult { Status = InventoryMutationStatus.Invalid }; + + if (quantity == item.Quantity) + await DeleteItemAsync(item.Id); + else + { + item.Quantity -= quantity; + item.UpdatedUtc = DateTime.UtcNow; + await ReplaceItemAsync(item); + } + + return new InventoryMutationResult + { + Status = InventoryMutationStatus.Ok, + OwnerType = item.OwnerType, + OwnerId = item.OwnerId, + Items = await GetByOwnerAsync(item.OwnerType, item.OwnerId) + }; + } + + public async Task EquipAsync(string itemId, string ownerId, string equipmentSlot, string userId, bool allowAnyOwner) + { + var owner = await ResolveOwnerAsync(CharacterOwnerType, ownerId, userId, allowAnyOwner); + if (!owner.Exists || !owner.IsAuthorized) + return new InventoryMutationResult { Status = InventoryMutationStatus.Invalid }; + + var item = await _items.Find(i => i.Id == itemId).FirstOrDefaultAsync(); + if (item is null) + return new InventoryMutationResult { Status = InventoryMutationStatus.ItemNotFound }; + if (item.OwnerType != CharacterOwnerType || item.OwnerId != ownerId || item.Slot is null) + return new InventoryMutationResult { Status = InventoryMutationStatus.Invalid }; + + var equipped = await _items.Find(i => + i.OwnerType == CharacterOwnerType && + i.OwnerId == ownerId && + i.EquippedSlot == equipmentSlot).FirstOrDefaultAsync(); + if (equipped is not null && equipped.Id != item.Id) + return new InventoryMutationResult { Status = InventoryMutationStatus.Conflict }; + + item.Slot = null; + item.EquippedSlot = equipmentSlot.Trim(); + item.UpdatedUtc = DateTime.UtcNow; + await ReplaceItemAsync(item); + + return new InventoryMutationResult + { + Status = InventoryMutationStatus.Ok, + OwnerType = item.OwnerType, + OwnerId = item.OwnerId, + Items = await GetByOwnerAsync(item.OwnerType, item.OwnerId) + }; + } + + public async Task UnequipAsync(string itemId, string ownerId, int? preferredSlot, string userId, bool allowAnyOwner) + { + var owner = await ResolveOwnerAsync(CharacterOwnerType, ownerId, userId, allowAnyOwner); + if (!owner.Exists || !owner.IsAuthorized) + return new InventoryMutationResult { Status = InventoryMutationStatus.Invalid }; + + var item = await _items.Find(i => i.Id == itemId).FirstOrDefaultAsync(); + if (item is null) + return new InventoryMutationResult { Status = InventoryMutationStatus.ItemNotFound }; + if (item.OwnerType != CharacterOwnerType || item.OwnerId != ownerId || string.IsNullOrWhiteSpace(item.EquippedSlot)) + return new InventoryMutationResult { Status = InventoryMutationStatus.Invalid }; + + var slot = preferredSlot ?? await FindFirstOpenSlotAsync(item.OwnerType, item.OwnerId); + var existing = await FindItemBySlotAsync(item.OwnerType, item.OwnerId, slot); + if (existing is not null && existing.Id != item.Id) + return new InventoryMutationResult { Status = InventoryMutationStatus.Conflict }; + + item.EquippedSlot = null; + item.Slot = slot; + item.UpdatedUtc = DateTime.UtcNow; + await ReplaceItemAsync(item); + + return new InventoryMutationResult + { + Status = InventoryMutationStatus.Ok, + OwnerType = item.OwnerType, + OwnerId = item.OwnerId, + Items = await GetByOwnerAsync(item.OwnerType, item.OwnerId) + }; + } + + private static string? NormalizeOwnerType(string ownerType) + { + var normalized = ownerType.Trim().ToLowerInvariant(); + return normalized switch + { + CharacterOwnerType => CharacterOwnerType, + LocationOwnerType => LocationOwnerType, + _ => null + }; + } + + private async Task FindFirstOpenSlotAsync(string ownerType, string ownerId, IClientSessionHandle? session = null) + { + var items = session is null + ? await GetByOwnerAsync(ownerType, ownerId) + : await _items.Find(session, i => i.OwnerType == ownerType && i.OwnerId == ownerId).ToListAsync(); + + var usedSlots = items.Where(i => i.Slot.HasValue).Select(i => i.Slot!.Value).ToHashSet(); + var slot = 0; + while (usedSlots.Contains(slot)) + slot += 1; + return slot; + } + + private Task FindItemBySlotAsync(string ownerType, string ownerId, int slot, IClientSessionHandle? session = null) + => session is null + ? FindItemBySlotNoSessionAsync(ownerType, ownerId, slot) + : FindItemBySlotWithSessionAsync(ownerType, ownerId, slot, session); + + private Task FindStackAsync(string ownerType, string ownerId, string itemKey, int slot, IClientSessionHandle? session = null) + => session is null + ? FindStackNoSessionAsync(ownerType, ownerId, itemKey, slot) + : FindStackWithSessionAsync(ownerType, ownerId, itemKey, slot, session); + + private async Task InsertItemAsync(InventoryItem item, IClientSessionHandle? session = null) + { + item.ItemKey = item.ItemKey.Trim(); + item.OwnerType = item.OwnerType.Trim().ToLowerInvariant(); + item.CreatedUtc = DateTime.UtcNow; + item.UpdatedUtc = item.CreatedUtc; + + if (session is null) + await _items.InsertOneAsync(item); + else + await _items.InsertOneAsync(session, item); + } + + private async Task ReplaceItemAsync(InventoryItem item, IClientSessionHandle? session = null) + { + item.UpdatedUtc = DateTime.UtcNow; + if (session is null) + await _items.ReplaceOneAsync(i => i.Id == item.Id, item); + else + await _items.ReplaceOneAsync(session, i => i.Id == item.Id, item); + } + + private Task DeleteItemAsync(string itemId, IClientSessionHandle? session = null) + { + return session is null + ? _items.DeleteOneAsync(i => i.Id == itemId) + : _items.DeleteOneAsync(session, i => i.Id == itemId); + } + + private bool IsStackable(string itemKey) => _stackableItemKeys.Contains(itemKey.Trim().ToLowerInvariant()); + + private bool CanMerge(InventoryItem source, InventoryItem target) => + source.ItemKey == target.ItemKey && + source.EquippedSlot is null && + target.EquippedSlot is null && + IsStackable(source.ItemKey); + + private void EnsureIndexes() + { + _items.Indexes.CreateOne(new CreateIndexModel( + Builders.IndexKeys.Ascending(i => i.Id), + new CreateIndexOptions { Unique = true, Name = ItemIdIndexName })); + + _items.Indexes.CreateOne(new CreateIndexModel( + Builders.IndexKeys.Ascending(i => i.OwnerType).Ascending(i => i.OwnerId), + new CreateIndexOptions { Name = OwnerIndexName })); + + _items.Indexes.CreateOne(new CreateIndexModel( + Builders.IndexKeys.Ascending(i => i.OwnerType).Ascending(i => i.OwnerId).Ascending(i => i.Slot), + new CreateIndexOptions + { + Unique = true, + Name = SlotIndexName, + PartialFilterExpression = Builders.Filter.Ne(i => i.Slot, null) + })); + + _items.Indexes.CreateOne(new CreateIndexModel( + Builders.IndexKeys.Ascending(i => i.OwnerType).Ascending(i => i.OwnerId).Ascending(i => i.EquippedSlot), + new CreateIndexOptions + { + Unique = true, + Name = EquippedSlotIndexName, + PartialFilterExpression = Builders.Filter.Ne(i => i.EquippedSlot, null) + })); + } + + private async Task FindItemBySlotNoSessionAsync(string ownerType, string ownerId, int slot) => + await _items.Find(i => i.OwnerType == ownerType && i.OwnerId == ownerId && i.Slot == slot).FirstOrDefaultAsync(); + + private async Task FindItemBySlotWithSessionAsync(string ownerType, string ownerId, int slot, IClientSessionHandle session) => + await _items.Find(session, i => i.OwnerType == ownerType && i.OwnerId == ownerId && i.Slot == slot).FirstOrDefaultAsync(); + + private async Task FindStackNoSessionAsync(string ownerType, string ownerId, string itemKey, int slot) => + await _items.Find(i => i.OwnerType == ownerType && i.OwnerId == ownerId && i.Slot == slot && i.ItemKey == itemKey && i.EquippedSlot == null).FirstOrDefaultAsync(); + + private async Task FindStackWithSessionAsync(string ownerType, string ownerId, string itemKey, int slot, IClientSessionHandle session) => + await _items.Find(session, i => i.OwnerType == ownerType && i.OwnerId == ownerId && i.Slot == slot && i.ItemKey == itemKey && i.EquippedSlot == null).FirstOrDefaultAsync(); + + private class CharacterOwnerDocument + { + [MongoDB.Bson.Serialization.Attributes.BsonId] + [MongoDB.Bson.Serialization.Attributes.BsonRepresentation(MongoDB.Bson.BsonType.ObjectId)] + public string? Id { get; set; } + + public string OwnerUserId { get; set; } = string.Empty; + } + + private class LocationOwnerDocument + { + [MongoDB.Bson.Serialization.Attributes.BsonId] + [MongoDB.Bson.Serialization.Attributes.BsonRepresentation(MongoDB.Bson.BsonType.ObjectId)] + public string? Id { get; set; } + } +} diff --git a/microservices/InventoryApi/appsettings.Development.json b/microservices/InventoryApi/appsettings.Development.json new file mode 100644 index 0000000..0c208ae --- /dev/null +++ b/microservices/InventoryApi/appsettings.Development.json @@ -0,0 +1,8 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + } +} diff --git a/microservices/InventoryApi/appsettings.json b/microservices/InventoryApi/appsettings.json new file mode 100644 index 0000000..b461ae5 --- /dev/null +++ b/microservices/InventoryApi/appsettings.json @@ -0,0 +1,7 @@ +{ + "Kestrel": { "Endpoints": { "Http": { "Url": "http://0.0.0.0:5003" } } }, + "MongoDB": { "ConnectionString": "mongodb://192.168.86.50:27017", "DatabaseName": "promiscuity" }, + "Jwt": { "Key": "SuperUltraSecureJwtKeyWithAtLeast32Chars!!", "Issuer": "promiscuity", "Audience": "promiscuity-auth-api" }, + "Logging": { "LogLevel": { "Default": "Information" } }, + "AllowedHosts": "*" +} diff --git a/microservices/InventoryApi/k8s/deployment.yaml b/microservices/InventoryApi/k8s/deployment.yaml new file mode 100644 index 0000000..a54590b --- /dev/null +++ b/microservices/InventoryApi/k8s/deployment.yaml @@ -0,0 +1,28 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: promiscuity-inventory + labels: + app: promiscuity-inventory +spec: + replicas: 2 + selector: + matchLabels: + app: promiscuity-inventory + template: + metadata: + labels: + app: promiscuity-inventory + spec: + containers: + - name: promiscuity-inventory + image: promiscuity-inventory:latest + imagePullPolicy: IfNotPresent + ports: + - containerPort: 5003 + readinessProbe: + httpGet: + path: /healthz + port: 5003 + initialDelaySeconds: 5 + periodSeconds: 10 diff --git a/microservices/InventoryApi/k8s/service.yaml b/microservices/InventoryApi/k8s/service.yaml new file mode 100644 index 0000000..8417b75 --- /dev/null +++ b/microservices/InventoryApi/k8s/service.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Service +metadata: + name: promiscuity-inventory + labels: + app: promiscuity-inventory +spec: + selector: + app: promiscuity-inventory + type: NodePort + ports: + - name: http + port: 80 + targetPort: 5003 + nodePort: 30083 diff --git a/microservices/README.md b/microservices/README.md index f849d14..bb28261 100644 --- a/microservices/README.md +++ b/microservices/README.md @@ -3,10 +3,12 @@ ## Document shapes - AuthApi: `AuthApi/DOCUMENTS.md` (auth request payloads and user document shape) - CharacterApi: `CharacterApi/DOCUMENTS.md` (character create payload and stored document) +- InventoryApi: `InventoryApi/DOCUMENTS.md` (inventory mutation payloads and stored document) - LocationsApi: `LocationsApi/DOCUMENTS.md` (location create/update payloads and stored document) ## Service READMEs - AuthApi: `AuthApi/README.md` - CharacterApi: `CharacterApi/README.md` +- InventoryApi: `InventoryApi/README.md` - LocationsApi: `LocationsApi/README.md` diff --git a/microservices/micro-services.sln b/microservices/micro-services.sln index 4d1a08d..685a13a 100644 --- a/microservices/micro-services.sln +++ b/microservices/micro-services.sln @@ -8,11 +8,13 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CharacterApi", "CharacterAp EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LocationsApi", "LocationsApi\LocationsApi.csproj", "{C343AFFB-9AB0-4B70-834C-3D2A21E2B506}" EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "InventoryApi", "InventoryApi\InventoryApi.csproj", "{72AA73C5-6A42-4F79-ADCC-19F10A66B9E0}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {334F3B23-EFE8-6F1A-5E5F-9A2275D56E28}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {334F3B23-EFE8-6F1A-5E5F-9A2275D56E28}.Debug|Any CPU.Build.0 = Debug|Any CPU @@ -26,7 +28,11 @@ Global {C343AFFB-9AB0-4B70-834C-3D2A21E2B506}.Debug|Any CPU.Build.0 = Debug|Any CPU {C343AFFB-9AB0-4B70-834C-3D2A21E2B506}.Release|Any CPU.ActiveCfg = Release|Any CPU {C343AFFB-9AB0-4B70-834C-3D2A21E2B506}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection + {72AA73C5-6A42-4F79-ADCC-19F10A66B9E0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {72AA73C5-6A42-4F79-ADCC-19F10A66B9E0}.Debug|Any CPU.Build.0 = Debug|Any CPU + {72AA73C5-6A42-4F79-ADCC-19F10A66B9E0}.Release|Any CPU.ActiveCfg = Release|Any CPU + {72AA73C5-6A42-4F79-ADCC-19F10A66B9E0}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection From 5287ecd56f88f215e5fe9a42c0c7e6a2aba7a8a5 Mon Sep 17 00:00:00 2001 From: Zeeshaun Date: Sun, 15 Mar 2026 13:15:49 -0500 Subject: [PATCH 17/19] Adding workflow for inventory microservice --- .gitea/workflows/deploy-inventory.yml | 112 ++++++++++++++++++++++++++ 1 file changed, 112 insertions(+) create mode 100644 .gitea/workflows/deploy-inventory.yml diff --git a/.gitea/workflows/deploy-inventory.yml b/.gitea/workflows/deploy-inventory.yml new file mode 100644 index 0000000..24e370d --- /dev/null +++ b/.gitea/workflows/deploy-inventory.yml @@ -0,0 +1,112 @@ +name: Deploy Promiscuity Inventory API + +on: + push: + branches: + - main + workflow_dispatch: {} + +jobs: + deploy: + runs-on: self-hosted + + env: + IMAGE_NAME: promiscuity-inventory:latest + IMAGE_TAR: /tmp/promiscuity-inventory.tar + # All nodes that might run the pod (control-plane + workers) + NODES: "192.168.86.72 192.168.86.73 192.168.86.74" + + steps: + - name: Checkout repo + uses: actions/checkout@v4 + + # ----------------------------- + # Build Docker image + # ----------------------------- + - name: Build Docker image + run: | + cd microservices/InventoryApi + docker build -t "${IMAGE_NAME}" . + + # ----------------------------- + # Save image as TAR on runner + # ----------------------------- + - name: Save Docker image to TAR + run: | + docker save "${IMAGE_NAME}" -o "${IMAGE_TAR}" + + # ----------------------------- + # Copy TAR to each Kubernetes node + # ----------------------------- + - name: Copy TAR to nodes + run: | + for node in ${NODES}; do + echo "Copying image tar to $node ..." + scp -o StrictHostKeyChecking=no "${IMAGE_TAR}" hz@"$node":/tmp/promiscuity-inventory.tar + done + + # ----------------------------- + # Import image into containerd on each node + # ----------------------------- + - name: Import image on nodes + run: | + for node in ${NODES}; do + echo "Importing image on $node ..." + ssh -o StrictHostKeyChecking=no hz@"$node" "sudo ctr -n k8s.io images import /tmp/promiscuity-inventory.tar" + done + + # ----------------------------- + # CLEANUP: delete TAR from nodes + # ----------------------------- + - name: Clean TAR from nodes + run: | + for node in ${NODES}; do + echo "Removing image tar on $node ..." + ssh -o StrictHostKeyChecking=no hz@"$node" "rm -f /tmp/promiscuity-inventory.tar" + done + + # ----------------------------- + # CLEANUP: delete TAR from runner + # ----------------------------- + - name: Clean TAR on runner + run: | + rm -f "${IMAGE_TAR}" + + # ----------------------------- + # Write kubeconfig from secret + # ----------------------------- + - name: Write kubeconfig from secret + env: + KUBECONFIG_CONTENT: ${{ secrets.KUBECONFIG }} + run: | + mkdir -p /tmp/kube + printf '%s\n' "$KUBECONFIG_CONTENT" > /tmp/kube/config + + # ----------------------------- + # Ensure namespace exists + # ----------------------------- + - name: Create namespace if missing + env: + KUBECONFIG: /tmp/kube/config + run: | + kubectl create namespace promiscuity-inventory --dry-run=client -o yaml | kubectl apply -f - + + # ----------------------------- + # Apply Kubernetes manifests + # ----------------------------- + - name: Apply Inventory deployment & service + env: + KUBECONFIG: /tmp/kube/config + run: | + kubectl apply -f microservices/InventoryApi/k8s/deployment.yaml -n promiscuity-inventory + kubectl apply -f microservices/InventoryApi/k8s/service.yaml -n promiscuity-inventory + + # ----------------------------- + # Rollout restart & wait + # ----------------------------- + - name: Restart Inventory deployment + env: + KUBECONFIG: /tmp/kube/config + run: | + kubectl rollout restart deployment/promiscuity-inventory -n promiscuity-inventory + kubectl rollout status deployment/promiscuity-inventory -n promiscuity-inventory From a2a4d48de52ff17f5624fb2836b7ea250560fbd3 Mon Sep 17 00:00:00 2001 From: Zeeshaun Date: Sun, 15 Mar 2026 13:57:15 -0500 Subject: [PATCH 18/19] Inventory enhancements --- .../Controllers/InventoryController.cs | 63 ++++++- microservices/InventoryApi/DOCUMENTS.md | 57 +++++- .../Models/CreateItemDefinitionRequest.cs | 16 ++ .../InventoryApi/Models/ItemDefinition.cs | 33 ++++ .../Models/ItemDefinitionResponse.cs | 29 +++ .../Models/UpdateItemDefinitionRequest.cs | 14 ++ microservices/InventoryApi/README.md | 8 + .../InventoryApi/Services/InventoryStore.cs | 176 +++++++++++++----- 8 files changed, 351 insertions(+), 45 deletions(-) create mode 100644 microservices/InventoryApi/Models/CreateItemDefinitionRequest.cs create mode 100644 microservices/InventoryApi/Models/ItemDefinition.cs create mode 100644 microservices/InventoryApi/Models/ItemDefinitionResponse.cs create mode 100644 microservices/InventoryApi/Models/UpdateItemDefinitionRequest.cs diff --git a/microservices/InventoryApi/Controllers/InventoryController.cs b/microservices/InventoryApi/Controllers/InventoryController.cs index 85c3c0b..7dd51c9 100644 --- a/microservices/InventoryApi/Controllers/InventoryController.cs +++ b/microservices/InventoryApi/Controllers/InventoryController.cs @@ -17,6 +17,63 @@ public class InventoryController : ControllerBase _inventory = inventory; } + [HttpGet("item-definitions")] + [Authorize(Roles = "USER,SUPER")] + public async Task ListItemDefinitions() + { + var definitions = await _inventory.ListItemDefinitionsAsync(); + return Ok(definitions.Select(ItemDefinitionResponse.FromModel).ToList()); + } + + [HttpGet("item-definitions/{itemKey}")] + [Authorize(Roles = "USER,SUPER")] + public async Task GetItemDefinition(string itemKey) + { + var definition = await _inventory.GetItemDefinitionAsync(itemKey); + if (definition is null) + return NotFound(); + + return Ok(ItemDefinitionResponse.FromModel(definition)); + } + + [HttpPost("item-definitions")] + [Authorize(Roles = "SUPER")] + public async Task CreateItemDefinition([FromBody] CreateItemDefinitionRequest req) + { + if (string.IsNullOrWhiteSpace(req.ItemKey)) + return BadRequest("itemKey required"); + if (string.IsNullOrWhiteSpace(req.DisplayName)) + return BadRequest("displayName required"); + if (req.MaxStackSize <= 0) + return BadRequest("maxStackSize must be greater than 0"); + if (!req.Stackable && req.MaxStackSize != 1) + return BadRequest("Non-stackable items must have maxStackSize of 1"); + + var created = await _inventory.CreateItemDefinitionAsync(req); + if (created is null) + return Conflict("Item definition already exists"); + + return Ok(ItemDefinitionResponse.FromModel(created)); + } + + [HttpPut("item-definitions/{itemKey}")] + [Authorize(Roles = "SUPER")] + public async Task UpdateItemDefinition(string itemKey, [FromBody] UpdateItemDefinitionRequest req) + { + if (string.IsNullOrWhiteSpace(req.DisplayName)) + return BadRequest("displayName required"); + if (req.MaxStackSize <= 0) + return BadRequest("maxStackSize must be greater than 0"); + if (!req.Stackable && req.MaxStackSize != 1) + return BadRequest("Non-stackable items must have maxStackSize of 1"); + + var updated = await _inventory.UpdateItemDefinitionAsync(itemKey, req); + if (updated is null) + return NotFound(); + + return Ok(ItemDefinitionResponse.FromModel(updated)); + } + [HttpGet("by-owner/{ownerType}/{ownerId}")] [Authorize(Roles = "USER,SUPER")] public async Task GetByOwner(string ownerType, string ownerId) @@ -63,7 +120,11 @@ public class InventoryController : ControllerBase if (!access.IsAuthorized) return Forbid(); - var items = await _inventory.GrantAsync(access, req); + var definition = await _inventory.GetItemDefinitionAsync(req.ItemKey); + if (definition is null) + return BadRequest("Unknown itemKey"); + + var items = await _inventory.GrantAsync(access, req, definition); return Ok(new InventoryOwnerResponse { OwnerType = access.OwnerType, diff --git a/microservices/InventoryApi/DOCUMENTS.md b/microservices/InventoryApi/DOCUMENTS.md index 88d0c86..05e00a5 100644 --- a/microservices/InventoryApi/DOCUMENTS.md +++ b/microservices/InventoryApi/DOCUMENTS.md @@ -3,6 +3,29 @@ This service stores one MongoDB document per inventory item record. Inbound JSON documents +- CreateItemDefinitionRequest (`POST /api/inventory/item-definitions`) + ```json + { + "itemKey": "wood", + "displayName": "Wood", + "stackable": true, + "maxStackSize": 20, + "category": "resource", + "equipSlot": null + } + ``` + +- UpdateItemDefinitionRequest (`PUT /api/inventory/item-definitions/{itemKey}`) + ```json + { + "displayName": "Wood", + "stackable": true, + "maxStackSize": 20, + "category": "resource", + "equipSlot": null + } + ``` + - GrantInventoryItemRequest (`POST /api/inventory/by-owner/{ownerType}/{ownerId}/grant`) ```json { @@ -63,6 +86,20 @@ Inbound JSON documents Only valid for items currently equipped by a character. Stored documents (MongoDB) +- ItemDefinition + ```json + { + "itemKey": "wood", + "displayName": "Wood", + "stackable": true, + "maxStackSize": 20, + "category": "resource", + "equipSlot": null, + "createdUtc": "string (ISO-8601 datetime)", + "updatedUtc": "string (ISO-8601 datetime)" + } + ``` + - InventoryItem ```json { @@ -112,6 +149,19 @@ Location stack example: ``` Outbound JSON documents +- ItemDefinitionResponse + ```json + { + "itemKey": "wood", + "displayName": "Wood", + "stackable": true, + "maxStackSize": 20, + "category": "resource", + "equipSlot": null, + "updatedUtc": "string (ISO-8601 datetime)" + } + ``` + - InventoryItemResponse ```json { @@ -160,10 +210,12 @@ Outbound JSON documents ``` Validation rules +- `itemKey` must map to an existing item definition before item instances can be created - `ownerType` must be a supported container type - `ownerId` must map to an existing owning entity where applicable - non-`SUPER` callers may only access owned character items unless explicit gameplay rules allow a world container read/write - `quantity` must be greater than `0` +- non-stackable item definitions must have `maxStackSize = 1` - non-stackable items must have `quantity = 1` - equipped items must have `slot = null` - unequipped bag items must have `equippedSlot = null` @@ -172,11 +224,11 @@ Validation rules - equipment occupancy must be unique for `(ownerType, ownerId, equippedSlot)` where `equippedSlot != null` Recommended indexes -- unique on `id` +- unique on `itemKey` for item definitions - index on `(ownerType, ownerId)` - unique on `(ownerType, ownerId, slot)` for bag slots - unique on `(ownerType, ownerId, equippedSlot)` for equipped slots -- index on `itemKey` +- index on `itemKey` for inventory items Behavior rules - moving a full non-stackable item should update its owner and slot in place @@ -184,3 +236,4 @@ Behavior rules - moving into a compatible stack should merge quantities and delete or reduce the source record - cross-owner transfer should be transactional when it mutates multiple records - auctions should reference `itemId` values directly instead of copying item state into the auction document +- the service does not auto-seed item definitions; `ItemDefinitions` must be populated explicitly diff --git a/microservices/InventoryApi/Models/CreateItemDefinitionRequest.cs b/microservices/InventoryApi/Models/CreateItemDefinitionRequest.cs new file mode 100644 index 0000000..1a141c6 --- /dev/null +++ b/microservices/InventoryApi/Models/CreateItemDefinitionRequest.cs @@ -0,0 +1,16 @@ +namespace InventoryApi.Models; + +public class CreateItemDefinitionRequest +{ + public string ItemKey { get; set; } = string.Empty; + + public string DisplayName { get; set; } = string.Empty; + + public bool Stackable { get; set; } + + public int MaxStackSize { get; set; } = 1; + + public string Category { get; set; } = "misc"; + + public string? EquipSlot { get; set; } +} diff --git a/microservices/InventoryApi/Models/ItemDefinition.cs b/microservices/InventoryApi/Models/ItemDefinition.cs new file mode 100644 index 0000000..9cb8b98 --- /dev/null +++ b/microservices/InventoryApi/Models/ItemDefinition.cs @@ -0,0 +1,33 @@ +using MongoDB.Bson.Serialization.Attributes; + +namespace InventoryApi.Models; + +[BsonIgnoreExtraElements] +public class ItemDefinition +{ + [BsonId] + [BsonElement("itemKey")] + public string ItemKey { get; set; } = string.Empty; + + [BsonElement("displayName")] + public string DisplayName { get; set; } = string.Empty; + + [BsonElement("stackable")] + public bool Stackable { get; set; } + + [BsonElement("maxStackSize")] + public int MaxStackSize { get; set; } = 1; + + [BsonElement("category")] + public string Category { get; set; } = "misc"; + + [BsonElement("equipSlot")] + [BsonIgnoreIfNull] + public string? EquipSlot { get; set; } + + [BsonElement("createdUtc")] + public DateTime CreatedUtc { get; set; } = DateTime.UtcNow; + + [BsonElement("updatedUtc")] + public DateTime UpdatedUtc { get; set; } = DateTime.UtcNow; +} diff --git a/microservices/InventoryApi/Models/ItemDefinitionResponse.cs b/microservices/InventoryApi/Models/ItemDefinitionResponse.cs new file mode 100644 index 0000000..5f8e31f --- /dev/null +++ b/microservices/InventoryApi/Models/ItemDefinitionResponse.cs @@ -0,0 +1,29 @@ +namespace InventoryApi.Models; + +public class ItemDefinitionResponse +{ + public string ItemKey { get; set; } = string.Empty; + + public string DisplayName { get; set; } = string.Empty; + + public bool Stackable { get; set; } + + public int MaxStackSize { get; set; } + + public string Category { get; set; } = "misc"; + + public string? EquipSlot { get; set; } + + public DateTime UpdatedUtc { get; set; } + + public static ItemDefinitionResponse FromModel(ItemDefinition definition) => new() + { + ItemKey = definition.ItemKey, + DisplayName = definition.DisplayName, + Stackable = definition.Stackable, + MaxStackSize = definition.MaxStackSize, + Category = definition.Category, + EquipSlot = definition.EquipSlot, + UpdatedUtc = definition.UpdatedUtc + }; +} diff --git a/microservices/InventoryApi/Models/UpdateItemDefinitionRequest.cs b/microservices/InventoryApi/Models/UpdateItemDefinitionRequest.cs new file mode 100644 index 0000000..58165ac --- /dev/null +++ b/microservices/InventoryApi/Models/UpdateItemDefinitionRequest.cs @@ -0,0 +1,14 @@ +namespace InventoryApi.Models; + +public class UpdateItemDefinitionRequest +{ + public string DisplayName { get; set; } = string.Empty; + + public bool Stackable { get; set; } + + public int MaxStackSize { get; set; } = 1; + + public string Category { get; set; } = "misc"; + + public string? EquipSlot { get; set; } +} diff --git a/microservices/InventoryApi/README.md b/microservices/InventoryApi/README.md index 9afa356..b95d50c 100644 --- a/microservices/InventoryApi/README.md +++ b/microservices/InventoryApi/README.md @@ -104,6 +104,14 @@ Optional future fields: - slot occupancy must be unique per `(ownerType, ownerId, slot)` - all mutating endpoints should be idempotent where practical +## Definition source +Item behavior is fully data-driven through the `ItemDefinitions` collection inside `InventoryApi`. + +That means: +- no hardcoded stack-size rules +- no automatic item-definition seeding +- item instances can only be created for `itemKey` values that already exist in `ItemDefinitions` + ## Client shape The Godot client should fetch all items for the currently relevant owner and group them into a bag view locally. diff --git a/microservices/InventoryApi/Services/InventoryStore.cs b/microservices/InventoryApi/Services/InventoryStore.cs index 823ec97..8f2cea6 100644 --- a/microservices/InventoryApi/Services/InventoryStore.cs +++ b/microservices/InventoryApi/Services/InventoryStore.cs @@ -8,17 +8,17 @@ public class InventoryStore { private const string CharacterOwnerType = "character"; private const string LocationOwnerType = "location"; - private const string ItemIdIndexName = "item_id_unique"; private const string OwnerIndexName = "owner_type_1_owner_id_1"; private const string SlotIndexName = "owner_type_1_owner_id_1_slot_1"; private const string EquippedSlotIndexName = "owner_type_1_owner_id_1_equipped_slot_1"; + private const string DefinitionCategoryIndexName = "category_1"; private readonly IMongoCollection _items; + private readonly IMongoCollection _definitions; private readonly IMongoCollection _characters; private readonly IMongoCollection _locations; private readonly IMongoClient _client; private readonly string _dbName; - private readonly HashSet _stackableItemKeys = ["wood", "stone", "small_health_potion"]; public InventoryStore(IConfiguration cfg) { @@ -27,6 +27,7 @@ public class InventoryStore _client = new MongoClient(cs); var db = _client.GetDatabase(_dbName); _items = db.GetCollection("InventoryItems"); + _definitions = db.GetCollection("ItemDefinitions"); _characters = db.GetCollection("Characters"); _locations = db.GetCollection("Locations"); @@ -84,30 +85,92 @@ public class InventoryStore .ThenBy(i => i.ItemKey) .ToListAsync(); - public async Task> GrantAsync(OwnerAccessResult owner, GrantInventoryItemRequest req) - { - var normalizedKey = req.ItemKey.Trim(); - if (IsStackable(normalizedKey)) - { - var targetSlot = req.PreferredSlot ?? await FindFirstOpenSlotAsync(owner.OwnerType, owner.OwnerId); - var existing = await FindStackAsync(owner.OwnerType, owner.OwnerId, normalizedKey, targetSlot); - if (existing is not null) - { - existing.Quantity += req.Quantity; - existing.UpdatedUtc = DateTime.UtcNow; - await ReplaceItemAsync(existing); - return await GetByOwnerAsync(owner.OwnerType, owner.OwnerId); - } + public Task> ListItemDefinitionsAsync() => + _definitions.Find(Builders.Filter.Empty).SortBy(d => d.ItemKey).ToListAsync(); - await InsertItemAsync(new InventoryItem + public async Task GetItemDefinitionAsync(string itemKey) => + await _definitions.Find(d => d.ItemKey == NormalizeItemKey(itemKey)).FirstOrDefaultAsync(); + + public async Task CreateItemDefinitionAsync(CreateItemDefinitionRequest req) + { + var itemKey = NormalizeItemKey(req.ItemKey); + var existing = await GetItemDefinitionAsync(itemKey); + if (existing is not null) + return null; + + var definition = new ItemDefinition + { + ItemKey = itemKey, + DisplayName = req.DisplayName.Trim(), + Stackable = req.Stackable, + MaxStackSize = req.Stackable ? req.MaxStackSize : 1, + Category = string.IsNullOrWhiteSpace(req.Category) ? "misc" : req.Category.Trim().ToLowerInvariant(), + EquipSlot = string.IsNullOrWhiteSpace(req.EquipSlot) ? null : req.EquipSlot.Trim().ToLowerInvariant(), + CreatedUtc = DateTime.UtcNow, + UpdatedUtc = DateTime.UtcNow + }; + + await _definitions.InsertOneAsync(definition); + return definition; + } + + public async Task UpdateItemDefinitionAsync(string itemKey, UpdateItemDefinitionRequest req) + { + var existing = await GetItemDefinitionAsync(itemKey); + if (existing is null) + return null; + + existing.DisplayName = req.DisplayName.Trim(); + existing.Stackable = req.Stackable; + existing.MaxStackSize = req.Stackable ? req.MaxStackSize : 1; + existing.Category = string.IsNullOrWhiteSpace(req.Category) ? "misc" : req.Category.Trim().ToLowerInvariant(); + existing.EquipSlot = string.IsNullOrWhiteSpace(req.EquipSlot) ? null : req.EquipSlot.Trim().ToLowerInvariant(); + existing.UpdatedUtc = DateTime.UtcNow; + + await _definitions.ReplaceOneAsync(d => d.ItemKey == existing.ItemKey, existing); + return existing; + } + + public async Task> GrantAsync(OwnerAccessResult owner, GrantInventoryItemRequest req, ItemDefinition definition) + { + var normalizedKey = NormalizeItemKey(req.ItemKey); + if (definition.Stackable) + { + var remaining = req.Quantity; + var targetSlot = req.PreferredSlot; + while (remaining > 0) { - ItemKey = normalizedKey, - Quantity = req.Quantity, - OwnerType = owner.OwnerType, - OwnerId = owner.OwnerId, - OwnerUserId = owner.OwnerUserId, - Slot = targetSlot - }); + var slot = targetSlot ?? await FindFirstOpenSlotAsync(owner.OwnerType, owner.OwnerId); + var existing = await FindStackAsync(owner.OwnerType, owner.OwnerId, normalizedKey, slot); + if (existing is not null) + { + var availableSpace = definition.MaxStackSize - existing.Quantity; + if (availableSpace > 0) + { + var added = Math.Min(remaining, availableSpace); + existing.Quantity += added; + existing.UpdatedUtc = DateTime.UtcNow; + await ReplaceItemAsync(existing); + remaining -= added; + } + } + else + { + var stackQuantity = Math.Min(remaining, definition.MaxStackSize); + await InsertItemAsync(new InventoryItem + { + ItemKey = normalizedKey, + Quantity = stackQuantity, + OwnerType = owner.OwnerType, + OwnerId = owner.OwnerId, + OwnerUserId = owner.OwnerUserId, + Slot = slot + }); + remaining -= stackQuantity; + } + + targetSlot = null; + } return await GetByOwnerAsync(owner.OwnerType, owner.OwnerId); } @@ -141,21 +204,29 @@ public class InventoryStore if (quantity <= 0 || quantity > item.Quantity) return new InventoryMutationResult { Status = InventoryMutationStatus.Invalid }; + var definition = await GetItemDefinitionAsync(item.ItemKey); + if (definition is null) + return new InventoryMutationResult { Status = InventoryMutationStatus.Invalid }; + var existing = await FindItemBySlotAsync(owner.OwnerType, owner.OwnerId, req.ToSlot); if (existing is not null && existing.Id != item.Id) { - if (!CanMerge(item, existing)) + if (!CanMerge(item, existing, definition)) return new InventoryMutationResult { Status = InventoryMutationStatus.Conflict }; - existing.Quantity += quantity; + var transferable = Math.Min(quantity, definition.MaxStackSize - existing.Quantity); + if (transferable <= 0) + return new InventoryMutationResult { Status = InventoryMutationStatus.Conflict }; + + existing.Quantity += transferable; existing.UpdatedUtc = DateTime.UtcNow; await ReplaceItemAsync(existing); - if (quantity == item.Quantity) + if (transferable == item.Quantity) await DeleteItemAsync(item.Id); else { - item.Quantity -= quantity; + item.Quantity -= transferable; item.UpdatedUtc = DateTime.UtcNow; await ReplaceItemAsync(item); } @@ -219,9 +290,16 @@ public class InventoryStore return new InventoryMutationResult { Status = InventoryMutationStatus.Invalid }; } + var definition = await GetItemDefinitionAsync(item.ItemKey); + if (definition is null) + { + await session.AbortTransactionAsync(); + return new InventoryMutationResult { Status = InventoryMutationStatus.Invalid }; + } + var toSlot = req.ToSlot ?? await FindFirstOpenSlotAsync(toOwner.OwnerType, toOwner.OwnerId, session); var target = await FindItemBySlotAsync(toOwner.OwnerType, toOwner.OwnerId, toSlot, session); - if (target is not null && !CanMerge(item, target)) + if (target is not null && !CanMerge(item, target, definition)) { await session.AbortTransactionAsync(); return new InventoryMutationResult { Status = InventoryMutationStatus.Conflict }; @@ -229,15 +307,22 @@ public class InventoryStore if (target is not null) { - target.Quantity += quantity; + var transferable = Math.Min(quantity, definition.MaxStackSize - target.Quantity); + if (transferable <= 0) + { + await session.AbortTransactionAsync(); + return new InventoryMutationResult { Status = InventoryMutationStatus.Conflict }; + } + + target.Quantity += transferable; target.UpdatedUtc = DateTime.UtcNow; await ReplaceItemAsync(target, session); - if (quantity == item.Quantity) + if (transferable == item.Quantity) await DeleteItemAsync(item.Id, session); else { - item.Quantity -= quantity; + item.Quantity -= transferable; item.UpdatedUtc = DateTime.UtcNow; await ReplaceItemAsync(item, session); } @@ -326,6 +411,11 @@ public class InventoryStore return new InventoryMutationResult { Status = InventoryMutationStatus.ItemNotFound }; if (item.OwnerType != CharacterOwnerType || item.OwnerId != ownerId || item.Slot is null) return new InventoryMutationResult { Status = InventoryMutationStatus.Invalid }; + var definition = await GetItemDefinitionAsync(item.ItemKey); + if (definition is null) + return new InventoryMutationResult { Status = InventoryMutationStatus.Invalid }; + if (!string.Equals(definition.EquipSlot, equipmentSlot.Trim(), StringComparison.OrdinalIgnoreCase)) + return new InventoryMutationResult { Status = InventoryMutationStatus.Invalid }; var equipped = await _items.Find(i => i.OwnerType == CharacterOwnerType && @@ -415,7 +505,7 @@ public class InventoryStore private async Task InsertItemAsync(InventoryItem item, IClientSessionHandle? session = null) { - item.ItemKey = item.ItemKey.Trim(); + item.ItemKey = NormalizeItemKey(item.ItemKey); item.OwnerType = item.OwnerType.Trim().ToLowerInvariant(); item.CreatedUtc = DateTime.UtcNow; item.UpdatedUtc = item.CreatedUtc; @@ -442,20 +532,16 @@ public class InventoryStore : _items.DeleteOneAsync(session, i => i.Id == itemId); } - private bool IsStackable(string itemKey) => _stackableItemKeys.Contains(itemKey.Trim().ToLowerInvariant()); + private static string NormalizeItemKey(string itemKey) => itemKey.Trim().ToLowerInvariant(); - private bool CanMerge(InventoryItem source, InventoryItem target) => + private static bool CanMerge(InventoryItem source, InventoryItem target, ItemDefinition definition) => source.ItemKey == target.ItemKey && source.EquippedSlot is null && target.EquippedSlot is null && - IsStackable(source.ItemKey); + definition.Stackable; private void EnsureIndexes() { - _items.Indexes.CreateOne(new CreateIndexModel( - Builders.IndexKeys.Ascending(i => i.Id), - new CreateIndexOptions { Unique = true, Name = ItemIdIndexName })); - _items.Indexes.CreateOne(new CreateIndexModel( Builders.IndexKeys.Ascending(i => i.OwnerType).Ascending(i => i.OwnerId), new CreateIndexOptions { Name = OwnerIndexName })); @@ -466,7 +552,7 @@ public class InventoryStore { Unique = true, Name = SlotIndexName, - PartialFilterExpression = Builders.Filter.Ne(i => i.Slot, null) + PartialFilterExpression = new BsonDocument("slot", new BsonDocument("$exists", true)) })); _items.Indexes.CreateOne(new CreateIndexModel( @@ -475,8 +561,12 @@ public class InventoryStore { Unique = true, Name = EquippedSlotIndexName, - PartialFilterExpression = Builders.Filter.Ne(i => i.EquippedSlot, null) + PartialFilterExpression = new BsonDocument("equippedSlot", new BsonDocument("$exists", true)) })); + + _definitions.Indexes.CreateOne(new CreateIndexModel( + Builders.IndexKeys.Ascending(d => d.Category), + new CreateIndexOptions { Name = DefinitionCategoryIndexName })); } private async Task FindItemBySlotNoSessionAsync(string ownerType, string ownerId, int slot) => @@ -491,6 +581,7 @@ public class InventoryStore private async Task FindStackWithSessionAsync(string ownerType, string ownerId, string itemKey, int slot, IClientSessionHandle session) => await _items.Find(session, i => i.OwnerType == ownerType && i.OwnerId == ownerId && i.Slot == slot && i.ItemKey == itemKey && i.EquippedSlot == null).FirstOrDefaultAsync(); + [MongoDB.Bson.Serialization.Attributes.BsonIgnoreExtraElements] private class CharacterOwnerDocument { [MongoDB.Bson.Serialization.Attributes.BsonId] @@ -500,6 +591,7 @@ public class InventoryStore public string OwnerUserId { get; set; } = string.Empty; } + [MongoDB.Bson.Serialization.Attributes.BsonIgnoreExtraElements] private class LocationOwnerDocument { [MongoDB.Bson.Serialization.Attributes.BsonId] From 9ba725d2070ff20eb02833b073f6ba7b247db7ab Mon Sep 17 00:00:00 2001 From: Zeeshaun Date: Sun, 15 Mar 2026 14:04:12 -0500 Subject: [PATCH 19/19] Gathering infra --- .../Controllers/LocationsController.cs | 73 ++++++++- microservices/LocationsApi/DOCUMENTS.md | 27 ++++ .../Models/GatherResourceRequest.cs | 8 + .../Models/GatherResourceResponse.cs | 16 ++ microservices/LocationsApi/Models/Location.cs | 3 + .../LocationsApi/Models/LocationResource.cs | 15 ++ microservices/LocationsApi/Program.cs | 1 + .../LocationsApi/Services/LocationStore.cs | 138 +++++++++++++++--- .../LocationsApi/appsettings.Development.json | 13 +- microservices/LocationsApi/appsettings.json | 1 + 10 files changed, 273 insertions(+), 22 deletions(-) create mode 100644 microservices/LocationsApi/Models/GatherResourceRequest.cs create mode 100644 microservices/LocationsApi/Models/GatherResourceResponse.cs create mode 100644 microservices/LocationsApi/Models/LocationResource.cs diff --git a/microservices/LocationsApi/Controllers/LocationsController.cs b/microservices/LocationsApi/Controllers/LocationsController.cs index 6c9886f..aa33f88 100644 --- a/microservices/LocationsApi/Controllers/LocationsController.cs +++ b/microservices/LocationsApi/Controllers/LocationsController.cs @@ -3,6 +3,10 @@ using LocationsApi.Services; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using MongoDB.Driver; +using System.Net.Http.Headers; +using System.Security.Claims; +using System.Text; +using System.Text.Json; namespace LocationsApi.Controllers; @@ -11,10 +15,14 @@ namespace LocationsApi.Controllers; public class LocationsController : ControllerBase { private readonly LocationStore _locations; + private readonly IHttpClientFactory _httpClientFactory; + private readonly IConfiguration _configuration; - public LocationsController(LocationStore locations) + public LocationsController(LocationStore locations, IHttpClientFactory httpClientFactory, IConfiguration configuration) { _locations = locations; + _httpClientFactory = httpClientFactory; + _configuration = configuration; } [HttpPost] @@ -85,4 +93,67 @@ public class LocationsController : ControllerBase return Ok("Updated"); } + + [HttpPost("{id}/gather")] + [Authorize(Roles = "USER,SUPER")] + public async Task Gather(string id, [FromBody] GatherResourceRequest req) + { + if (string.IsNullOrWhiteSpace(req.CharacterId)) + return BadRequest("characterId required"); + if (string.IsNullOrWhiteSpace(req.ResourceKey)) + return BadRequest("resourceKey required"); + + var userId = User.FindFirstValue(ClaimTypes.NameIdentifier); + if (string.IsNullOrWhiteSpace(userId)) + return Unauthorized(); + + var allowAnyOwner = User.IsInRole("SUPER"); + var gather = await _locations.GatherResourceAsync(id, req.CharacterId, req.ResourceKey, userId, allowAnyOwner); + if (gather.Status == GatherStatus.LocationNotFound) + return NotFound("Location not found"); + if (gather.Status == GatherStatus.CharacterNotFound) + return NotFound("Character not found"); + if (gather.Status == GatherStatus.Forbidden) + return Forbid(); + if (gather.Status == GatherStatus.Invalid) + return BadRequest("Character is not at the target location"); + if (gather.Status == GatherStatus.ResourceNotFound) + return NotFound("Resource not found at location"); + if (gather.Status == GatherStatus.ResourceDepleted) + return Conflict("Resource is depleted"); + + var inventoryBaseUrl = (_configuration["Services:InventoryApiBaseUrl"] ?? "http://localhost:5003").TrimEnd('/'); + var token = Request.Headers.Authorization.ToString(); + var grantBody = JsonSerializer.Serialize(new + { + itemKey = gather.ResourceKey, + quantity = gather.QuantityGranted + }); + + var client = _httpClientFactory.CreateClient(); + using var request = new HttpRequestMessage( + HttpMethod.Post, + $"{inventoryBaseUrl}/api/inventory/by-owner/character/{req.CharacterId}/grant"); + request.Content = new StringContent(grantBody, Encoding.UTF8, "application/json"); + if (!string.IsNullOrWhiteSpace(token)) + request.Headers.Authorization = AuthenticationHeaderValue.Parse(token); + + using var response = await client.SendAsync(request); + var responseBody = await response.Content.ReadAsStringAsync(); + if (!response.IsSuccessStatusCode) + { + await _locations.RestoreGatheredResourceAsync(id, gather.ResourceKey, gather.QuantityGranted); + return StatusCode((int)response.StatusCode, responseBody); + } + + return Ok(new GatherResourceResponse + { + LocationId = id, + CharacterId = req.CharacterId, + ResourceKey = gather.ResourceKey, + QuantityGranted = gather.QuantityGranted, + RemainingQuantity = gather.RemainingQuantity, + InventoryResponseJson = responseBody + }); + } } diff --git a/microservices/LocationsApi/DOCUMENTS.md b/microservices/LocationsApi/DOCUMENTS.md index 0df5336..9b85cb9 100644 --- a/microservices/LocationsApi/DOCUMENTS.md +++ b/microservices/LocationsApi/DOCUMENTS.md @@ -21,6 +21,13 @@ Inbound JSON documents } ``` `coord` cannot be updated. +- GatherResourceRequest (`POST /api/locations/{id}/gather`) + ```json + { + "characterId": "string (Character ObjectId)", + "resourceKey": "wood" + } + ``` Stored documents (MongoDB) - Location @@ -32,6 +39,26 @@ Stored documents (MongoDB) "x": 0, "y": 0 }, + "resources": [ + { + "itemKey": "wood", + "remainingQuantity": 100, + "gatherQuantity": 3 + } + ], "createdUtc": "string (ISO-8601 datetime)" } ``` + +Outbound JSON documents +- GatherResourceResponse (`POST /api/locations/{id}/gather`) + ```json + { + "locationId": "string (ObjectId)", + "characterId": "string (ObjectId)", + "resourceKey": "wood", + "quantityGranted": 3, + "remainingQuantity": 97, + "inventoryResponseJson": "string (raw InventoryApi response JSON)" + } + ``` diff --git a/microservices/LocationsApi/Models/GatherResourceRequest.cs b/microservices/LocationsApi/Models/GatherResourceRequest.cs new file mode 100644 index 0000000..ec7a07f --- /dev/null +++ b/microservices/LocationsApi/Models/GatherResourceRequest.cs @@ -0,0 +1,8 @@ +namespace LocationsApi.Models; + +public class GatherResourceRequest +{ + public string CharacterId { get; set; } = string.Empty; + + public string ResourceKey { get; set; } = string.Empty; +} diff --git a/microservices/LocationsApi/Models/GatherResourceResponse.cs b/microservices/LocationsApi/Models/GatherResourceResponse.cs new file mode 100644 index 0000000..092d5c2 --- /dev/null +++ b/microservices/LocationsApi/Models/GatherResourceResponse.cs @@ -0,0 +1,16 @@ +namespace LocationsApi.Models; + +public class GatherResourceResponse +{ + public string LocationId { get; set; } = string.Empty; + + public string CharacterId { get; set; } = string.Empty; + + public string ResourceKey { get; set; } = string.Empty; + + public int QuantityGranted { get; set; } + + public int RemainingQuantity { get; set; } + + public string InventoryResponseJson { get; set; } = string.Empty; +} diff --git a/microservices/LocationsApi/Models/Location.cs b/microservices/LocationsApi/Models/Location.cs index 462e763..f477932 100644 --- a/microservices/LocationsApi/Models/Location.cs +++ b/microservices/LocationsApi/Models/Location.cs @@ -15,6 +15,9 @@ public class Location [BsonElement("coord")] public required Coord Coord { get; set; } + [BsonElement("resources")] + public List Resources { get; set; } = []; + [BsonElement("createdUtc")] public DateTime CreatedUtc { get; set; } = DateTime.UtcNow; } diff --git a/microservices/LocationsApi/Models/LocationResource.cs b/microservices/LocationsApi/Models/LocationResource.cs new file mode 100644 index 0000000..8d955ca --- /dev/null +++ b/microservices/LocationsApi/Models/LocationResource.cs @@ -0,0 +1,15 @@ +using MongoDB.Bson.Serialization.Attributes; + +namespace LocationsApi.Models; + +public class LocationResource +{ + [BsonElement("itemKey")] + public string ItemKey { get; set; } = string.Empty; + + [BsonElement("remainingQuantity")] + public int RemainingQuantity { get; set; } + + [BsonElement("gatherQuantity")] + public int GatherQuantity { get; set; } = 1; +} diff --git a/microservices/LocationsApi/Program.cs b/microservices/LocationsApi/Program.cs index c4da181..fdfbe7c 100644 --- a/microservices/LocationsApi/Program.cs +++ b/microservices/LocationsApi/Program.cs @@ -6,6 +6,7 @@ using System.Text; var builder = WebApplication.CreateBuilder(args); builder.Services.AddControllers(); +builder.Services.AddHttpClient(); // DI builder.Services.AddSingleton(); diff --git a/microservices/LocationsApi/Services/LocationStore.cs b/microservices/LocationsApi/Services/LocationStore.cs index 1d589a1..570dbda 100644 --- a/microservices/LocationsApi/Services/LocationStore.cs +++ b/microservices/LocationsApi/Services/LocationStore.cs @@ -8,6 +8,7 @@ public class LocationStore { private readonly IMongoCollection _col; private readonly IMongoCollection _rawCol; + private readonly IMongoCollection _characters; private const string CoordIndexName = "coord_x_1_coord_y_1"; public LocationStore(IConfiguration cfg) @@ -20,6 +21,7 @@ public class LocationStore EnsureLocationSchema(db, collectionName); _col = db.GetCollection(collectionName); _rawCol = db.GetCollection(collectionName); + _characters = db.GetCollection("Characters"); EnsureCoordIndexes(); @@ -34,11 +36,11 @@ public class LocationStore "$jsonSchema", new BsonDocument { { "bsonType", "object" }, - { "required", new BsonArray { "name", "coord", "createdUtc" } }, - { - "properties", new BsonDocument - { - { "name", new BsonDocument { { "bsonType", "string" } } }, + { "required", new BsonArray { "name", "coord", "createdUtc" } }, + { + "properties", new BsonDocument + { + { "name", new BsonDocument { { "bsonType", "string" } } }, { "coord", new BsonDocument { @@ -52,10 +54,31 @@ public class LocationStore } } } - }, - { "createdUtc", new BsonDocument { { "bsonType", "date" } } } - } - } + }, + { + "resources", new BsonDocument + { + { "bsonType", new BsonArray { "array", "null" } }, + { + "items", new BsonDocument + { + { "bsonType", "object" }, + { "required", new BsonArray { "itemKey", "remainingQuantity", "gatherQuantity" } }, + { + "properties", new BsonDocument + { + { "itemKey", new BsonDocument { { "bsonType", "string" } } }, + { "remainingQuantity", new BsonDocument { { "bsonType", "int" }, { "minimum", 0 } } }, + { "gatherQuantity", new BsonDocument { { "bsonType", "int" }, { "minimum", 1 } } } + } + } + } + } + } + }, + { "createdUtc", new BsonDocument { { "bsonType", "date" } } } + } + } } } }; @@ -102,6 +125,57 @@ public class LocationStore return result.ModifiedCount > 0; } + public sealed record GatherResult(GatherStatus Status, string ResourceKey = "", int QuantityGranted = 0, int RemainingQuantity = 0); + + public async Task GatherResourceAsync(string locationId, string characterId, string resourceKey, string userId, bool allowAnyOwner) + { + var normalizedKey = resourceKey.Trim().ToLowerInvariant(); + var location = await _col.Find(l => l.Id == locationId).FirstOrDefaultAsync(); + if (location is null) + return new GatherResult(GatherStatus.LocationNotFound); + + var character = await _characters.Find(c => c.Id == characterId).FirstOrDefaultAsync(); + if (character is null) + return new GatherResult(GatherStatus.CharacterNotFound); + if (!allowAnyOwner && character.OwnerUserId != userId) + return new GatherResult(GatherStatus.Forbidden); + if (character.Coord.X != location.Coord.X || character.Coord.Y != location.Coord.Y) + return new GatherResult(GatherStatus.Invalid); + + var resource = location.Resources.FirstOrDefault(r => NormalizeItemKey(r.ItemKey) == normalizedKey); + if (resource is null) + return new GatherResult(GatherStatus.ResourceNotFound); + if (resource.RemainingQuantity <= 0) + return new GatherResult(GatherStatus.ResourceDepleted); + + var quantityGranted = Math.Min(resource.GatherQuantity, resource.RemainingQuantity); + var filter = Builders.Filter.And( + Builders.Filter.Eq(l => l.Id, locationId), + Builders.Filter.ElemMatch(l => l.Resources, r => r.ItemKey == resource.ItemKey && r.RemainingQuantity >= quantityGranted) + ); + var update = Builders.Update.Inc("resources.$.remainingQuantity", -quantityGranted); + var result = await _col.UpdateOneAsync(filter, update); + if (result.ModifiedCount == 0) + return new GatherResult(GatherStatus.ResourceDepleted); + + return new GatherResult( + GatherStatus.Ok, + resource.ItemKey, + quantityGranted, + resource.RemainingQuantity - quantityGranted); + } + + public async Task RestoreGatheredResourceAsync(string locationId, string resourceKey, int quantity) + { + var normalizedKey = NormalizeItemKey(resourceKey); + var filter = Builders.Filter.And( + Builders.Filter.Eq(l => l.Id, locationId), + Builders.Filter.ElemMatch(l => l.Resources, r => r.ItemKey == normalizedKey) + ); + var update = Builders.Update.Inc("resources.$.remainingQuantity", quantity); + await _col.UpdateOneAsync(filter, update); + } + private void EnsureCoordIndexes() { var indexes = _rawCol.Indexes.List().ToList(); @@ -149,12 +223,17 @@ public class LocationStore if (existing is not null) return; - var origin = new Location - { - Name = "Origin", - Coord = new Coord { X = 0, Y = 0 }, - CreatedUtc = DateTime.UtcNow - }; + var origin = new Location + { + Name = "Origin", + Coord = new Coord { X = 0, Y = 0 }, + Resources = + [ + new LocationResource { ItemKey = "wood", RemainingQuantity = 100, GatherQuantity = 3 }, + new LocationResource { ItemKey = "grass", RemainingQuantity = 500, GatherQuantity = 10 } + ], + CreatedUtc = DateTime.UtcNow + }; try { @@ -164,5 +243,30 @@ public class LocationStore { // Another instance seeded it first. } - } -} + } + + private static string NormalizeItemKey(string itemKey) => itemKey.Trim().ToLowerInvariant(); + + [MongoDB.Bson.Serialization.Attributes.BsonIgnoreExtraElements] + private class CharacterDocument + { + [MongoDB.Bson.Serialization.Attributes.BsonId] + [MongoDB.Bson.Serialization.Attributes.BsonRepresentation(MongoDB.Bson.BsonType.ObjectId)] + public string? Id { get; set; } + + public string OwnerUserId { get; set; } = string.Empty; + + public Coord Coord { get; set; } = new(); + } +} + +public enum GatherStatus +{ + Ok, + LocationNotFound, + CharacterNotFound, + Forbidden, + Invalid, + ResourceNotFound, + ResourceDepleted +} diff --git a/microservices/LocationsApi/appsettings.Development.json b/microservices/LocationsApi/appsettings.Development.json index 07f3f94..c478bd3 100644 --- a/microservices/LocationsApi/appsettings.Development.json +++ b/microservices/LocationsApi/appsettings.Development.json @@ -1,6 +1,11 @@ { - "Kestrel": { "Endpoints": { "Http": { "Url": "http://0.0.0.0:5002" } } }, - "MongoDB": { "ConnectionString": "mongodb://192.168.86.50:27017", "DatabaseName": "promiscuity" }, - "Jwt": { "Key": "SuperUltraSecureJwtKeyWithAtLeast32Chars!!", "Issuer": "promiscuity", "Audience": "promiscuity-auth-api" }, - "Logging": { "LogLevel": { "Default": "Information" } } + "Services": { + "InventoryApiBaseUrl": "http://localhost:5003" + }, + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + } } diff --git a/microservices/LocationsApi/appsettings.json b/microservices/LocationsApi/appsettings.json index d67c59f..45d1ba6 100644 --- a/microservices/LocationsApi/appsettings.json +++ b/microservices/LocationsApi/appsettings.json @@ -1,6 +1,7 @@ { "Kestrel": { "Endpoints": { "Http": { "Url": "http://0.0.0.0:5002" } } }, "MongoDB": { "ConnectionString": "mongodb://192.168.86.50:27017", "DatabaseName": "promiscuity" }, + "Services": { "InventoryApiBaseUrl": "https://pinv.ranaze.com" }, "Jwt": { "Key": "SuperUltraSecureJwtKeyWithAtLeast32Chars!!", "Issuer": "promiscuity", "Audience": "promiscuity-auth-api" }, "Logging": { "LogLevel": { "Default": "Information" } }, "AllowedHosts": "*"