diff --git a/Components/HTTPTextureRect.gd b/Components/HTTPTextureRect.gd
new file mode 100644
index 0000000..be9cc7e
--- /dev/null
+++ b/Components/HTTPTextureRect.gd
@@ -0,0 +1,106 @@
+extends TextureRect
+class_name HTTPTextureRect
+
+signal loading_started
+signal loading_finished(success: bool)
+
+# HTTP请求节点
+var http_request: HTTPRequest
+
+func _ready():
+ # 创建HTTP请求节点
+ http_request = HTTPRequest.new()
+ add_child(http_request)
+
+ # 连接信号
+ http_request.request_completed.connect(_on_request_completed)
+
+# 从URL加载图像
+func load_from_url(url: String, custom_headers: Array = []) -> void:
+ if url.is_empty():
+ push_error("HTTPTextureRect: URL不能为空")
+ loading_finished.emit(false)
+ return
+
+ loading_started.emit()
+
+ # 发起HTTP请求
+ var error = http_request.request(url, custom_headers)
+ if error != OK:
+ push_error("HTTPTextureRect: 发起HTTP请求失败,错误码: " + str(error))
+ loading_finished.emit(false)
+
+# HTTP请求完成的回调函数
+func _on_request_completed(result, response_code, headers, body):
+ if result != HTTPRequest.RESULT_SUCCESS:
+ push_error("HTTPTextureRect: HTTP请求失败,错误码: " + str(result))
+ loading_finished.emit(false)
+ return
+
+ if response_code != 200:
+ push_error("HTTPTextureRect: HTTP请求返回非200状态码: " + str(response_code))
+ loading_finished.emit(false)
+ return
+
+ # 检查内容类型
+ var content_type = ""
+ for header in headers:
+ if header.to_lower().begins_with("content-type:"):
+ content_type = header.substr(13).strip_edges().to_lower()
+ print("HTTPTextureRect: 内容类型: ", content_type)
+ break
+
+ # 创建图像
+ var image = Image.new()
+ var error = ERR_INVALID_DATA
+
+ # 根据内容类型选择加载方法
+ if content_type.begins_with("image/jpeg") or content_type.begins_with("image/jpg"):
+ error = image.load_jpg_from_buffer(body)
+ elif content_type.begins_with("image/png"):
+ error = image.load_png_from_buffer(body)
+ elif content_type.begins_with("image/webp"):
+ error = image.load_webp_from_buffer(body)
+ elif content_type.begins_with("image/bmp"):
+ error = image.load_bmp_from_buffer(body)
+ else:
+ # 未知内容类型,尝试常见格式
+ error = image.load_jpg_from_buffer(body)
+ if error != OK:
+ error = image.load_png_from_buffer(body)
+ if error != OK:
+ error = image.load_webp_from_buffer(body)
+ if error != OK:
+ error = image.load_bmp_from_buffer(body)
+
+ # 检查加载结果
+ if error != OK:
+ push_error("HTTPTextureRect: 无法加载图像,错误码: " + str(error))
+ loading_finished.emit(false)
+ return
+
+ # 创建纹理并应用
+ var texture = ImageTexture.create_from_image(image)
+ self.texture = texture
+ print("HTTPTextureRect: 图像加载成功,尺寸: ", image.get_width(), "x", image.get_height())
+ loading_finished.emit(true)
+
+# 加载QQ头像的便捷方法
+func load_qq_avatar(qq_number: String) -> void:
+ if not qq_number.is_valid_int():
+ push_error("HTTPTextureRect: QQ号必须为纯数字")
+ loading_finished.emit(false)
+ return
+
+ # 使用QQ头像API
+ #var url = "https://q.qlogo.cn/headimg_dl?dst_uin=" + qq_number + "&spec=640&img_type=png"
+ var url = "http://q1.qlogo.cn/g?b=qq&nk="+qq_number+"&s=100"
+
+ # 添加浏览器模拟头
+ var headers = [
+ "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36",
+ "Accept: image/png,image/jpeg,image/webp,image/*,*/*;q=0.8"
+ ]
+
+ # 加载图像
+ load_from_url(url, headers)
diff --git a/Components/HTTPTextureRect.gd.uid b/Components/HTTPTextureRect.gd.uid
new file mode 100644
index 0000000..95e326a
--- /dev/null
+++ b/Components/HTTPTextureRect.gd.uid
@@ -0,0 +1 @@
+uid://0d2j5m6j2ema
diff --git a/Components/ToastShow.gd.uid b/Components/ToastShow.gd.uid
new file mode 100644
index 0000000..a429a11
--- /dev/null
+++ b/Components/ToastShow.gd.uid
@@ -0,0 +1 @@
+uid://caly13tf4ni1d
diff --git a/CopyItems/black_blue_crop.tscn b/CopyItems/black_blue_crop.tscn
new file mode 100644
index 0000000..3e8c7c1
--- /dev/null
+++ b/CopyItems/black_blue_crop.tscn
@@ -0,0 +1,27 @@
+[gd_scene load_steps=3 format=3 uid="uid://cm1e72lhd7j7v"]
+
+[ext_resource type="Script" uid="uid://c6ylh1o2kgqth" path="res://CopyItems/item_crop.gd" id="1_sgirt"]
+[ext_resource type="Texture2D" uid="uid://kdhowrc6av4g" path="res://assets/作物/默认/0.png" id="2_sgirt"]
+
+[node name="BlackBlueCrop" type="Button"]
+custom_minimum_size = Vector2(400, 400)
+offset_right = 400.0
+offset_bottom = 400.0
+scale = Vector2(0.3, 0.3)
+theme_override_font_sizes/font_size = 1
+icon_alignment = 1
+script = ExtResource("1_sgirt")
+
+[node name="CropImage" type="Sprite2D" parent="."]
+position = Vector2(199.569, 201.043)
+scale = Vector2(0.260977, 0.259058)
+texture = ExtResource("2_sgirt")
+
+[node name="Title" type="Label" parent="."]
+modulate = Color(0, 0.152941, 0.984314, 1)
+layout_mode = 0
+offset_right = 400.0
+offset_bottom = 55.0
+theme_override_font_sizes/font_size = 50
+text = "普通"
+horizontal_alignment = 1
diff --git a/CopyItems/crop_item.tscn b/CopyItems/crop_item.tscn
new file mode 100644
index 0000000..6736eb7
--- /dev/null
+++ b/CopyItems/crop_item.tscn
@@ -0,0 +1,42 @@
+[gd_scene load_steps=4 format=3 uid="uid://bkivlkirrx6u8"]
+
+[ext_resource type="Texture2D" uid="uid://c4l0qn0p4yav8" path="res://assets/tu3.png" id="1_bns1c"]
+[ext_resource type="Script" uid="uid://xh5tr5co5kfu" path="res://GUI/SMY_ProgressBar.gd" id="2_1n4xp"]
+[ext_resource type="Texture2D" uid="uid://kdhowrc6av4g" path="res://assets/作物/默认/0.png" id="2_bns1c"]
+
+[node name="CropItem" type="Button"]
+self_modulate = Color(1, 1, 1, 0.435294)
+custom_minimum_size = Vector2(100, 100)
+offset_right = 40.0
+offset_bottom = 40.0
+
+[node name="ground_sprite" type="Sprite2D" parent="."]
+position = Vector2(50, 63)
+scale = Vector2(0.130329, 0.130329)
+texture = ExtResource("1_bns1c")
+
+[node name="crop_sprite" type="Sprite2D" parent="."]
+visible = false
+position = Vector2(50, 36)
+scale = Vector2(0.0660772, 0.0660772)
+texture = ExtResource("2_bns1c")
+
+[node name="ProgressBar" type="ProgressBar" parent="."]
+layout_mode = 2
+offset_top = 86.0
+offset_right = 495.0
+offset_bottom = 159.0
+scale = Vector2(0.2, 0.2)
+theme_override_font_sizes/font_size = 50
+script = ExtResource("2_1n4xp")
+
+[node name="Label" type="Label" parent="."]
+layout_mode = 2
+offset_right = 250.0
+offset_bottom = 42.0
+scale = Vector2(0.4, 0.4)
+size_flags_horizontal = 3
+theme_override_font_sizes/font_size = 30
+text = "[普通-胡萝卜]"
+horizontal_alignment = 1
+vertical_alignment = 1
diff --git a/CopyItems/green_crop.tscn b/CopyItems/green_crop.tscn
new file mode 100644
index 0000000..27ddc2a
--- /dev/null
+++ b/CopyItems/green_crop.tscn
@@ -0,0 +1,25 @@
+[gd_scene load_steps=2 format=3 uid="uid://2m54c0f1ejir"]
+
+[ext_resource type="Script" uid="uid://c6ylh1o2kgqth" path="res://CopyItems/item_crop.gd" id="1_ihcyw"]
+
+[node name="GreenCrop" type="Button"]
+custom_minimum_size = Vector2(400, 400)
+offset_right = 400.0
+offset_bottom = 400.0
+scale = Vector2(0.3, 0.3)
+theme_override_font_sizes/font_size = 1
+icon_alignment = 1
+script = ExtResource("1_ihcyw")
+
+[node name="CropImage" type="Sprite2D" parent="."]
+position = Vector2(199.569, 201.043)
+scale = Vector2(0.260977, 0.259058)
+
+[node name="Title" type="Label" parent="."]
+modulate = Color(0.243137, 0.729412, 0, 1)
+layout_mode = 0
+offset_right = 400.0
+offset_bottom = 55.0
+theme_override_font_sizes/font_size = 50
+text = "普通"
+horizontal_alignment = 1
diff --git a/CopyItems/item_crop.gd b/CopyItems/item_crop.gd
new file mode 100644
index 0000000..58f4e54
--- /dev/null
+++ b/CopyItems/item_crop.gd
@@ -0,0 +1,9 @@
+extends Button
+
+@onready var title :Label = $Title
+@onready var crop_image: Sprite2D = $CropImage
+
+
+func _ready() -> void:
+ title.text = self.text
+ pass
diff --git a/CopyItems/item_crop.gd.uid b/CopyItems/item_crop.gd.uid
new file mode 100644
index 0000000..8337b0e
--- /dev/null
+++ b/CopyItems/item_crop.gd.uid
@@ -0,0 +1 @@
+uid://c6ylh1o2kgqth
diff --git a/CopyItems/orange_crop.tscn b/CopyItems/orange_crop.tscn
new file mode 100644
index 0000000..a8c18eb
--- /dev/null
+++ b/CopyItems/orange_crop.tscn
@@ -0,0 +1,25 @@
+[gd_scene load_steps=2 format=3 uid="uid://forqk66f354p"]
+
+[ext_resource type="Script" uid="uid://c6ylh1o2kgqth" path="res://CopyItems/item_crop.gd" id="1_00rx4"]
+
+[node name="OrangeCrop" type="Button"]
+custom_minimum_size = Vector2(400, 400)
+offset_right = 400.0
+offset_bottom = 400.0
+scale = Vector2(0.3, 0.3)
+theme_override_font_sizes/font_size = 1
+icon_alignment = 1
+script = ExtResource("1_00rx4")
+
+[node name="CropImage" type="Sprite2D" parent="."]
+position = Vector2(200, 200)
+scale = Vector2(0.308178, 0.308356)
+
+[node name="Title" type="Label" parent="."]
+modulate = Color(0.822776, 0.578065, 0, 1)
+layout_mode = 0
+offset_right = 400.0
+offset_bottom = 55.0
+theme_override_font_sizes/font_size = 50
+text = "普通"
+horizontal_alignment = 1
diff --git a/CopyItems/pink_crop.tscn b/CopyItems/pink_crop.tscn
new file mode 100644
index 0000000..baf3051
--- /dev/null
+++ b/CopyItems/pink_crop.tscn
@@ -0,0 +1,25 @@
+[gd_scene load_steps=2 format=3 uid="uid://cmdoymcviv0ai"]
+
+[ext_resource type="Script" uid="uid://c6ylh1o2kgqth" path="res://CopyItems/item_crop.gd" id="1_3xhou"]
+
+[node name="PinkCrop" type="Button"]
+custom_minimum_size = Vector2(400, 400)
+offset_right = 400.0
+offset_bottom = 400.0
+scale = Vector2(0.3, 0.3)
+theme_override_font_sizes/font_size = 1
+icon_alignment = 1
+script = ExtResource("1_3xhou")
+
+[node name="CropImage" type="Sprite2D" parent="."]
+position = Vector2(199.569, 201.043)
+scale = Vector2(0.260977, 0.259058)
+
+[node name="Title" type="Label" parent="."]
+modulate = Color(0.980392, 0, 0.552941, 1)
+layout_mode = 0
+offset_right = 400.0
+offset_bottom = 55.0
+theme_override_font_sizes/font_size = 50
+text = "普通"
+horizontal_alignment = 1
diff --git a/CopyItems/red_crop.tscn b/CopyItems/red_crop.tscn
new file mode 100644
index 0000000..2b8dcdd
--- /dev/null
+++ b/CopyItems/red_crop.tscn
@@ -0,0 +1,25 @@
+[gd_scene load_steps=2 format=3 uid="uid://d3ve4qeggsdqy"]
+
+[ext_resource type="Script" uid="uid://c6ylh1o2kgqth" path="res://CopyItems/item_crop.gd" id="1_1yrv4"]
+
+[node name="RedCrop" type="Button"]
+custom_minimum_size = Vector2(400, 400)
+offset_right = 400.0
+offset_bottom = 400.0
+scale = Vector2(0.3, 0.3)
+theme_override_font_sizes/font_size = 1
+icon_alignment = 1
+script = ExtResource("1_1yrv4")
+
+[node name="CropImage" type="Sprite2D" parent="."]
+position = Vector2(199.569, 201.043)
+scale = Vector2(0.260977, 0.259058)
+
+[node name="Title" type="Label" parent="."]
+modulate = Color(1, 0.0509804, 0.0352941, 1)
+layout_mode = 0
+offset_right = 400.0
+offset_bottom = 55.0
+theme_override_font_sizes/font_size = 50
+text = "普通"
+horizontal_alignment = 1
diff --git a/CopyItems/white_blue_crop.tscn b/CopyItems/white_blue_crop.tscn
new file mode 100644
index 0000000..c81c5b0
--- /dev/null
+++ b/CopyItems/white_blue_crop.tscn
@@ -0,0 +1,25 @@
+[gd_scene load_steps=2 format=3 uid="uid://dagh3u5med30i"]
+
+[ext_resource type="Script" uid="uid://c6ylh1o2kgqth" path="res://CopyItems/item_crop.gd" id="1_nfqts"]
+
+[node name="WhiteBlueCrop" type="Button"]
+custom_minimum_size = Vector2(400, 400)
+offset_right = 400.0
+offset_bottom = 400.0
+scale = Vector2(0.3, 0.3)
+theme_override_font_sizes/font_size = 1
+icon_alignment = 1
+script = ExtResource("1_nfqts")
+
+[node name="CropImage" type="Sprite2D" parent="."]
+position = Vector2(199.569, 201.043)
+scale = Vector2(0.260977, 0.259058)
+
+[node name="Title" type="Label" parent="."]
+modulate = Color(0.111013, 0.795686, 0.959948, 1)
+layout_mode = 0
+offset_right = 400.0
+offset_bottom = 55.0
+theme_override_font_sizes/font_size = 50
+text = "普通"
+horizontal_alignment = 1
diff --git a/Data/crop_data.json b/Data/crop_data.json
new file mode 100644
index 0000000..2db9dfa
--- /dev/null
+++ b/Data/crop_data.json
@@ -0,0 +1,31 @@
+{
+ "测试作物": {"花费": 1, "生长时间": 3, "收益": 9999, "品质": "普通", "描述": "测试作物", "耐候性": 10, "等级": 1, "经验": 999},
+
+ "小麦": {"花费": 120, "生长时间": 120, "收益": 100, "品质": "普通", "描述": "基础作物,品质较低,适合新手种植", "耐候性": 10, "等级": 1, "经验": 10},
+ "稻谷": {"花费": 100, "生长时间": 240, "收益": 120, "品质": "普通", "描述": "适合大规模种植的基础作物", "耐候性": 10, "等级": 1, "经验": 10},
+ "玉米": {"花费": 70, "生长时间": 600, "收益": 90, "品质": "普通", "描述": "营养丰富的优良作物,适合稍有经验的玩家", "耐候性": 15, "等级": 2, "经验": 15},
+ "土豆": {"花费": 75, "生长时间": 360, "收益": 90, "品质": "普通", "描述": "容易种植的耐寒作物", "耐候性": 12, "等级": 1, "经验": 10},
+ "胡萝卜": {"花费": 60, "生长时间": 480, "收益": 80, "品质": "普通", "描述": "适合新手的健康作物", "耐候性": 12, "等级": 1, "经验": 10},
+
+ "草莓": {"花费": 120, "生长时间": 960, "收益": 150, "品质": "优良", "描述": "营养丰富的果实,收益不错", "耐候性": 14, "等级": 2, "经验": 20},
+ "番茄": {"花费": 100, "生长时间": 720, "收益": 130, "品质": "优良", "描述": "常见作物,适合小规模种植", "耐候性": 12, "等级": 2, "经验": 15},
+ "大豆": {"花费": 90, "生长时间": 840, "收益": 110, "品质": "优良", "描述": "富含蛋白质的基础作物", "耐候性": 11, "等级": 2, "经验": 12},
+
+ "蓝莓": {"花费": 150, "生长时间": 1200, "收益": 200, "品质": "稀有", "描述": "较为稀有的作物,市场价值较高", "耐候性": 18, "等级": 3, "经验": 25},
+ "洋葱": {"花费": 85, "生长时间": 600, "收益": 105, "品质": "稀有", "描述": "烹饪常用的作物,适合中级种植", "耐候性": 10, "等级": 2, "经验": 10},
+ "南瓜": {"花费": 180, "生长时间": 1440, "收益": 250, "品质": "稀有", "描述": "秋季收获的高收益作物", "耐候性": 20, "等级": 4, "经验": 30},
+ "葡萄": {"花费": 200, "生长时间": 1200, "收益": 300, "品质": "稀有", "描述": "需要特殊管理的高收益作物", "耐候性": 15, "等级": 4, "经验": 35},
+ "柿子": {"花费": 160, "生长时间": 1080, "收益": 240, "品质": "稀有", "描述": "富含营养的秋季作物", "耐候性": 18, "等级": 3, "经验": 28},
+ "花椰菜": {"花费": 130, "生长时间": 960, "收益": 170, "品质": "稀有", "描述": "耐寒的高品质作物,适合经验丰富的玩家", "耐候性": 17, "等级": 3, "经验": 22},
+ "芦笋": {"花费": 200, "生长时间": 1560, "收益": 280, "品质": "稀有", "描述": "市场需求量高的稀有作物", "耐候性": 15, "等级": 4, "经验": 30},
+
+ "香草": {"花费": 250, "生长时间": 1800, "收益": 400, "品质": "史诗", "描述": "非常稀有且收益极高的作物", "耐候性": 22, "等级": 5, "经验": 40},
+ "西瓜": {"花费": 240, "生长时间": 2400, "收益": 420, "品质": "史诗", "描述": "夏季丰产的高价值作物", "耐候性": 21, "等级": 5, "经验": 45},
+ "甜菜": {"花费": 220, "生长时间": 2160, "收益": 350, "品质": "史诗", "描述": "营养丰富的根茎作物,收益较高", "耐候性": 20, "等级": 5, "经验": 38},
+ "甘蔗": {"花费": 260, "生长时间": 3000, "收益": 450, "品质": "史诗", "描述": "需要充足水源的高价值作物", "耐候性": 18, "等级": 5, "经验": 50},
+
+ "龙果": {"花费": 400, "生长时间": 4800, "收益": 600, "品质": "传奇", "描述": "极为稀有的热带作物,产量和价值都极高", "耐候性": 25, "等级": 6, "经验": 60},
+ "松露": {"花费": 500, "生长时间": 7200, "收益": 700, "品质": "传奇", "描述": "极其珍贵的地下作物,市场价格极高", "耐候性": 23, "等级": 7, "经验": 80},
+ "人参": {"花费": 450, "生长时间": 6600, "收益": 650, "品质": "传奇", "描述": "需要耐心等待的珍贵药材", "耐候性": 22, "等级": 6, "经验": 75},
+ "金橘": {"花费": 420, "生长时间": 4800, "收益": 620, "品质": "传奇", "描述": "少见的耐寒果树,市场需求量极大", "耐候性": 26, "等级": 7, "经验": 70}
+}
\ No newline at end of file
diff --git a/Data/initial_player_data_template.json b/Data/initial_player_data_template.json
new file mode 100644
index 0000000..d8f1286
--- /dev/null
+++ b/Data/initial_player_data_template.json
@@ -0,0 +1,48 @@
+{
+ "experience": 0,
+ "farm_lots": [
+ {"crop_type": "", "grow_time": 0, "is_dead": false, "is_diged": true, "is_planted": false, "max_grow_time": 3},
+ {"crop_type": "", "grow_time": 0, "is_dead": false, "is_diged": true, "is_planted": false, "max_grow_time": 3},
+ {"crop_type": "", "grow_time": 0, "is_dead": false, "is_diged": true, "is_planted": false, "max_grow_time": 3},
+ {"crop_type": "", "grow_time": 0, "is_dead": false, "is_diged": true, "is_planted": false, "max_grow_time": 3},
+ {"crop_type": "", "grow_time": 0, "is_dead": false, "is_diged": true, "is_planted": false, "max_grow_time": 3},
+ {"crop_type": "", "grow_time": 0, "is_dead": false, "is_diged": false, "is_planted": false, "max_grow_time": 5},
+ {"crop_type": "", "grow_time": 0, "is_dead": false, "is_diged": false, "is_planted": false, "max_grow_time": 5},
+ {"crop_type": "", "grow_time": 0, "is_dead": false, "is_diged": false, "is_planted": false, "max_grow_time": 5},
+ {"crop_type": "", "grow_time": 0, "is_dead": false, "is_diged": false, "is_planted": false, "max_grow_time": 5},
+ {"crop_type": "", "grow_time": 0, "is_dead": false, "is_diged": false, "is_planted": false, "max_grow_time": 5},
+ {"crop_type": "", "grow_time": 0, "is_dead": false, "is_diged": false, "is_planted": false, "max_grow_time": 5},
+ {"crop_type": "", "grow_time": 0, "is_dead": false, "is_diged": false, "is_planted": false, "max_grow_time": 5},
+ {"crop_type": "", "grow_time": 0, "is_dead": false, "is_diged": false, "is_planted": false, "max_grow_time": 5},
+ {"crop_type": "", "grow_time": 0, "is_dead": false, "is_diged": false, "is_planted": false, "max_grow_time": 5},
+ {"crop_type": "", "grow_time": 0, "is_dead": false, "is_diged": false, "is_planted": false, "max_grow_time": 5},
+ {"crop_type": "", "grow_time": 0, "is_dead": false, "is_diged": false, "is_planted": false, "max_grow_time": 5},
+ {"crop_type": "", "grow_time": 0, "is_dead": false, "is_diged": false, "is_planted": false, "max_grow_time": 5},
+ {"crop_type": "", "grow_time": 0, "is_dead": false, "is_diged": false, "is_planted": false, "max_grow_time": 5},
+ {"crop_type": "", "grow_time": 0, "is_dead": false, "is_diged": false, "is_planted": false, "max_grow_time": 5},
+ {"crop_type": "", "grow_time": 0, "is_dead": false, "is_diged": false, "is_planted": false, "max_grow_time": 5},
+ {"crop_type": "", "grow_time": 0, "is_dead": false, "is_diged": false, "is_planted": false, "max_grow_time": 5},
+ {"crop_type": "", "grow_time": 0, "is_dead": false, "is_diged": false, "is_planted": false, "max_grow_time": 5},
+ {"crop_type": "", "grow_time": 0, "is_dead": false, "is_diged": false, "is_planted": false, "max_grow_time": 5},
+ {"crop_type": "", "grow_time": 0, "is_dead": false, "is_diged": false, "is_planted": false, "max_grow_time": 5},
+ {"crop_type": "", "grow_time": 0, "is_dead": false, "is_diged": false, "is_planted": false, "max_grow_time": 5},
+ {"crop_type": "", "grow_time": 0, "is_dead": false, "is_diged": false, "is_planted": false, "max_grow_time": 5},
+ {"crop_type": "", "grow_time": 0, "is_dead": false, "is_diged": false, "is_planted": false, "max_grow_time": 5},
+ {"crop_type": "", "grow_time": 0, "is_dead": false, "is_diged": false, "is_planted": false, "max_grow_time": 5},
+ {"crop_type": "", "grow_time": 0, "is_dead": false, "is_diged": false, "is_planted": false, "max_grow_time": 5},
+ {"crop_type": "", "grow_time": 0, "is_dead": false, "is_diged": false, "is_planted": false, "max_grow_time": 5},
+ {"crop_type": "", "grow_time": 0, "is_dead": false, "is_diged": false, "is_planted": false, "max_grow_time": 5},
+ {"crop_type": "", "grow_time": 0, "is_dead": false, "is_diged": false, "is_planted": false, "max_grow_time": 5},
+ {"crop_type": "", "grow_time": 0, "is_dead": false, "is_diged": false, "is_planted": false, "max_grow_time": 5},
+ {"crop_type": "", "grow_time": 0, "is_dead": false, "is_diged": false, "is_planted": false, "max_grow_time": 5},
+ {"crop_type": "", "grow_time": 0, "is_dead": false, "is_diged": false, "is_planted": false, "max_grow_time": 5},
+ {"crop_type": "", "grow_time": 0, "is_dead": false, "is_diged": true, "is_planted": false, "max_grow_time": 5},
+ {"crop_type": "", "grow_time": 0, "is_dead": false, "is_diged": true, "is_planted": false, "max_grow_time": 5},
+ {"crop_type": "", "grow_time": 0, "is_dead": false, "is_diged": true, "is_planted": false, "max_grow_time": 5},
+ {"crop_type": "", "grow_time": 0, "is_dead": false, "is_diged": true, "is_planted": false, "max_grow_time": 5}
+ ],
+ "level": 1,
+ "money": 1000,
+ "user_name": "shumengya",
+ "user_password": "0123456789"
+}
\ No newline at end of file
diff --git a/GUI/LoginPanel.gd b/GUI/LoginPanel.gd
deleted file mode 100644
index 8ebde81..0000000
--- a/GUI/LoginPanel.gd
+++ /dev/null
@@ -1,19 +0,0 @@
-extends Panel
-
-#用户登录账号,用QQ号代替
-@onready var username_input = $username_input
-#用户登录密码
-@onready var password_input = $password_input
-#登录按钮
-@onready var login_button = $login_button
-
-
-func _ready():
-
- pass
-
-func _process(delta):
- pass
-
-func _on_login_button_pressed():
- pass
diff --git a/SMY_ProgressBar.gd b/GUI/SMY_ProgressBar.gd
similarity index 100%
rename from SMY_ProgressBar.gd
rename to GUI/SMY_ProgressBar.gd
diff --git a/GUI/SMY_ProgressBar.gd.uid b/GUI/SMY_ProgressBar.gd.uid
new file mode 100644
index 0000000..7c91315
--- /dev/null
+++ b/GUI/SMY_ProgressBar.gd.uid
@@ -0,0 +1 @@
+uid://xh5tr5co5kfu
diff --git a/GUI/crop_store_panel.gd b/GUI/crop_store_panel.gd
new file mode 100644
index 0000000..c4184f5
--- /dev/null
+++ b/GUI/crop_store_panel.gd
@@ -0,0 +1,494 @@
+extends Panel
+
+#种子商店面板
+#种子商店格子
+@onready var crop_grid_container : GridContainer = $ScrollContainer/Crop_Grid
+@onready var quit_button : Button = $QuitButton
+
+#各种排序过滤按钮
+@onready var sort_all_button : Button = $SortContainer/Sort_All#全部
+@onready var sort_common_button : Button = $SortContainer/Sort_Common#普通
+@onready var sort_superior_button : Button = $SortContainer/Sort_Superior#优良
+@onready var sort_rare_button : Button = $SortContainer/Sort_Rare#稀有
+@onready var sort_epic_button : Button = $SortContainer/Sort_Epic#史诗
+@onready var sort_legendary_button : Button = $SortContainer/Sort_Legendary#传奇
+@onready var sort_price_button : Button = $SortContainer/Sort_Price#价格
+@onready var sort_growtime_button : Button = $SortContainer/Sort_GrowTime#生长时间
+@onready var sort_profit_button : Button = $SortContainer/Sort_Profit#收益
+@onready var sort_level_button : Button = $SortContainer/Sort_Level#等级
+
+#预添加常用的面板
+@onready var main_game = get_node("/root/main")
+@onready var land_panel = get_node("/root/main/UI/LandPanel")
+@onready var crop_store_panel = get_node("/root/main/UI/PlayerBagPanel")
+@onready var player_ranking_panel = get_node("/root/main/UI/PlayerRankingPanel")
+@onready var player_bag_panel = get_node("/root/main/UI/PlayerBagPanel")
+@onready var network_manager = get_node("/root/main/UI/TCPNetworkManager")
+
+# 作物图片缓存(复用主游戏的缓存系统)
+var crop_textures_cache : Dictionary = {}
+var crop_frame_counts : Dictionary = {}
+
+# 当前过滤和排序设置
+var current_filter_quality = ""
+var current_sort_key = ""
+var current_sort_ascending = true
+
+# 准备函数
+func _ready():
+ # 连接按钮信号
+ _connect_buttons()
+ # 隐藏面板(初始默认隐藏)
+ self.hide()
+
+# 连接所有按钮信号
+func _connect_buttons():
+ # 关闭按钮
+ quit_button.pressed.connect(self._on_quit_button_pressed)
+
+ # 过滤按钮
+ sort_all_button.pressed.connect(func(): _filter_by_quality(""))
+ sort_common_button.pressed.connect(func(): _filter_by_quality("普通"))
+ sort_superior_button.pressed.connect(func(): _filter_by_quality("优良"))
+ sort_rare_button.pressed.connect(func(): _filter_by_quality("稀有"))
+ sort_epic_button.pressed.connect(func(): _filter_by_quality("史诗"))
+ sort_legendary_button.pressed.connect(func(): _filter_by_quality("传奇"))
+
+ # 排序按钮
+ sort_price_button.pressed.connect(func(): _sort_by("花费"))
+ sort_growtime_button.pressed.connect(func(): _sort_by("生长时间"))
+ sort_profit_button.pressed.connect(func(): _sort_by("收益"))
+ sort_level_button.pressed.connect(func(): _sort_by("等级"))
+
+# 初始化商店
+func init_store():
+ print("初始化商店...")
+
+ # 清空已有的作物按钮
+ for child in crop_grid_container.get_children():
+ child.queue_free()
+
+ # 遍历可种植的作物数据并添加到商店
+ print("初始化商店,显示所有作物...")
+ for crop_name in main_game.can_planted_crop:
+ var crop = main_game.can_planted_crop[crop_name]
+
+ # 只显示当前等级可以种植的作物
+ if crop["等级"] <= main_game.level:
+ var store_btn = _create_store_button(crop_name, crop["品质"])
+ crop_grid_container.add_child(store_btn)
+ #print("添加商店按钮: " + crop_name)
+
+ print("商店初始化完成,共添加按钮: " + str(crop_grid_container.get_child_count()) + "个")
+
+ # 更新金钱显示
+ _update_money_display()
+
+# 创建商店按钮
+func _create_store_button(crop_name: String, crop_quality: String) -> Button:
+ # 根据品质选择相应的按钮
+ var button = null
+ match crop_quality:
+ "普通":
+ button = main_game.green_bar.duplicate()
+ "优良":
+ button = main_game.orange_bar.duplicate()
+ "稀有":
+ button = main_game.white_blue_bar.duplicate()
+ "史诗":
+ button = main_game.pink_bar.duplicate()
+ "传奇":
+ button = main_game.black_blue_bar.duplicate()
+ _: # 默认情况
+ button = main_game.green_bar.duplicate()
+
+ var crop = main_game.can_planted_crop[crop_name]
+
+ # 确保按钮可见并可点击
+ button.visible = true
+ button.disabled = false
+ button.focus_mode = Control.FOCUS_ALL
+
+ # 设置按钮文本,显示价格
+ button.text = str(crop_quality + "-" + crop_name + "\n价格: ¥" + str(crop["花费"]))
+
+ # 将成熟时间从秒转换为天时分秒格式
+ var total_seconds = int(crop["生长时间"])
+
+ # 定义时间单位换算
+ var SECONDS_PER_MINUTE = 60
+ var SECONDS_PER_HOUR = 3600
+ var SECONDS_PER_DAY = 86400
+
+ # 计算各时间单位
+ var days = total_seconds / SECONDS_PER_DAY
+ total_seconds %= SECONDS_PER_DAY
+
+ var hours = total_seconds / SECONDS_PER_HOUR
+ total_seconds %= SECONDS_PER_HOUR
+
+ var minutes = total_seconds / SECONDS_PER_MINUTE
+ var seconds = total_seconds % SECONDS_PER_MINUTE
+
+ # 构建时间字符串(只显示有值的单位)
+ var time_str = ""
+ if days > 0:
+ time_str += str(days) + "天"
+ if hours > 0:
+ time_str += str(hours) + "小时"
+ if minutes > 0:
+ time_str += str(minutes) + "分钟"
+ if seconds > 0:
+ time_str += str(seconds) + "秒"
+
+ button.tooltip_text = str(
+ "作物: " + crop_name + "\n" +
+ "品质: " + crop_quality + "\n" +
+ "价格: " + str(crop["花费"]) + "元\n" +
+ "成熟时间: " + time_str + "\n" +
+ "收获收益: " + str(crop["收益"]) + "元\n" +
+ "需求等级: " + str(crop["等级"]) + "\n" +
+ "耐候性: " + str(crop["耐候性"]) + "\n" +
+ "经验: " + str(crop["经验"]) + "点\n" +
+ "描述: " + str(crop["描述"])
+ )
+
+ # 添加按钮事件
+ button.pressed.connect(func(): _on_store_buy_pressed(crop_name))
+
+ # 更新按钮的作物图片
+ _update_button_crop_image(button, crop_name)
+
+ # 如果按钮有标题标签,设置标题
+ if button.has_node("Title"):
+ match crop_quality:
+ "普通":
+ button.get_node("Title").modulate = Color.HONEYDEW#白色
+ "优良":
+ button.get_node("Title").modulate =Color.DODGER_BLUE#深蓝色
+ "稀有":
+ button.get_node("Title").modulate =Color.HOT_PINK#品红色
+ "史诗":
+ button.get_node("Title").modulate =Color.YELLOW#黄色
+ "传奇":
+ button.get_node("Title").modulate =Color.ORANGE_RED#红色
+
+ return button
+
+# 购买种子事件处理
+func _on_store_buy_pressed(crop_name: String):
+ print("购买种子: " + crop_name)
+ var crop = main_game.can_planted_crop[crop_name]
+
+ # 检查等级要求
+ if main_game.level < crop["等级"]:
+ Toast.show("等级不足,无法购买此种子", Color.RED)
+ return
+
+ # 检查金钱是否足够
+ if main_game.money < crop["花费"]:
+ Toast.show("金钱不足,无法购买种子", Color.RED)
+ return
+
+ # 发送购买请求到服务器
+ if network_manager and network_manager.sendBuySeed(crop_name):
+ # 购买请求已发送,等待服务器响应
+ Toast.show("正在购买种子...", Color.YELLOW, 2.0, 1.0)
+
+ # 将种子添加到背包
+ var found = false
+ for seed_item in main_game.player_bag:
+ if seed_item["name"] == crop_name:
+ seed_item["count"] += 1
+ found = true
+ break
+
+ if not found:
+ main_game.player_bag.append({
+ "name": crop_name,
+ "quality": crop["品质"],
+ "count": 1
+ })
+
+ # 显示购买成功消息
+ Toast.show("购买了" + crop["品质"] + "-" + crop_name + "种子", Color.GREEN)
+
+ # 更新背包UI
+ crop_store_panel.update_player_bag_ui()
+
+ # 更新金钱显示
+ _update_money_display()
+
+# 关闭面板
+func _on_quit_button_pressed():
+ print("关闭商店面板")
+ self.hide()
+
+# 按品质过滤作物
+func _filter_by_quality(quality: String):
+ current_filter_quality = quality
+ print("过滤作物,品质: " + (quality if quality != "" else "全部"))
+ _apply_filter_and_sort()
+
+# 按指定键排序
+func _sort_by(sort_key: String):
+ # 切换排序方向或设置新排序键
+ if current_sort_key == sort_key:
+ current_sort_ascending = !current_sort_ascending
+ else:
+ current_sort_key = sort_key
+ current_sort_ascending = true
+
+ print("排序作物,键: " + sort_key + ",升序: " + str(current_sort_ascending))
+ _apply_filter_and_sort()
+
+# 应用过滤和排序
+func _apply_filter_and_sort():
+ # 清空现有按钮
+ for child in crop_grid_container.get_children():
+ child.queue_free()
+
+ # 收集符合条件的作物
+ var filtered_crops = []
+ for crop_name in main_game.can_planted_crop:
+ var crop = main_game.can_planted_crop[crop_name]
+
+ # 检查等级和品质过滤
+ if crop["等级"] > main_game.level:
+ continue
+
+ if current_filter_quality != "" and crop["品质"] != current_filter_quality:
+ continue
+
+ # 添加到过滤后的列表
+ filtered_crops.append({
+ "name": crop_name,
+ "data": crop
+ })
+
+ # 如果有排序条件,进行排序
+ if current_sort_key != "":
+ filtered_crops.sort_custom(Callable(self, "_sort_crop_items"))
+
+ # 添加所有过滤和排序后的作物
+ for crop in filtered_crops:
+ var store_btn = _create_store_button(crop["name"], crop["data"]["品质"])
+ crop_grid_container.add_child(store_btn)
+
+ # 更新金钱显示
+ _update_money_display()
+
+# 自定义排序函数
+func _sort_crop_items(a, b):
+ if current_sort_ascending:
+ return a["data"][current_sort_key] < b["data"][current_sort_key]
+ else:
+ return a["data"][current_sort_key] > b["data"][current_sort_key]
+
+# 更新金钱显示
+func _update_money_display():
+ var money_label = get_node_or_null("MoneyLabel")
+ if money_label == null:
+ # 创建金钱显示标签
+ money_label = Label.new()
+ money_label.name = "MoneyLabel"
+ money_label.position = Vector2(10, 10)
+ money_label.size = Vector2(300, 45)
+
+ # 设置标签样式
+ money_label.add_theme_color_override("font_color", Color(1, 0.647, 0, 1)) # 橙色
+ money_label.add_theme_font_size_override("font_size", 24)
+
+ add_child(money_label)
+
+ # 更新金钱显示
+ money_label.text = "当前金钱:" + str(main_game.money) + " 元"
+ print("更新商店金钱显示:" + str(main_game.money))
+
+# 刷新商店内容,可以在金钱变化或等级提升后调用
+func refresh_store():
+ # 清空并重新创建商店按钮
+ init_store()
+
+ # 尝试创建过滤按钮(如果商店面板中没有这些按钮)
+ _create_filter_buttons_if_needed()
+
+# 如果需要,动态创建过滤按钮
+func _create_filter_buttons_if_needed():
+ # 检查是否已存在过滤器容器
+ var filter_container = get_node_or_null("FilterContainer")
+ if filter_container == null:
+ # 创建过滤器容器
+ filter_container = HBoxContainer.new()
+ filter_container.name = "FilterContainer"
+
+ # 设置容器位置和大小
+ filter_container.position = Vector2(320, 10)
+ filter_container.size = Vector2(770, 45)
+
+ add_child(filter_container)
+
+ # 添加过滤按钮
+ _add_filter_button(filter_container, "全部", func(): _filter_by_quality(""))
+ _add_filter_button(filter_container, "普通", func(): _filter_by_quality("普通"))
+ _add_filter_button(filter_container, "优良", func(): _filter_by_quality("优良"))
+ _add_filter_button(filter_container, "稀有", func(): _filter_by_quality("稀有"))
+ _add_filter_button(filter_container, "史诗", func(): _filter_by_quality("史诗"))
+ _add_filter_button(filter_container, "传奇", func(): _filter_by_quality("传奇"))
+
+ # 检查是否已存在排序容器
+ var sort_container = get_node_or_null("SortContainer")
+ if sort_container == null:
+ # 创建排序容器
+ sort_container = HBoxContainer.new()
+ sort_container.name = "SortContainer"
+
+ # 设置容器位置和大小
+ sort_container.position = Vector2(320, 55)
+ sort_container.size = Vector2(770, 30)
+
+ add_child(sort_container)
+
+ # 添加排序按钮
+ _add_filter_button(sort_container, "按价格", func(): _sort_by("花费"))
+ _add_filter_button(sort_container, "按生长时间", func(): _sort_by("生长时间"))
+ _add_filter_button(sort_container, "按收益", func(): _sort_by("收益"))
+ _add_filter_button(sort_container, "按等级", func(): _sort_by("等级"))
+
+# 添加过滤按钮
+func _add_filter_button(container, text, callback):
+ var button = Button.new()
+ button.text = text
+ button.custom_minimum_size = Vector2(100, 0)
+ button.size_flags_horizontal = Control.SIZE_EXPAND_FILL
+ container.add_child(button)
+ button.pressed.connect(callback)
+
+# 获取作物的最后一帧图片(用于商店显示)
+func _get_crop_final_texture(crop_name: String) -> Texture2D:
+ """
+ 获取作物的最后一帧图片,用于商店和背包显示
+ 如果作物图片不存在,使用默认图片的最后一帧
+ """
+ # 先尝试从主游戏的缓存中获取
+ if main_game and main_game.crop_textures_cache.has(crop_name):
+ var textures = main_game.crop_textures_cache[crop_name]
+ if textures.size() > 0:
+ return textures[textures.size() - 1] # 返回最后一帧
+
+ # 如果主游戏缓存中没有,自己加载
+ var textures = _load_crop_textures(crop_name)
+ if textures.size() > 0:
+ return textures[textures.size() - 1] # 返回最后一帧
+
+ return null
+
+# 加载作物图片序列帧(复用主游戏的逻辑)
+func _load_crop_textures(crop_name: String) -> Array:
+ """
+ 加载指定作物的所有序列帧图片
+ """
+ if crop_textures_cache.has(crop_name):
+ return crop_textures_cache[crop_name]
+
+ var textures = []
+ var crop_path = "res://assets/作物/" + crop_name + "/"
+ var default_path = "res://assets/作物/默认/"
+
+ # 检查作物文件夹是否存在
+ if DirAccess.dir_exists_absolute(crop_path):
+ # 尝试加载作物的序列帧(从0开始)
+ var frame_index = 0
+ while true:
+ var texture_path = crop_path + str(frame_index) + ".png"
+ if ResourceLoader.exists(texture_path):
+ var texture = load(texture_path)
+ if texture:
+ textures.append(texture)
+ frame_index += 1
+ else:
+ break
+ else:
+ break
+
+ if textures.size() > 0:
+ print("商店加载作物 ", crop_name, " 的 ", textures.size(), " 帧图片")
+ else:
+ print("商店:作物 ", crop_name, " 文件夹存在但没有找到有效图片,使用默认图片")
+ textures = _load_default_textures()
+ else:
+ print("商店:作物 ", crop_name, " 的文件夹不存在,使用默认图片")
+ textures = _load_default_textures()
+
+ # 缓存结果
+ crop_textures_cache[crop_name] = textures
+ crop_frame_counts[crop_name] = textures.size()
+
+ return textures
+
+# 加载默认图片
+func _load_default_textures() -> Array:
+ """
+ 加载默认作物图片
+ """
+ if crop_textures_cache.has("默认"):
+ return crop_textures_cache["默认"]
+
+ var textures = []
+ var default_path = "res://assets/作物/默认/"
+
+ # 尝试加载默认图片序列帧
+ var frame_index = 0
+ while true:
+ var texture_path = default_path + str(frame_index) + ".png"
+ if ResourceLoader.exists(texture_path):
+ var texture = load(texture_path)
+ if texture:
+ textures.append(texture)
+ frame_index += 1
+ else:
+ break
+ else:
+ break
+
+ # 如果没有找到序列帧,尝试加载单个默认图片
+ if textures.size() == 0:
+ var single_texture_path = default_path + "0.png"
+ if ResourceLoader.exists(single_texture_path):
+ var texture = load(single_texture_path)
+ if texture:
+ textures.append(texture)
+
+ # 缓存默认图片
+ crop_textures_cache["默认"] = textures
+ crop_frame_counts["默认"] = textures.size()
+
+ print("商店加载了 ", textures.size(), " 个默认作物图片")
+ return textures
+
+# 更新按钮的作物图片
+func _update_button_crop_image(button: Button, crop_name: String):
+ """
+ 更新按钮中的作物图片
+ """
+ # 检查按钮是否有CropImage节点
+ var crop_image = button.get_node_or_null("CropImage")
+ if not crop_image:
+ print("商店按钮没有找到CropImage节点:", button.name)
+ return
+
+ # 获取作物的最后一帧图片
+ var texture = _get_crop_final_texture(crop_name)
+
+ if texture:
+ # CropImage是Sprite2D,直接设置texture属性
+ crop_image.texture = texture
+ crop_image.visible = true
+ print("商店更新作物图片:", crop_name)
+ else:
+ crop_image.visible = false
+ print("商店无法获取作物图片:", crop_name)
+
+# 兼容MainGame.gd中的调用,转发到_on_store_buy_pressed
+func _on_crop_selected(crop_name: String):
+ _on_store_buy_pressed(crop_name)
diff --git a/GUI/crop_store_panel.gd.uid b/GUI/crop_store_panel.gd.uid
new file mode 100644
index 0000000..8f3c387
--- /dev/null
+++ b/GUI/crop_store_panel.gd.uid
@@ -0,0 +1 @@
+uid://mtfp0ct42nrx
diff --git a/GUI/land_panel.gd b/GUI/land_panel.gd
new file mode 100644
index 0000000..7c5a61a
--- /dev/null
+++ b/GUI/land_panel.gd
@@ -0,0 +1,126 @@
+extends Panel
+
+#获取玩家要操作的地块序号
+var selected_lot_index = 0
+
+#预添加常用的面板
+@onready var main_game = get_node("/root/main")
+@onready var land_panel = get_node("/root/main/UI/LandPanel")
+@onready var crop_store_panel = get_node("/root/main/UI/PlayerBagPanel")
+@onready var player_ranking_panel = get_node("/root/main/UI/PlayerRankingPanel")
+@onready var player_bag_panel = get_node("/root/main/UI/PlayerBagPanel")
+@onready var network_manager = get_node("/root/main/UI/TCPNetworkManager")
+
+@onready var quit_button :Button = $Quit_Button
+@onready var dig_button: Button = $Grid/Dig_Button
+@onready var water_button: Button = $Grid/Water_Button
+@onready var fertilize_button: Button = $Grid/Fertilize_Button
+@onready var upgrade_button: Button = $Grid/Upgrade_Button
+@onready var plant_button: Button = $Grid/Plant_Button
+@onready var remove_button: Button = $Grid/Remove_Button
+@onready var harvest_button: Button = $Grid/Harvest_Button
+
+
+func _ready():
+ self.hide()
+ quit_button.pressed.connect(self._on_quit_button_pressed)
+ dig_button.pressed.connect(self._on_dig_button_pressed)
+ water_button.pressed.connect(self._on_water_button_pressed)
+ fertilize_button.pressed.connect(self._on_fertilize_button_pressed)
+ upgrade_button.pressed.connect(self._on_upgrade_button_pressed)
+ plant_button.pressed.connect(self._on_plant_button_pressed)
+ remove_button.pressed.connect(self._on_remove_button_pressed)
+ harvest_button.pressed.connect(self._on_harvest_button_pressed)
+ dig_button.text = "开垦"+"\n花费:"+str(main_game.dig_money)
+
+#开垦
+func _on_dig_button_pressed():
+ # 检查是否处于访问模式
+ if main_game.is_visiting_mode:
+ Toast.show("访问模式下无法开垦土地", Color.ORANGE, 2.0, 1.0)
+ self.hide()
+ return
+
+ dig_button.text = "开垦"+"\n花费:"+str(main_game.dig_money)
+
+ if network_manager and network_manager.is_connected_to_server():
+ # 使用服务器API来开垦土地
+ if network_manager.sendDigGround(selected_lot_index):
+ self.hide()
+#浇水
+func _on_water_button_pressed():
+ # 检查是否处于访问模式
+ if main_game.is_visiting_mode:
+ Toast.show("访问模式下无法浇水", Color.ORANGE, 2.0, 1.0)
+ self.hide()
+ return
+
+ self.hide()
+ pass
+#施肥
+func _on_fertilize_button_pressed():
+ # 检查是否处于访问模式
+ if main_game.is_visiting_mode:
+ Toast.show("访问模式下无法施肥", Color.ORANGE, 2.0, 1.0)
+ self.hide()
+ return
+
+ self.hide()
+ pass
+#升级
+func _on_upgrade_button_pressed():
+ # 检查是否处于访问模式
+ if main_game.is_visiting_mode:
+ Toast.show("访问模式下无法升级", Color.ORANGE, 2.0, 1.0)
+ self.hide()
+ return
+
+ self.hide()
+ pass
+#种植
+func _on_plant_button_pressed():
+ # 检查是否处于访问模式
+ if main_game.is_visiting_mode:
+ Toast.show("访问模式下无法种植", Color.ORANGE, 2.0, 1.0)
+ self.hide()
+ return
+
+ player_bag_panel.show()
+ self.hide()
+ pass
+#铲除
+func _on_remove_button_pressed():
+ # 检查是否处于访问模式
+ if main_game.is_visiting_mode:
+ Toast.show("访问模式下无法铲除作物", Color.ORANGE, 2.0, 1.0)
+ self.hide()
+ return
+
+ main_game.root_out_crop(selected_lot_index)
+ self.hide()
+ pass
+#收获
+func _on_harvest_button_pressed():
+ # 检查是否处于访问模式
+ if main_game.is_visiting_mode:
+ Toast.show("访问模式下无法收获作物", Color.ORANGE, 2.0, 1.0)
+ self.hide()
+ return
+
+ main_game._harvest_crop(selected_lot_index)
+ self.hide()
+ pass
+#退出
+func _on_quit_button_pressed():
+ self.hide()
+ pass
+
+
+
+
+
+
+
+
+
+
diff --git a/GUI/land_panel.gd.uid b/GUI/land_panel.gd.uid
new file mode 100644
index 0000000..431760c
--- /dev/null
+++ b/GUI/land_panel.gd.uid
@@ -0,0 +1 @@
+uid://bljtkxil64h14
diff --git a/GUI/login.gd b/GUI/login.gd
deleted file mode 100644
index b086158..0000000
--- a/GUI/login.gd
+++ /dev/null
@@ -1,87 +0,0 @@
-extends Node
-
-var http_request: HTTPRequest
-var farm_lots = []
-
-@onready var harvest = $harvest
-@onready var label1 = $Label
-@onready var username_input = $Panel/username_input
-@onready var password_input = $Panel/password_input
-@onready var login_button = $Panel/login_button
-@onready var panel = $Panel
-@onready var item_list = $item_list #ItemList
-
-func _ready():
- # 创建 HTTPRequest 节点
- http_request = HTTPRequest.new()
- add_child(http_request)
- # 连接信号
- http_request.connect("request_completed", Callable(self, "_on_request_completed"))
- # 连接登录按钮点击事件
- login_button.connect("pressed", Callable(self, "_on_login_button_pressed"))
-
-# 登录按钮按下事件
-func _on_login_button_pressed():
- # 隐藏面板(只有在输入后才进行隐藏)
- panel.hide()
-
- # 获取用户名和密码输入
- var username = username_input.text # 直接获取输入
- var password = password_input.text # 直接获取输入
-
- # 打印调试信息
- print("Username entered: ", username)
- print("Password entered: ", password)
-
- # 检查用户名和密码是否为空
- if username == "" or password == "":
- print("用户名和密码不能为空")
- panel.show() # 如果输入为空,显示面板
- return
-
- # 构建登录请求的 URL 和参数
- var url = "https://api.shumengya.top/smyfarm/login.php"
- var body = {
- "username": username,
- "password": password
- }
-
- # 发送 POST 请求进行登录
- var err = http_request.request(url, [], HTTPClient.METHOD_POST, JSON.stringify(body))
- if err != OK:
- print("Error making HTTP POST request: ", err)
-
-# 请求完成后的回调函数
-func _on_request_completed(result, response_code, headers, body):
- if response_code == 200:
- var json = JSON.new()
- var parse_result = json.parse(body.get_string_from_utf8())
-
- if parse_result != OK:
- print("Error parsing JSON: ", json.get_error_message())
- return
-
- var json_data = json.data
-
- if json_data.has("error"):
- print("Error: " + str(json_data["error"]))
- panel.show() # 如果登录失败,显示面板,允许重新输入
- elif json_data.has("message"):
- print(json_data["message"])
-
- # 处理登录成功
- if json_data.has("data"):
- var player_data = json_data["data"]
- print("欢迎, " + player_data["username"])
-
- # 加载玩家数据,进入游戏逻辑
- _load_player_data(player_data)
- else:
- print("HTTP Request failed with response code: " + str(response_code))
- panel.show() # 请求失败,重新显示面板
-
-# 加载玩家数据
-func _load_player_data(player_data):
- # 根据返回的 player_data 初始化玩家的农场状态等
- pass
-
diff --git a/GUI/login_panel.gd b/GUI/login_panel.gd
new file mode 100644
index 0000000..16fe216
--- /dev/null
+++ b/GUI/login_panel.gd
@@ -0,0 +1,433 @@
+#玩家登录注册面板
+extends PanelContainer
+
+#玩家登录账号,用QQ号代替
+@onready var username_input : LineEdit = $VBox/UserName/username_input
+#用户登录密码
+@onready var password_input : LineEdit = $VBox/Password1/password_input
+#登录按钮
+@onready var login_button : Button = $VBox/LoginRegister/login_button
+
+#下面是注册相关的
+#注册按钮
+@onready var register_button : Button = $VBox/LoginRegister/register_button
+#注册账号时二次确认密码
+@onready var password_input_2 : LineEdit = $VBox/Password2/password_input2
+#农场名称
+@onready var farmname_input : LineEdit = $VBox/FarmName/farmname_input
+#玩家昵称
+@onready var playername_input :LineEdit = $VBox/PlayerName/playername_input
+#邮箱验证码
+@onready var verificationcode_input :LineEdit = $VBox/VerificationCode/verificationcode_input
+#发送验证码按钮
+@onready var send_button :Button = $VBox/VerificationCode/SendButton
+#状态提示标签
+@onready var status_label : Label = $VBox/status_label
+
+# 记住密码选项(如果UI中有CheckBox的话)
+var remember_password : bool = true # 默认记住密码
+
+# 引用主场景和全局函数
+@onready var main_game = get_node("/root/main")
+@onready var land_panel = get_node("/root/main/UI/LandPanel")
+@onready var crop_store_panel = get_node("/root/main/UI/PlayerBagPanel")
+@onready var player_ranking_panel = get_node("/root/main/UI/PlayerRankingPanel")
+@onready var player_bag_panel = get_node("/root/main/UI/PlayerBagPanel")
+@onready var tcp_network_manager = get_node("/root/main/UI/TCPNetworkManager")
+
+# 准备函数
+func _ready():
+
+ # 连接按钮信号
+ login_button.pressed.connect(self._on_login_button_pressed)
+ register_button.pressed.connect(self._on_register_button_pressed)
+ send_button.pressed.connect(self._on_send_button_pressed)
+
+ # 加载保存的登录信息
+ _load_login_info()
+
+# 处理登录按钮点击
+func _on_login_button_pressed():
+ var user_name = username_input.text.strip_edges() # 修剪前后的空格
+ var user_password = password_input.text.strip_edges()
+ var farmname = farmname_input.text.strip_edges()
+
+ if user_name == "" or user_password == "":
+ status_label.text = "用户名或密码不能为空!"
+ status_label.modulate = Color.RED
+ return
+
+ # 检查网络连接状态
+ if !tcp_network_manager.client.is_client_connected():
+ status_label.text = "未连接到服务器,正在尝试连接..."
+ status_label.modulate = Color.YELLOW
+ # 尝试自动连接到服务器
+ tcp_network_manager._on_connection_button_pressed()
+ await get_tree().create_timer(1.0).timeout
+
+ # 再次检查连接状态
+ if !tcp_network_manager.client.is_client_connected():
+ status_label.text = "连接服务器失败,请检查网络设置!"
+ status_label.modulate = Color.RED
+ return
+
+ # 禁用按钮,防止重复点击
+ login_button.disabled = true
+
+ status_label.text = "正在登录,请稍候..."
+ status_label.modulate = Color.YELLOW
+
+ # 如果启用了记住密码,保存登录信息
+ if remember_password:
+ _save_login_info(user_name, user_password)
+
+ tcp_network_manager.sendLoginInfo(user_name, user_password)
+
+ # 更新主游戏数据
+ main_game.user_name = user_name
+ main_game.user_password = user_password
+ main_game.farmname = farmname
+
+ # 5秒后重新启用按钮(如果没有收到响应)
+ await get_tree().create_timer(5.0).timeout
+ if login_button.disabled:
+ login_button.disabled = false
+ status_label.text = "登录超时,请重试!"
+ status_label.modulate = Color.RED
+
+# 处理验证码发送按钮点击
+func _on_send_button_pressed():
+ var user_name = username_input.text.strip_edges()
+
+ if user_name == "":
+ status_label.text = "请输入QQ号以接收验证码!"
+ status_label.modulate = Color.RED
+ return
+
+ if !is_valid_qq_number(user_name):
+ status_label.text = "请输入正确的QQ号码(5-12位数字)!"
+ status_label.modulate = Color.RED
+ return
+
+ # 检查网络连接状态
+ if !tcp_network_manager.client.is_client_connected():
+ status_label.text = "未连接到服务器,正在尝试连接..."
+ status_label.modulate = Color.YELLOW
+ # 尝试自动连接到服务器
+ tcp_network_manager._on_connection_button_pressed()
+ await get_tree().create_timer(1.0).timeout
+
+ # 再次检查连接状态
+ if !tcp_network_manager.client.is_client_connected():
+ status_label.text = "连接服务器失败,请检查网络设置!"
+ status_label.modulate = Color.RED
+ return
+
+ # 禁用按钮,防止重复点击
+ send_button.disabled = true
+
+ status_label.text = "正在发送验证码,请稍候..."
+ status_label.modulate = Color.YELLOW
+
+ # 发送验证码请求
+ tcp_network_manager.sendVerificationCodeRequest(user_name)
+
+ # 60秒后重新启用按钮(或收到响应后提前启用)
+ var timer = 60
+ while timer > 0 and send_button.disabled:
+ send_button.text = "重新发送(%d)" % timer
+ await get_tree().create_timer(1.0).timeout
+ timer -= 1
+
+ if send_button.disabled:
+ send_button.disabled = false
+ send_button.text = "发送验证码"
+
+ if status_label.text == "正在发送验证码,请稍候...":
+ status_label.text = "验证码发送超时,请重试!"
+ status_label.modulate = Color.RED
+
+# 处理注册按钮点击
+func _on_register_button_pressed():
+ var user_name = username_input.text.strip_edges()
+ var user_password = password_input.text.strip_edges()
+ var user_password_2 = password_input_2.text.strip_edges()
+ var farmname = farmname_input.text.strip_edges()
+ var player_name = playername_input.text.strip_edges()
+ var verification_code = verificationcode_input.text.strip_edges()
+
+ if user_name == "" or user_password == "":
+ status_label.text = "用户名或密码不能为空!"
+ status_label.modulate = Color.RED
+ return
+ if farmname == "":
+ status_label.text = "农场名称不能为空!"
+ status_label.modulate = Color.RED
+ return
+ if user_password != user_password_2:
+ status_label.text = "两次输入的密码不一致!"
+ status_label.modulate = Color.RED
+ return
+
+ if !is_valid_qq_number(user_name):
+ status_label.text = "请输入正确的QQ号码(5-12位数字)!"
+ status_label.modulate = Color.RED
+ return
+
+ if verification_code == "":
+ status_label.text = "请输入验证码!"
+ status_label.modulate = Color.RED
+ return
+
+ # 检查网络连接状态
+ if !tcp_network_manager.client.is_client_connected():
+ status_label.text = "未连接到服务器,正在尝试连接..."
+ status_label.modulate = Color.YELLOW
+ # 尝试自动连接到服务器
+ tcp_network_manager._on_connection_button_pressed()
+ await get_tree().create_timer(1.0).timeout
+
+ # 再次检查连接状态
+ if !tcp_network_manager.client.is_client_connected():
+ status_label.text = "连接服务器失败,请检查网络设置!"
+ status_label.modulate = Color.RED
+ return
+
+ # 禁用按钮,防止重复点击
+ register_button.disabled = true
+
+ status_label.text = "正在注册,请稍候..."
+ status_label.modulate = Color.YELLOW
+
+ # 发送注册请求
+ tcp_network_manager.sendRegisterInfo(user_name, user_password, farmname, player_name, verification_code)
+
+ # 更新主游戏数据
+ main_game.user_name = user_name
+ main_game.user_password = user_password
+ main_game.farmname = farmname
+
+ # 5秒后重新启用按钮(如果没有收到响应)
+ await get_tree().create_timer(5.0).timeout
+ if register_button.disabled:
+ register_button.disabled = false
+ status_label.text = "注册超时,请重试!"
+ status_label.modulate = Color.RED
+
+# 处理验证码发送响应
+func _on_verification_code_response(success: bool, message: String):
+ if success:
+ status_label.text = message
+ status_label.modulate = Color.GREEN
+ else:
+ status_label.text = message
+ status_label.modulate = Color.RED
+ send_button.disabled = false
+ send_button.text = "发送验证码"
+
+# 处理验证码验证响应
+func _on_verify_code_response(success: bool, message: String):
+ if success:
+ status_label.text = message
+ status_label.modulate = Color.GREEN
+ else:
+ status_label.text = message
+ status_label.modulate = Color.RED
+
+# 验证QQ号是否有效
+func is_valid_qq_number(qq_number: String) -> bool:
+ # QQ号的标准格式是5到12位的数字
+ var qq_regex = RegEx.new()
+ var pattern = r"^\d{5,12}$"
+
+ var error = qq_regex.compile(pattern)
+ if error != OK:
+ status_label.text = "QQ号验证失败部错误"
+ status_label.modulate = Color.RED
+ return false
+
+ return qq_regex.search(qq_number) != null
+
+# 处理登录响应
+func _on_login_response_received(success: bool, message: String, user_data: Dictionary):
+ # 启用按钮
+ login_button.disabled = false
+
+ if success:
+ status_label.text = "登录成功!正在加载游戏..."
+ status_label.modulate = Color.GREEN
+
+ # 更新主游戏数据
+ main_game.experience = user_data.get("experience", 0)
+ main_game.farm_lots = user_data.get("farm_lots", [])
+ main_game.level = user_data.get("level", 1)
+ main_game.money = user_data.get("money", 0)
+ main_game.farmname = user_data.get("farm_name", "")
+ farmname_input.text = user_data.get("farm_name", "")
+
+ # 加载玩家背包数据
+ if user_data.has("player_bag"):
+ main_game.player_bag = user_data.get("player_bag", [])
+ else:
+ main_game.player_bag = []
+
+ main_game.start_game = true
+ self.hide()
+
+ # 确保在更新数据后调用主游戏的 UI 更新函数
+ main_game._update_ui()
+ main_game._refresh_farm_lots()
+ player_bag_panel.update_player_bag_ui()
+ else:
+ status_label.text = "登录失败:" + message
+ status_label.modulate = Color.RED
+
+ # 如果登录失败且是密码错误,可以选择清除保存的信息
+ if "密码" in message or "password" in message.to_lower():
+ print("登录失败,可能是密码错误。如需清除保存的登录信息,请调用_clear_login_info()")
+
+# 处理注册响应
+func _on_register_response_received(success: bool, message: String):
+ # 启用按钮
+ register_button.disabled = false
+
+ if success:
+ status_label.text = "注册成功!请登录游戏"
+ status_label.modulate = Color.GREEN
+
+ # 注册成功后,如果启用了记住密码,保存登录信息
+ if remember_password:
+ var user_name = username_input.text.strip_edges()
+ var user_password = password_input.text.strip_edges()
+ _save_login_info(user_name, user_password)
+
+ # 清除注册相关的输入框
+ password_input_2.text = ""
+ verificationcode_input.text = ""
+ else:
+ status_label.text = "注册失败:" + message
+ status_label.modulate = Color.RED
+
+# 保存登录信息到JSON文件
+func _save_login_info(user_name: String, password: String):
+ var login_data = {
+ "user_name": user_name,
+ "password": password
+ }
+
+ var file = FileAccess.open("user://login.json", FileAccess.WRITE)
+ if file:
+ var json_string = JSON.stringify(login_data, "\t")
+ file.store_string(json_string)
+ file.close()
+ print("登录信息已保存")
+ else:
+ print("无法保存登录信息")
+
+# 从JSON文件加载登录信息
+func _load_login_info():
+ var file = FileAccess.open("user://login.json", FileAccess.READ)
+ if file:
+ var json_text = file.get_as_text()
+ file.close()
+
+ var json = JSON.new()
+ var parse_result = json.parse(json_text)
+ if parse_result == OK:
+ var login_data = json.get_data()
+ if login_data.has("user_name") and login_data.has("password"):
+ var saved_username = login_data.get("user_name", "")
+ var saved_password = login_data.get("password", "")
+
+ if saved_username != "" and saved_password != "":
+ username_input.text = saved_username
+ password_input.text = saved_password
+ status_label.text = "已加载保存的登录信息"
+ status_label.modulate = Color.CYAN
+ print("登录信息已加载:用户名 =", saved_username)
+ else:
+ status_label.text = "欢迎使用萌芽农场"
+ status_label.modulate = Color.WHITE
+ print("没有有效的保存登录信息")
+ else:
+ print("登录信息格式错误")
+ else:
+ print("登录信息JSON解析错误:", json.get_error_message())
+ else:
+ # 创建默认的登录信息文件
+ _save_login_info("", "")
+ status_label.text = "欢迎使用萌芽农场"
+ status_label.modulate = Color.WHITE
+ print("没有找到保存的登录信息,已创建默认文件")
+
+# 清除保存的登录信息
+func _clear_login_info():
+ var file = FileAccess.open("user://login.json", FileAccess.WRITE)
+ if file:
+ var empty_data = {
+ "user_name": "",
+ "password": ""
+ }
+ var json_string = JSON.stringify(empty_data, "\t")
+ file.store_string(json_string)
+ file.close()
+ print("登录信息已清除")
+ else:
+ print("无法清除登录信息")
+
+# 切换记住密码选项
+func toggle_remember_password():
+ remember_password = !remember_password
+ print("记住密码选项:", "开启" if remember_password else "关闭")
+
+ # 如果关闭了记住密码,清除已保存的信息
+ if not remember_password:
+ _clear_login_info()
+
+# 检查是否有保存的登录信息
+func has_saved_login_info() -> bool:
+ var file = FileAccess.open("user://login.json", FileAccess.READ)
+ if file:
+ var json_text = file.get_as_text()
+ file.close()
+
+ var json = JSON.new()
+ var parse_result = json.parse(json_text)
+ if parse_result == OK:
+ var login_data = json.get_data()
+ var user_name = login_data.get("user_name", "")
+ var password = login_data.get("password", "")
+ return user_name != "" and password != ""
+
+ return false
+
+# 快捷登录(使用保存的登录信息)
+func quick_login():
+ if has_saved_login_info():
+ var user_name = username_input.text.strip_edges()
+ var user_password = password_input.text.strip_edges()
+
+ if user_name != "" and user_password != "":
+ print("执行快捷登录...")
+ _on_login_button_pressed()
+ else:
+ status_label.text = "保存的登录信息不完整"
+ status_label.modulate = Color.ORANGE
+ else:
+ status_label.text = "没有保存的登录信息"
+ status_label.modulate = Color.ORANGE
+
+# 获取保存的用户名(用于调试或显示)
+func get_saved_username() -> String:
+ var file = FileAccess.open("user://login.json", FileAccess.READ)
+ if file:
+ var json_text = file.get_as_text()
+ file.close()
+
+ var json = JSON.new()
+ var parse_result = json.parse(json_text)
+ if parse_result == OK:
+ var login_data = json.get_data()
+ return login_data.get("user_name", "")
+
+ return ""
diff --git a/GUI/login_panel.gd.uid b/GUI/login_panel.gd.uid
new file mode 100644
index 0000000..59912fd
--- /dev/null
+++ b/GUI/login_panel.gd.uid
@@ -0,0 +1 @@
+uid://cka0r4g8tbf0
diff --git a/GUI/player_bag_panel.gd b/GUI/player_bag_panel.gd
new file mode 100644
index 0000000..317b476
--- /dev/null
+++ b/GUI/player_bag_panel.gd
@@ -0,0 +1,479 @@
+extends Panel
+
+# 背包格子容器
+@onready var player_bag_grid_container : GridContainer = $ScrollContainer/Bag_Grid
+@onready var quit_button : Button = $QuitButton
+
+#各种排序过滤按钮
+@onready var sort_all_button : Button = $SortContainer/Sort_All#全部
+@onready var sort_common_button : Button = $SortContainer/Sort_Common#普通
+@onready var sort_superior_button : Button = $SortContainer/Sort_Superior#优良
+@onready var sort_rare_button : Button = $SortContainer/Sort_Rare#稀有
+@onready var sort_epic_button : Button = $SortContainer/Sort_Epic#史诗
+@onready var sort_legendary_button : Button = $SortContainer/Sort_Legendary#传奇
+@onready var sort_price_button : Button = $SortContainer/Sort_Price#价格
+@onready var sort_growtime_button : Button = $SortContainer/Sort_GrowTime#生长时间
+@onready var sort_profit_button : Button = $SortContainer/Sort_Profit#收益
+@onready var sort_level_button : Button = $SortContainer/Sort_Level#等级
+
+#预添加常用的面板
+@onready var main_game = get_node("/root/main")
+@onready var land_panel = get_node("/root/main/UI/LandPanel")
+@onready var crop_store_panel = get_node("/root/main/UI/PlayerBagPanel")
+@onready var player_ranking_panel = get_node("/root/main/UI/PlayerRankingPanel")
+@onready var player_bag_panel = get_node("/root/main/UI/PlayerBagPanel")
+@onready var network_manager = get_node("/root/main/UI/TCPNetworkManager")
+
+# 作物图片缓存(复用主游戏的缓存系统)
+var crop_textures_cache : Dictionary = {}
+var crop_frame_counts : Dictionary = {}
+
+# 当前选择的地块索引,从MainGame获取
+var selected_lot_index : int = -1
+
+# 当前过滤和排序设置
+var current_filter_quality = ""
+var current_sort_key = ""
+var current_sort_ascending = true
+
+# 准备函数
+func _ready():
+ # 连接按钮信号
+ _connect_buttons()
+
+ # 隐藏面板(初始默认隐藏)
+ self.hide()
+
+# 连接所有按钮信号
+func _connect_buttons():
+ # 关闭按钮
+ quit_button.pressed.connect(self._on_quit_button_pressed)
+
+ # 过滤按钮
+ sort_all_button.pressed.connect(func(): _filter_by_quality(""))
+ sort_common_button.pressed.connect(func(): _filter_by_quality("普通"))
+ sort_superior_button.pressed.connect(func(): _filter_by_quality("优良"))
+ sort_rare_button.pressed.connect(func(): _filter_by_quality("稀有"))
+ sort_epic_button.pressed.connect(func(): _filter_by_quality("史诗"))
+ sort_legendary_button.pressed.connect(func(): _filter_by_quality("传奇"))
+
+ # 排序按钮
+ sort_price_button.pressed.connect(func(): _sort_by("花费"))
+ sort_growtime_button.pressed.connect(func(): _sort_by("生长时间"))
+ sort_profit_button.pressed.connect(func(): _sort_by("收益"))
+ sort_level_button.pressed.connect(func(): _sort_by("等级"))
+
+# 初始化玩家背包
+func init_player_bag():
+ # 清空玩家背包格子
+ for child in player_bag_grid_container.get_children():
+ child.queue_free()
+
+ # 显示背包中的种子
+ update_player_bag_ui()
+
+# 更新玩家背包UI
+func update_player_bag_ui():
+ # 清空玩家背包格子
+ for child in player_bag_grid_container.get_children():
+ child.queue_free()
+ #print("更新背包UI,背包中物品数量:", main_game.player_bag.size())
+
+ # 应用过滤和排序
+ var filtered_seeds = _get_filtered_and_sorted_seeds()
+
+ # 为背包中的每个过滤后的种子创建按钮
+ for seed_item in filtered_seeds:
+ var crop_name = seed_item["name"]
+ var crop_quality = seed_item["quality"]
+ var crop_count = seed_item["count"]
+ #print("背包物品:", crop_name, " 数量:", crop_count)
+ # 创建种子按钮
+ var button = _create_crop_button(crop_name, crop_quality)
+ # 更新按钮文本显示数量
+ button.text = str(crop_quality + "-" + crop_name + "\n数量:" + str(crop_count))
+
+ # 根据是否处于访问模式连接不同的事件
+ if main_game.is_visiting_mode:
+ # 访问模式下,点击种子只显示信息,不能种植
+ button.pressed.connect(func(): _on_visit_seed_selected(crop_name, crop_count))
+ else:
+ # 正常模式下,连接种植事件
+ button.pressed.connect(func(): _on_bag_seed_selected(crop_name))
+
+ player_bag_grid_container.add_child(button)
+
+# 获取过滤和排序后的种子列表
+func _get_filtered_and_sorted_seeds():
+ var filtered_seeds = []
+
+ # 收集符合条件的种子
+ for seed_item in main_game.player_bag:
+ # 品质过滤
+ if current_filter_quality != "" and seed_item["quality"] != current_filter_quality:
+ continue
+
+ # 获取种子对应的作物数据
+ var crop_data = null
+ if main_game.can_planted_crop.has(seed_item["name"]):
+ crop_data = main_game.can_planted_crop[seed_item["name"]]
+
+ # 添加到过滤后的列表
+ filtered_seeds.append({
+ "name": seed_item["name"],
+ "quality": seed_item["quality"],
+ "count": seed_item["count"],
+ "data": crop_data
+ })
+
+ # 如果有排序条件且数据可用,进行排序
+ if current_sort_key != "":
+ filtered_seeds.sort_custom(Callable(self, "_sort_seed_items"))
+
+ return filtered_seeds
+
+# 自定义排序函数
+func _sort_seed_items(a, b):
+ # 检查是否有有效数据用于排序
+ if a["data"] == null or b["data"] == null:
+ # 如果某一项没有数据,将其排在后面
+ if a["data"] == null and b["data"] != null:
+ return false
+ if a["data"] != null and b["data"] == null:
+ return true
+ # 如果都没有数据,按名称排序
+ return a["name"] < b["name"]
+
+ # 确保排序键存在于数据中
+ if !a["data"].has(current_sort_key) or !b["data"].has(current_sort_key):
+ print("警告: 排序键 ", current_sort_key, " 在某些种子数据中不存在")
+ return false
+
+ # 执行排序
+ if current_sort_ascending:
+ return a["data"][current_sort_key] < b["data"][current_sort_key]
+ else:
+ return a["data"][current_sort_key] > b["data"][current_sort_key]
+
+# 按品质过滤种子
+func _filter_by_quality(quality: String):
+ current_filter_quality = quality
+ print("过滤种子,品质: " + (quality if quality != "" else "全部"))
+ update_player_bag_ui()
+
+# 按指定键排序
+func _sort_by(sort_key: String):
+ # 切换排序方向或设置新排序键
+ if current_sort_key == sort_key:
+ current_sort_ascending = !current_sort_ascending
+ else:
+ current_sort_key = sort_key
+ current_sort_ascending = true
+
+ print("排序种子,键: " + sort_key + ",升序: " + str(current_sort_ascending))
+ update_player_bag_ui()
+
+# 创建作物按钮
+func _create_crop_button(crop_name: String, crop_quality: String) -> Button:
+ # 根据品质选择相应的进度条
+ var button = null
+ #普通 Color.HONEYDEW#白色
+ #优良 Color.DODGER_BLUE#深蓝色
+ #稀有 Color.HOT_PINK#品红色
+ #史诗 Color.YELLOW#黄色
+ #传奇 Color.ORANGE_RED#红色
+ #空地 Color.GREEN#绿色
+ #未开垦 Color.WEB_GRAY#深褐色
+ match crop_quality:
+ "普通":
+ button = main_game.green_bar.duplicate()
+ "优良":
+ button = main_game.orange_bar.duplicate()
+ "稀有":
+ button = main_game.white_blue_bar.duplicate()
+ "史诗":
+ button = main_game.pink_bar.duplicate()
+ "传奇":
+ button = main_game.black_blue_bar.duplicate()
+ _: # 默认情况
+ button = main_game.green_bar.duplicate()
+
+ # 确保按钮可见并可点击
+ button.visible = true
+ button.disabled = false
+ button.focus_mode = Control.FOCUS_ALL
+
+ # 设置按钮文本
+ button.text = str(crop_quality + "-" + crop_name)
+
+ # 添加工具提示 (tooltip)
+ if main_game.can_planted_crop.has(crop_name):
+ var crop = main_game.can_planted_crop[crop_name]
+
+ # 将成熟时间从秒转换为天时分秒格式
+ var total_seconds = int(crop["生长时间"])
+
+ # 定义时间单位换算
+ var SECONDS_PER_MINUTE = 60
+ var SECONDS_PER_HOUR = 3600
+ var SECONDS_PER_DAY = 86400
+
+ # 计算各时间单位
+ var days = total_seconds / SECONDS_PER_DAY
+ total_seconds %= SECONDS_PER_DAY
+
+ var hours = total_seconds / SECONDS_PER_HOUR
+ total_seconds %= SECONDS_PER_HOUR
+
+ var minutes = total_seconds / SECONDS_PER_MINUTE
+ var seconds = total_seconds % SECONDS_PER_MINUTE
+
+ # 构建时间字符串(只显示有值的单位)
+ var time_str = ""
+ if days > 0:
+ time_str += str(days) + "天"
+ if hours > 0:
+ time_str += str(hours) + "小时"
+ if minutes > 0:
+ time_str += str(minutes) + "分钟"
+ if seconds > 0:
+ time_str += str(seconds) + "秒"
+
+ button.tooltip_text = str(
+ "作物: " + crop_name + "\n" +
+ "品质: " + crop_quality + "\n" +
+ "价格: " + str(crop["花费"]) + "元\n" +
+ "成熟时间: " + time_str + "\n" +
+ "收获收益: " + str(crop["收益"]) + "元\n" +
+ "需求等级: " + str(crop["等级"]) + "\n" +
+ "耐候性: " + str(crop["耐候性"]) + "\n" +
+ "经验: " + str(crop["经验"]) + "点\n" +
+ "描述: " + str(crop["描述"])
+ )
+
+ # 如果按钮有标题标签,设置标题
+ if button.has_node("Title"):
+ button.get_node("Title").text = crop_quality
+ match crop_quality:
+ "普通":
+ button.get_node("Title").modulate = Color.HONEYDEW#白色
+ "优良":
+ button.get_node("Title").modulate =Color.DODGER_BLUE#深蓝色
+ "稀有":
+ button.get_node("Title").modulate =Color.HOT_PINK#品红色
+ "史诗":
+ button.get_node("Title").modulate =Color.YELLOW#黄色
+ "传奇":
+ button.get_node("Title").modulate =Color.ORANGE_RED#红色
+
+ # 更新按钮的作物图片
+ _update_button_crop_image(button, crop_name)
+
+ return button
+
+# 从背包中选择种子并种植
+func _on_bag_seed_selected(crop_name):
+ # 检查是否处于访问模式
+ if main_game.is_visiting_mode:
+ Toast.show("访问模式下无法种植", Color.ORANGE, 2.0, 1.0)
+ return
+
+ # 从主场景获取当前选择的地块索引
+ selected_lot_index = main_game.selected_lot_index
+
+ if selected_lot_index != -1:
+ # 检查背包中是否有这个种子
+ var seed_index = -1
+ for i in range(len(main_game.player_bag)):
+ if main_game.player_bag[i]["name"] == crop_name:
+ seed_index = i
+ break
+ #print("选择种子:", crop_name, ",背包索引:", seed_index)
+
+ if seed_index != -1 and main_game.player_bag[seed_index]["count"] > 0:
+ # 种植种子并从背包中减少数量
+ _plant_crop_from_bag(selected_lot_index, crop_name, seed_index)
+ main_game.selected_lot_index = -1
+ self.hide()
+
+# 访问模式下的种子点击处理
+func _on_visit_seed_selected(crop_name, crop_count):
+ # 显示种子信息
+ var info_text = ""
+
+ if main_game.can_planted_crop.has(crop_name):
+ var crop = main_game.can_planted_crop[crop_name]
+ var quality = crop.get("品质", "未知")
+ var price = crop.get("花费", 0)
+ var grow_time = crop.get("生长时间", 0)
+ var profit = crop.get("收益", 0)
+ var level_req = crop.get("等级", 1)
+
+ # 将成熟时间转换为可读格式
+ var time_str = ""
+ var total_seconds = int(grow_time)
+ var hours = total_seconds / 3600
+ var minutes = (total_seconds % 3600) / 60
+ var seconds = total_seconds % 60
+
+ if hours > 0:
+ time_str += str(hours) + "小时"
+ if minutes > 0:
+ time_str += str(minutes) + "分钟"
+ if seconds > 0:
+ time_str += str(seconds) + "秒"
+
+ info_text = quality + "-" + crop_name + " (数量: " + str(crop_count) + ")\n"
+ info_text += "价格: " + str(price) + "元, 收益: " + str(profit) + "元\n"
+ info_text += "成熟时间: " + time_str + ", 需求等级: " + str(level_req)
+ else:
+ info_text = crop_name + " (数量: " + str(crop_count) + ")"
+
+ Toast.show(info_text, Color.CYAN, 3.0, 1.0)
+ print("查看种子信息: ", info_text)
+
+# 从背包种植作物
+func _plant_crop_from_bag(index, crop_name, seed_index):
+ var crop = main_game.can_planted_crop[crop_name]
+
+ # 检查是否有效的种子索引,防止越界访问
+ if seed_index < 0 or seed_index >= main_game.player_bag.size():
+ #print("错误:无效的种子索引 ", seed_index)
+ return
+
+ # 发送种植请求到服务器
+
+ if network_manager and network_manager.sendPlantCrop(index, crop_name):
+ # 种植请求已发送,等待服务器响应
+ Toast.show("正在发送种植请求", Color.YELLOW, 2.0, 1.0)
+ # 关闭背包面板
+ hide()
+
+# 关闭面板
+func _on_quit_button_pressed():
+ self.hide()
+
+# 获取作物的最后一帧图片(用于背包显示)
+func _get_crop_final_texture(crop_name: String) -> Texture2D:
+ """
+ 获取作物的最后一帧图片,用于背包显示
+ 如果作物图片不存在,使用默认图片的最后一帧
+ """
+ # 先尝试从主游戏的缓存中获取
+ if main_game and main_game.crop_textures_cache.has(crop_name):
+ var textures = main_game.crop_textures_cache[crop_name]
+ if textures.size() > 0:
+ return textures[textures.size() - 1] # 返回最后一帧
+
+ # 如果主游戏缓存中没有,自己加载
+ var textures = _load_crop_textures(crop_name)
+ if textures.size() > 0:
+ return textures[textures.size() - 1] # 返回最后一帧
+
+ return null
+
+# 加载作物图片序列帧(复用主游戏的逻辑)
+func _load_crop_textures(crop_name: String) -> Array:
+ """
+ 加载指定作物的所有序列帧图片
+ """
+ if crop_textures_cache.has(crop_name):
+ return crop_textures_cache[crop_name]
+
+ var textures = []
+ var crop_path = "res://assets/作物/" + crop_name + "/"
+ var default_path = "res://assets/作物/默认/"
+
+ # 检查作物文件夹是否存在
+ if DirAccess.dir_exists_absolute(crop_path):
+ # 尝试加载作物的序列帧(从0开始)
+ var frame_index = 0
+ while true:
+ var texture_path = crop_path + str(frame_index) + ".png"
+ if ResourceLoader.exists(texture_path):
+ var texture = load(texture_path)
+ if texture:
+ textures.append(texture)
+ frame_index += 1
+ else:
+ break
+ else:
+ break
+
+ if textures.size() > 0:
+ print("背包加载作物 ", crop_name, " 的 ", textures.size(), " 帧图片")
+ else:
+ print("背包:作物 ", crop_name, " 文件夹存在但没有找到有效图片,使用默认图片")
+ textures = _load_default_textures()
+ else:
+ print("背包:作物 ", crop_name, " 的文件夹不存在,使用默认图片")
+ textures = _load_default_textures()
+
+ # 缓存结果
+ crop_textures_cache[crop_name] = textures
+ crop_frame_counts[crop_name] = textures.size()
+
+ return textures
+
+# 加载默认图片
+func _load_default_textures() -> Array:
+ """
+ 加载默认作物图片
+ """
+ if crop_textures_cache.has("默认"):
+ return crop_textures_cache["默认"]
+
+ var textures = []
+ var default_path = "res://assets/作物/默认/"
+
+ # 尝试加载默认图片序列帧
+ var frame_index = 0
+ while true:
+ var texture_path = default_path + str(frame_index) + ".png"
+ if ResourceLoader.exists(texture_path):
+ var texture = load(texture_path)
+ if texture:
+ textures.append(texture)
+ frame_index += 1
+ else:
+ break
+ else:
+ break
+
+ # 如果没有找到序列帧,尝试加载单个默认图片
+ if textures.size() == 0:
+ var single_texture_path = default_path + "0.png"
+ if ResourceLoader.exists(single_texture_path):
+ var texture = load(single_texture_path)
+ if texture:
+ textures.append(texture)
+
+ # 缓存默认图片
+ crop_textures_cache["默认"] = textures
+ crop_frame_counts["默认"] = textures.size()
+
+ print("背包加载了 ", textures.size(), " 个默认作物图片")
+ return textures
+
+# 更新按钮的作物图片
+func _update_button_crop_image(button: Button, crop_name: String):
+ """
+ 更新按钮中的作物图片
+ """
+ # 检查按钮是否有CropImage节点
+ var crop_image = button.get_node_or_null("CropImage")
+ if not crop_image:
+ print("背包按钮没有找到CropImage节点:", button.name)
+ return
+
+ # 获取作物的最后一帧图片
+ var texture = _get_crop_final_texture(crop_name)
+
+ if texture:
+ # CropImage是Sprite2D,直接设置texture属性
+ crop_image.texture = texture
+ crop_image.visible = true
+ print("背包更新作物图片:", crop_name)
+ else:
+ crop_image.visible = false
+ print("背包无法获取作物图片:", crop_name)
diff --git a/GUI/player_bag_panel.gd.uid b/GUI/player_bag_panel.gd.uid
new file mode 100644
index 0000000..7208216
--- /dev/null
+++ b/GUI/player_bag_panel.gd.uid
@@ -0,0 +1 @@
+uid://cgr332wsx63a8
diff --git a/GUI/player_ranking_item.tscn b/GUI/player_ranking_item.tscn
new file mode 100644
index 0000000..28e5cb4
--- /dev/null
+++ b/GUI/player_ranking_item.tscn
@@ -0,0 +1,71 @@
+[gd_scene load_steps=3 format=3 uid="uid://crd28qnymob7"]
+
+[ext_resource type="Texture2D" uid="uid://c3vng0nal1wr8" path="res://assets/Test/g.png" id="1_sgoxp"]
+[ext_resource type="Script" uid="uid://0d2j5m6j2ema" path="res://Components/HTTPTextureRect.gd" id="2_ky0k8"]
+
+[node name="player_ranking_item" type="VBoxContainer"]
+offset_right = 1152.0
+offset_bottom = 82.0
+
+[node name="HBox" type="HBoxContainer" parent="."]
+layout_mode = 2
+
+[node name="SerialNumber" type="Label" parent="HBox"]
+layout_mode = 2
+theme_override_font_sizes/font_size = 30
+text = "1."
+
+[node name="PlayerAvatar" type="TextureRect" parent="HBox"]
+layout_mode = 2
+texture = ExtResource("1_sgoxp")
+expand_mode = 3
+script = ExtResource("2_ky0k8")
+metadata/_custom_type_script = "uid://0d2j5m6j2ema"
+
+[node name="PlayerName" type="Label" parent="HBox"]
+layout_mode = 2
+size_flags_horizontal = 3
+theme_override_font_sizes/font_size = 30
+text = "树萌芽"
+
+[node name="PlayerMoney" type="Label" parent="HBox"]
+modulate = Color(1, 1, 0, 1)
+layout_mode = 2
+size_flags_horizontal = 3
+theme_override_font_sizes/font_size = 30
+text = "钱币:999"
+
+[node name="SeedNum" type="Label" parent="HBox"]
+modulate = Color(0, 1, 0, 1)
+layout_mode = 2
+size_flags_horizontal = 3
+theme_override_font_sizes/font_size = 30
+text = "种子数:999"
+
+[node name="PlayerLevel" type="Label" parent="HBox"]
+modulate = Color(0, 1, 1, 1)
+layout_mode = 2
+size_flags_horizontal = 3
+theme_override_font_sizes/font_size = 30
+text = "等级:999"
+
+[node name="VisitButton" type="Button" parent="HBox"]
+layout_mode = 2
+size_flags_horizontal = 3
+theme_override_font_sizes/font_size = 30
+text = "访问"
+
+[node name="HBox2" type="HBoxContainer" parent="."]
+layout_mode = 2
+
+[node name="LastLoginTime" type="Label" parent="HBox2"]
+layout_mode = 2
+size_flags_horizontal = 3
+theme_override_font_sizes/font_size = 20
+text = "最后在线:2025年12时09分35秒"
+
+[node name="OnlineTime" type="Label" parent="HBox2"]
+layout_mode = 2
+size_flags_horizontal = 3
+theme_override_font_sizes/font_size = 20
+text = "累计在线时长:99时60分60秒"
diff --git a/GUI/player_ranking_panel.gd b/GUI/player_ranking_panel.gd
new file mode 100644
index 0000000..2f8822a
--- /dev/null
+++ b/GUI/player_ranking_panel.gd
@@ -0,0 +1,110 @@
+extends Panel
+
+@onready var player_ranking_list : VBoxContainer = $Scroll/PlayerList
+@onready var refresh_button : Button = $RefreshButton
+@onready var quit_button : Button = $QuitButton
+
+#预添加常用的面板
+@onready var main_game = get_node("/root/main")
+@onready var land_panel = get_node("/root/main/UI/LandPanel")
+@onready var crop_store_panel = get_node("/root/main/UI/PlayerBagPanel")
+@onready var player_ranking_panel = get_node("/root/main/UI/PlayerRankingPanel")
+@onready var player_bag_panel = get_node("/root/main/UI/PlayerBagPanel")
+@onready var network_manager = get_node("/root/main/UI/TCPNetworkManager")
+
+#下面这是每个玩家要展示的信息,直接获取服务器玩家数据json文件来实现
+#模板用于复制创建新的玩家条目
+@onready var player_info_template : VBoxContainer = $Scroll/PlayerList/player_ranking_item
+
+func _ready() -> void:
+ # 隐藏模板
+ player_info_template.visible = false
+
+ # 连接按钮信号
+ refresh_button.pressed.connect(_on_refresh_button_pressed)
+ quit_button.pressed.connect(_on_quit_button_pressed)
+
+ # 初始加载排行榜
+ request_player_rankings()
+
+# 请求玩家排行榜数据
+func request_player_rankings():
+ if network_manager:
+ network_manager.sendGetPlayerRankings()
+
+# 处理玩家排行榜响应
+func handle_player_rankings_response(data):
+ # 检查响应是否成功
+ if not data.get("success", false):
+ print("获取玩家排行榜失败:", data.get("message", "未知错误"))
+ return
+
+ # 清除现有的玩家条目(除了模板)
+ for child in player_ranking_list.get_children():
+ if child != player_info_template:
+ child.queue_free()
+
+ # 添加玩家条目
+ var players = data.get("players", [])
+ for player_data in players:
+ add_player_entry(player_data)
+
+# 添加单个玩家条目
+func add_player_entry(player_data):
+ # 复制模板
+ var player_entry = player_info_template.duplicate()
+ player_entry.visible = true
+ player_ranking_list.add_child(player_entry)
+
+ # 设置玩家信息
+ var player_name = player_entry.get_node("HBox/PlayerName")
+ var player_level = player_entry.get_node("HBox/PlayerLevel")
+ var player_money = player_entry.get_node("HBox/PlayerMoney")
+ var player_seed_num = player_entry.get_node("HBox/SeedNum")
+ var player_online_time = player_entry.get_node("HBox2/OnlineTime")
+ var player_last_login_time = player_entry.get_node("HBox2/LastLoginTime")
+ var player_avatar = player_entry.get_node("HBox/PlayerAvatar")
+ var visit_button = player_entry.get_node("HBox/VisitButton")
+
+ # 填充数据
+ var username = player_data.get("user_name", "未知")
+ var display_name = player_data.get("player_name", username)
+ player_name.text = display_name
+ player_level.text = "等级: " + str(player_data.get("level", 0))
+ player_money.text = "金币: " + str(player_data.get("money", 0))
+ player_seed_num.text = "种子: " + str(player_data.get("seed_count", 0))
+ player_online_time.text = "游玩时间: " + player_data.get("total_login_time", "0时0分0秒")
+ player_last_login_time.text = "最后登录: " + player_data.get("last_login_time", "未知")
+
+ # 尝试加载玩家头像(使用用户名/QQ号加载头像,而不是显示名)
+ if username.is_valid_int():
+ player_avatar.load_from_url("http://q1.qlogo.cn/g?b=qq&nk=" + username + "&s=100")
+
+ # 设置访问按钮
+ visit_button.pressed.connect(func(): _on_visit_player_pressed(username))
+
+# 访问玩家按钮点击
+func _on_visit_player_pressed(username):
+ print("访问玩家:", username)
+
+ # 发送访问玩家请求
+ if network_manager and network_manager.has_method("sendVisitPlayer"):
+ var success = network_manager.sendVisitPlayer(username)
+ if success:
+ print("已发送访问玩家请求:", username)
+ else:
+ print("发送访问玩家请求失败,网络未连接")
+ else:
+ print("网络管理器不可用")
+
+# 刷新按钮点击
+func _on_refresh_button_pressed():
+ request_player_rankings()
+
+# 退出按钮点击
+func _on_quit_button_pressed():
+ self.hide()
+
+# 添加到main.gd中调用
+func _handle_player_rankings_response(data):
+ handle_player_rankings_response(data)
diff --git a/GUI/player_ranking_panel.gd.uid b/GUI/player_ranking_panel.gd.uid
new file mode 100644
index 0000000..2b4de47
--- /dev/null
+++ b/GUI/player_ranking_panel.gd.uid
@@ -0,0 +1 @@
+uid://fk4q3x6uqydd
diff --git a/GlobalScript/GlobalFunctions.gd b/GlobalScript/GlobalFunctions.gd
new file mode 100644
index 0000000..81e7383
--- /dev/null
+++ b/GlobalScript/GlobalFunctions.gd
@@ -0,0 +1,76 @@
+extends Node
+
+# 全局通用功能脚本
+# 使用方法:首先在项目设置的自动加载中添加此脚本,然后在任何地方使用 GlobalFunctions.函数名() 调用
+
+func _ready():
+ print("全局函数库已加载")
+
+# 写入 TXT 文件
+func write_txt_file(file_path: String, text: String, append: bool = false) -> void:
+ var file
+ if append == true:
+ file = FileAccess.open(file_path, FileAccess.READ_WRITE) # 追加模式
+ if file:
+ file.seek_end() # 移动光标到文件末尾
+ else:
+ file = FileAccess.open(file_path, FileAccess.WRITE) # 覆盖模式
+ if file:
+ file.store_string(text)
+ file.close()
+ if has_node("/root/ToastScript"):
+ get_node("/root/ToastScript").show("游戏已保存!", Color.GREEN, 5.0, 1.0)
+ else:
+ print("写入文件时打开失败: ", file_path)
+ if has_node("/root/ToastScript"):
+ get_node("/root/ToastScript").show("写入文件时打开失败!", Color.RED, 5.0, 1.0)
+
+
+# 读取 TXT 文件
+func read_txt_file(file_path: String) -> String:
+ var file = FileAccess.open(file_path, FileAccess.READ)
+ if file:
+ var text = file.get_as_text()
+ file.close()
+ return text
+ else:
+ print("打开文件失败: ", file_path)
+ return "false"
+
+
+#生成随机数-用于作物随机死亡
+func random_probability(probability: float) -> bool:
+ # 确保传入的概率值在 0 到 1 之间
+ if probability*0.001 < 0.0 or probability*0.001 > 1.0:
+ print("概率值必须在 0 和 1 之间")
+ return false
+
+ # 生成一个 0 到 1 之间的随机数
+ var random_value = randf()
+
+ # 如果随机数小于等于概率值,则返回 true
+ return random_value <= (probability*0.001)
+
+
+# 格式化时间为可读字符串
+func format_time(seconds: int) -> String:
+ var minutes = seconds / 60
+ seconds = seconds % 60
+ var hours = minutes / 60
+ minutes = minutes % 60
+
+ if hours > 0:
+ return "%02d:%02d:%02d" % [hours, minutes, seconds]
+ else:
+ return "%02d:%02d" % [minutes, seconds]
+
+
+#双击切换UI事件-比如按一下打开再按一下关闭
+func double_click_close(node):
+ if node.visible == false:
+ node.show()
+ pass
+ else :
+ node.hide()
+ pass
+ pass
diff --git a/GlobalScript/GlobalFunctions.gd.uid b/GlobalScript/GlobalFunctions.gd.uid
new file mode 100644
index 0000000..406a45a
--- /dev/null
+++ b/GlobalScript/GlobalFunctions.gd.uid
@@ -0,0 +1 @@
+uid://bv4lf4v2c73pb
diff --git a/test.gd b/GlobalScript/GlobalVariables.gd
similarity index 100%
rename from test.gd
rename to GlobalScript/GlobalVariables.gd
diff --git a/GlobalScript/GlobalVariables.gd.uid b/GlobalScript/GlobalVariables.gd.uid
new file mode 100644
index 0000000..0607ecd
--- /dev/null
+++ b/GlobalScript/GlobalVariables.gd.uid
@@ -0,0 +1 @@
+uid://co5rk48low4kq
diff --git a/components/toast.gd b/GlobalScript/Toast.gd
similarity index 100%
rename from components/toast.gd
rename to GlobalScript/Toast.gd
diff --git a/GlobalScript/Toast.gd.uid b/GlobalScript/Toast.gd.uid
new file mode 100644
index 0000000..bd9629a
--- /dev/null
+++ b/GlobalScript/Toast.gd.uid
@@ -0,0 +1 @@
+uid://336lik63ehtt
diff --git a/components/toast.tscn b/GlobalScript/Toast.tscn
similarity index 55%
rename from components/toast.tscn
rename to GlobalScript/Toast.tscn
index c494d4b..a15a029 100644
--- a/components/toast.tscn
+++ b/GlobalScript/Toast.tscn
@@ -1,6 +1,6 @@
[gd_scene load_steps=2 format=3 uid="uid://cvip7owyfmqav"]
-[ext_resource type="Script" path="res://components/toast.gd" id="1_rdgmi"]
+[ext_resource type="Script" uid="uid://336lik63ehtt" path="res://Components/Toast.gd" id="1_rdgmi"]
[node name="Toast" type="Node"]
script = ExtResource("1_rdgmi")
diff --git a/MainGame.gd b/MainGame.gd
index 8131af6..834bf88 100644
--- a/MainGame.gd
+++ b/MainGame.gd
@@ -1,254 +1,346 @@
extends Node
# 变量定义
-@onready var grid_container = $GridContainer # 农场地块的 GridContainer
-@onready var crop_item = $CropItem
-@onready var crop_list = $CropList # 作物选择的 ItemList
-
-@onready var show_money = $GUI/money # 显示当前剩余的钱
-@onready var show_experience = $GUI/experience # 显示当前玩家的经验
-@onready var show_level = $GUI/level # 显示当前玩家的等级
-@onready var tip = $GUI/tip #显示保存相关
+@onready var grid_container : GridContainer = $GridContainer # 农场地块的 GridContainer
+@onready var crop_item : Button = $CopyNodes/CropItem
-@onready var land_panel = $GUI/Land_Panel
-@onready var dig_button = $GUI/Land_Panel/VBox/HBox/Dig_button
-@onready var crop_grid_container = $ScrollContainer/Crop_GridContainer
+@onready var show_money : Label = $UI/GUI/HBox/money # 显示当前剩余的钱
+@onready var show_experience : Label = $UI/GUI/HBox/experience # 显示当前玩家的经验
+@onready var show_level : Label = $UI/GUI/HBox/level # 显示当前玩家的等级
+@onready var show_tip : Label = $UI/GUI/HBox/tip # 显示小提示
+@onready var show_player_name : Label = $UI/GUI/HBox2/player_name # 显示玩家昵称
+@onready var show_farm_name : Label = $UI/GUI/HBox2/farm_name # 显示农场名称
+@onready var show_status_label : Label = $UI/GUI/HBox2/StatusLabel # 显示与服务器连接状态
-@onready var green_bar = $Copy_Nodes/Green #普通
-@onready var white_blue_bar = $Copy_Nodes/White_Blue #稀有
-@onready var orange_bar = $Copy_Nodes/Orange #优良
-@onready var pink_bar = $Copy_Nodes/Pink #史诗
-@onready var black_blue_bar = $Copy_Nodes/Black_Blue #传奇
-@onready var red_bar = $Copy_Nodes/Red #神圣
+@onready var network_status_label :Label = get_node("/root/main/UI/TCPNetworkManager/StatusLabel")
+@onready var network_manager = get_node("/root/main/UI/TCPNetworkManager")
-#----------------网络联机部分--------------------------
-#用户登录账号,用QQ号代替
-@onready var username_input = $GUI/LoginPanel/VBox/HBox/username_input
-#用户登录密码
-@onready var password_input = $GUI/LoginPanel/VBox/HBox2/password_input
-#注册账号时二次确认密码
-@onready var password_input_2 = $GUI/LoginPanel/VBox/HBox5/password_input2
-#登录按钮
-@onready var login_button = $GUI/LoginPanel/VBox/HBox4/login_button
-#注册按钮
-@onready var register_button = $GUI/LoginPanel/VBox/HBox4/register_button
-#农场名称
-@onready var farmname_input = $GUI/LoginPanel/VBox/HBox3/farmname_input
-#登录注册面板
-@onready var login_panel = $GUI/LoginPanel
-#----------------网络联机部分--------------------------
+#种子商店格子
+@onready var crop_grid_container : GridContainer = $UI/CropStorePanel/ScrollContainer/Crop_Grid
+#玩家背包格子
+@onready var player_bag_grid_container : GridContainer = $UI/PlayerBagPanel/ScrollContainer/Bag_Grid
+#作物品质按钮
+@onready var green_bar : Button = $CopyNodes/GreenCrop #普通
+@onready var white_blue_bar : Button = $CopyNodes/WhiteBlueCrop #稀有
+@onready var orange_bar : Button = $CopyNodes/OrangeCrop #优良
+@onready var pink_bar : Button = $CopyNodes/PinkCrop #史诗
+@onready var black_blue_bar : Button = $CopyNodes/BlackBlueCrop #传奇
+@onready var red_bar : Button = $CopyNodes/RedCrop #神圣
+#各种面板
+@onready var land_panel : Panel = $UI/LandPanel#地块面板
+@onready var login_panel : PanelContainer = $UI/LoginPanel#登录注册面板
+@onready var crop_store_panel : Panel = $UI/CropStorePanel#种子商店面板
+@onready var player_bag_panel : Panel = $UI/PlayerBagPanel#玩家背包面板
+@onready var TCPNerworkManager : Panel = $UI/TCPNetworkManager#网络管理器
+@onready var player_ranking_panel : Panel = $UI/PlayerRankingPanel#玩家排行榜面板
-@onready var http_request = $HTTPRequest
+@onready var return_my_farm_button: Button = $UI/GUI/VBox/ReturnMyFarmButton
var money: int = 500 # 默认每个人初始为100元
var experience: float = 0.0 # 初始每个玩家的经验为0
var grow_speed: float = 1 # 作物生长速度
var level: int = 1 # 初始玩家等级为1
-var farm_lots = [] # 用于保存每个地块的状态
-
-var dig_index = 0
-var dig_money = 1000
-var climate_death_timer = 0
-
-var blink_speed: float = 1 # 每秒闪烁的次数
-var is_blink_on: bool = false # 是否闪烁状态
-var blink_counter: float = 0.0 # 计数器,用于控制闪烁
+var dig_money : int = 1000 #开垦费用
-#农作物种类JSON
-var can_planted_crop = {
- #玩家点击空地块时可以种植的作物
- #品质有 普通,优良,稀有,史诗,传奇,品质会影响作物的颜色
- #耐候性:种植的过程中可能会死亡
- #等级:需要玩家达到相应等级才能种植
- #经验:收获时可以获得的经验,经验到达某一程度,玩家会升等级
- #基础作物
- # 基础作物
- "测试作物": {"花费": 1, "生长时间": 3, "收益": 9999, "品质": "普通", "描述": "测试作物", "耐候性": 10, "等级": 1, "经验": 999}, # 1分钟
-
- "小麦": {"花费": 120, "生长时间": 120, "收益": 100, "品质": "普通", "描述": "基础作物,品质较低,适合新手种植", "耐候性": 10, "等级": 1, "经验": 10}, # 1分钟
- "稻谷": {"花费": 100, "生长时间": 240, "收益": 120, "品质": "普通", "描述": "适合大规模种植的基础作物", "耐候性": 10, "等级": 1, "经验": 10}, # 2分钟
- "玉米": {"花费": 70, "生长时间": 600, "收益": 90, "品质": "普通", "描述": "营养丰富的优良作物,适合稍有经验的玩家", "耐候性": 15, "等级": 2, "经验": 15}, # 5分钟
- "土豆": {"花费": 75, "生长时间": 360, "收益": 90, "品质": "普通", "描述": "容易种植的耐寒作物", "耐候性": 12, "等级": 1, "经验": 10}, # 3分钟
- "胡萝卜": {"花费": 60, "生长时间": 480, "收益": 80, "品质": "普通", "描述": "适合新手的健康作物", "耐候性": 12, "等级": 1, "经验": 10}, # 4分钟
- # 中级作物
- "草莓": {"花费": 120, "生长时间": 960, "收益": 150, "品质": "优良", "描述": "营养丰富的果实,收益不错", "耐候性": 14, "等级": 2, "经验": 20}, # 8分钟
- "番茄": {"花费": 100, "生长时间": 720, "收益": 130, "品质": "优良", "描述": "常见作物,适合小规模种植", "耐候性": 12, "等级": 2, "经验": 15}, # 6分钟
- "大豆": {"花费": 90, "生长时间": 840, "收益": 110, "品质": "优良", "描述": "富含蛋白质的基础作物", "耐候性": 11, "等级": 2, "经验": 12}, # 7分钟
- # 高级作物
- "蓝莓": {"花费": 150, "生长时间": 1200, "收益": 200, "品质": "稀有", "描述": "较为稀有的作物,市场价值较高", "耐候性": 18, "等级": 3, "经验": 25}, # 10分钟
- "洋葱": {"花费": 85, "生长时间": 600, "收益": 105, "品质": "稀有", "描述": "烹饪常用的作物,适合中级种植", "耐候性": 10, "等级": 2, "经验": 10}, # 5分钟
- "南瓜": {"花费": 180, "生长时间": 1440, "收益": 250, "品质": "稀有", "描述": "秋季收获的高收益作物", "耐候性": 20, "等级": 4, "经验": 30}, # 12分钟
- "葡萄": {"花费": 200, "生长时间": 1200, "收益": 300, "品质": "稀有", "描述": "需要特殊管理的高收益作物", "耐候性": 15, "等级": 4, "经验": 35}, # 10分钟
- "柿子": {"花费": 160, "生长时间": 1080, "收益": 240, "品质": "稀有", "描述": "富含营养的秋季作物", "耐候性": 18, "等级": 3, "经验": 28}, # 9分钟
- "花椰菜": {"花费": 130, "生长时间": 960, "收益": 170, "品质": "稀有", "描述": "耐寒的高品质作物,适合经验丰富的玩家", "耐候性": 17, "等级": 3, "经验": 22}, # 8分钟
- "芦笋": {"花费": 200, "生长时间": 1560, "收益": 280, "品质": "稀有", "描述": "市场需求量高的稀有作物", "耐候性": 15, "等级": 4, "经验": 30}, # 13分钟
- # 史诗作物
- "香草": {"花费": 250, "生长时间": 1800, "收益": 400, "品质": "史诗", "描述": "非常稀有且收益极高的作物", "耐候性": 22, "等级": 5, "经验": 40}, # 15分钟
- "西瓜": {"花费": 240, "生长时间": 2400, "收益": 420, "品质": "史诗", "描述": "夏季丰产的高价值作物", "耐候性": 21, "等级": 5, "经验": 45}, # 20分钟
- "甜菜": {"花费": 220, "生长时间": 2160, "收益": 350, "品质": "史诗", "描述": "营养丰富的根茎作物,收益较高", "耐候性": 20, "等级": 5, "经验": 38}, # 18分钟
- "甘蔗": {"花费": 260, "生长时间": 3000, "收益": 450, "品质": "史诗", "描述": "需要充足水源的高价值作物", "耐候性": 18, "等级": 5, "经验": 50}, # 25分钟
- # 传奇作物
- "龙果": {"花费": 400, "生长时间": 4800, "收益": 600, "品质": "传奇", "描述": "极为稀有的热带作物,产量和价值都极高", "耐候性": 25, "等级": 6, "经验": 60}, # 40分钟
- "松露": {"花费": 500, "生长时间": 7200, "收益": 700, "品质": "传奇", "描述": "极其珍贵的地下作物,市场价格极高", "耐候性": 23, "等级": 7, "经验": 80}, # 60分钟
- "人参": {"花费": 450, "生长时间": 6600, "收益": 650, "品质": "传奇", "描述": "需要耐心等待的珍贵药材", "耐候性": 22, "等级": 6, "经验": 75}, # 55分钟
- "金橘": {"花费": 420, "生长时间": 4800, "收益": 620, "品质": "传奇", "描述": "少见的耐寒果树,市场需求量极大", "耐候性": 26, "等级": 7, "经验": 70} # 40分钟
- };
-
-var selected_lot_index = -1 # 当前被选择的地块索引
-#电脑版本地游戏保存路径
-var game_path = "C:/Users/shumengya/Desktop/smyfarm/"
-var save_time = 10
-
+#临时变量
+var user_name : String = ""
+var user_password : String = ""
+var farmname : String = ""
+var login_data : Dictionary = {}
+var data : Dictionary = {}
+var buttons : Array = []
# 使用 _process 计时器实现作物生长机制
var update_timer: float = 0.0
var update_interval: float = 1.0
-var start_game = false
+var start_game : bool = false
+# 玩家背包数据
+var player_bag : Array = []
+#农作物种类JSON
+var can_planted_crop : Dictionary = {}
+# 当前被选择的地块索引
+var selected_lot_index : int = -1
+var farm_lots : Array = [] # 用于保存每个地块的状态
+var dig_index : int = 0
+var climate_death_timer : int = 0
-var user_name = ""
-var user_password = ""
-var farmname = ""
-var login_data = {}
+# 访问模式相关变量
+var is_visiting_mode : bool = false # 是否处于访问模式
+var original_player_data : Dictionary = {} # 保存原始玩家数据
+var visited_player_data : Dictionary = {} # 被访问玩家的数据
-var data = null
-
-var buttons = []
+# 作物图片缓存
+var crop_textures_cache : Dictionary = {} # 缓存已加载的作物图片
+var crop_frame_counts : Dictionary = {} # 记录每种作物的帧数
-
-
-
-
-##方法分类->Godot自带方法和自定义方法
#-------------Godot自带方法-----------------
+func _on_quit_button_pressed():
+ player_bag_panel.hide()
+ pass
+
+
# 准备阶段
func _ready():
_update_ui()
- _init_crop_list2()
- Toast.show("快去偷其他人的菜吧!", Color.GREEN,5.0,1.0)
- # 初始化农场地块
- _init_farm_lots(40)
- _update_farm_lots()
-
- crop_grid_container.hide()
+ _create_farm_buttons() # 创建地块按钮
+ _update_farm_lots_state() # 初始更新地块状态
+
+ # 预加载默认作物图片
+ _preload_common_crop_textures()
+
+ # 先尝试加载本地数据进行快速初始化
+ _load_local_crop_data()
+
+ # 初始化玩家背包UI
+ player_bag_panel.init_player_bag()
+ # 初始化商店
+ crop_store_panel.init_store()
+
+ # 隐藏面板
+ crop_store_panel.hide()
+ player_bag_panel.hide()
+
+ # 启动后稍等片刻尝试从服务器获取最新数据
+ var timer = get_tree().create_timer(0.5)
+ await timer.timeout
+ _try_load_from_server()
+#每时每刻都更新
func _physics_process(delta):
+ #1秒计时器
update_timer += delta
-
if update_timer >= update_interval:
update_timer = 0.0 # 重置计时器
+ #同步网络管理器的状态
+ show_status_label.text = network_status_label.text
+ show_status_label.modulate = network_status_label.modulate
+
if start_game == true:
- _update_save_time()
- _update_farm_lots()
+ _update_farm_lots_state() # 更新地块状态,不重新创建UI
+
+ #访客模式处理
+ if is_visiting_mode:
+ return_my_farm_button.show()
+ pass
+ else:
+ return_my_farm_button.hide()
+ pass
pass
-
- for i in range(len(farm_lots)):
- var lot = farm_lots[i]
- if lot["is_planted"]:
- lot["grow_time"] += grow_speed * update_interval
- _update_blinking(lot)
-func _on_dig_button_pressed():
- if money < dig_money:
- print("金钱不足,无法开垦" )
- Toast.show("金钱不足,无法开垦", Color.RED)
+# 处理服务器作物更新消息
+func _handle_crop_update(update_data):
+ # 检查是否是访问模式的更新
+ var is_visiting_update = update_data.get("is_visiting", false)
+ var visited_player = update_data.get("visited_player", "")
+
+ if is_visiting_update and is_visiting_mode:
+ # 访问模式下的更新,更新被访问玩家的农场数据
+ farm_lots = update_data["farm_lots"]
+ print("收到访问模式下的作物更新,被访问玩家:", visited_player)
+ elif not is_visiting_update and not is_visiting_mode:
+ # 正常模式下的更新,更新自己的农场数据
+ farm_lots = update_data["farm_lots"]
+ print("收到自己农场的作物更新")
else:
- money -= dig_money
- farm_lots[dig_index]["is_diged"] = true
- land_panel.hide()
- _update_ui()
- _update_farm_lots()
- pass
-
-# 添加按键触发保存和加载的功能
-func _input(event):
- if event.is_action_pressed("ui_save"): # 需要在输入设置中定义这个动作
- _save_game()
- elif event.is_action_pressed("ui_load"): # 需要在输入设置中定义这个动作
- _load_game()
-
-#这里处理登录逻辑,如果用户没有账号,直接注册一个新的
-func _on_login_button_pressed():
-
- user_name = username_input.text.strip_edges() # 修剪前后的空格
- user_password = password_input.text.strip_edges()
- farmname = farmname_input.text.strip_edges()
-
- login_data = {
- "user_name": user_name,
- "user_password": user_password
- }
-
- if user_name == "" or user_password == "":
- print("用户名或密码不能为空!")
- return
-
- send_request("login", HTTPClient.METHOD_POST, login_data)
-
-func _on_register_button_pressed():
- user_name = username_input.text.strip_edges()
- user_password = password_input.text.strip_edges()
-
- var user_password_2 = password_input_2.text.strip_edges()
- farmname = farmname_input.text.strip_edges()
- #压缩后成一坨大便了
- var init_player_data = {"experience":0,"farm_lots":[{"crop_type":"","grow_time":0,"is_dead":false,"is_diged":true,"is_planted":false,"max_grow_time":3},{"crop_type":"","grow_time":0,"is_dead":false,"is_diged":true,"is_planted":false,"max_grow_time":3},{"crop_type":"","grow_time":0,"is_dead":false,"is_diged":true,"is_planted":false,"max_grow_time":3},{"crop_type":"","grow_time":0,"is_dead":false,"is_diged":true,"is_planted":false,"max_grow_time":3},{"crop_type":"","grow_time":0,"is_dead":false,"is_diged":true,"is_planted":false,"max_grow_time":3},{"crop_type":"","grow_time":0,"is_dead":false,"is_diged":false,"is_planted":false,"max_grow_time":5},{"crop_type":"","grow_time":0,"is_dead":false,"is_diged":false,"is_planted":false,"max_grow_time":5},{"crop_type":"","grow_time":0,"is_dead":false,"is_diged":false,"is_planted":false,"max_grow_time":5},{"crop_type":"","grow_time":0,"is_dead":false,"is_diged":false,"is_planted":false,"max_grow_time":5},{"crop_type":"","grow_time":0,"is_dead":false,"is_diged":false,"is_planted":false,"max_grow_time":5},{"crop_type":"","grow_time":0,"is_dead":false,"is_diged":false,"is_planted":false,"max_grow_time":5},{"crop_type":"","grow_time":0,"is_dead":false,"is_diged":false,"is_planted":false,"max_grow_time":5},{"crop_type":"","grow_time":0,"is_dead":false,"is_diged":false,"is_planted":false,"max_grow_time":5},{"crop_type":"","grow_time":0,"is_dead":false,"is_diged":false,"is_planted":false,"max_grow_time":5},{"crop_type":"","grow_time":0,"is_dead":false,"is_diged":false,"is_planted":false,"max_grow_time":5},{"crop_type":"","grow_time":0,"is_dead":false,"is_diged":false,"is_planted":false,"max_grow_time":5},{"crop_type":"","grow_time":0,"is_dead":false,"is_diged":false,"is_planted":false,"max_grow_time":5},{"crop_type":"","grow_time":0,"is_dead":false,"is_diged":false,"is_planted":false,"max_grow_time":5},{"crop_type":"","grow_time":0,"is_dead":false,"is_diged":false,"is_planted":false,"max_grow_time":5},{"crop_type":"","grow_time":0,"is_dead":false,"is_diged":false,"is_planted":false,"max_grow_time":5},{"crop_type":"","grow_time":0,"is_dead":false,"is_diged":false,"is_planted":false,"max_grow_time":5},{"crop_type":"","grow_time":0,"is_dead":false,"is_diged":false,"is_planted":false,"max_grow_time":5},{"crop_type":"","grow_time":0,"is_dead":false,"is_diged":false,"is_planted":false,"max_grow_time":5},{"crop_type":"","grow_time":0,"is_dead":false,"is_diged":false,"is_planted":false,"max_grow_time":5},{"crop_type":"","grow_time":0,"is_dead":false,"is_diged":false,"is_planted":false,"max_grow_time":5},{"crop_type":"","grow_time":0,"is_dead":false,"is_diged":false,"is_planted":false,"max_grow_time":5},{"crop_type":"","grow_time":0,"is_dead":false,"is_diged":false,"is_planted":false,"max_grow_time":5},{"crop_type":"","grow_time":0,"is_dead":false,"is_diged":false,"is_planted":false,"max_grow_time":5},{"crop_type":"","grow_time":0,"is_dead":false,"is_diged":false,"is_planted":false,"max_grow_time":5},{"crop_type":"","grow_time":0,"is_dead":false,"is_diged":false,"is_planted":false,"max_grow_time":5},{"crop_type":"","grow_time":0,"is_dead":false,"is_diged":false,"is_planted":false,"max_grow_time":5},{"crop_type":"","grow_time":0,"is_dead":false,"is_diged":false,"is_planted":false,"max_grow_time":5},{"crop_type":"","grow_time":0,"is_dead":false,"is_diged":false,"is_planted":false,"max_grow_time":5},{"crop_type":"","grow_time":0,"is_dead":false,"is_diged":false,"is_planted":false,"max_grow_time":5},{"crop_type":"","grow_time":0,"is_dead":false,"is_diged":false,"is_planted":false,"max_grow_time":5},{"crop_type":"","grow_time":0,"is_dead":false,"is_diged":true,"is_planted":false,"max_grow_time":5},{"crop_type":"","grow_time":0,"is_dead":false,"is_diged":true,"is_planted":false,"max_grow_time":5},{"crop_type":"","grow_time":0,"is_dead":false,"is_diged":true,"is_planted":false,"max_grow_time":5},{"crop_type":"","grow_time":0,"is_dead":false,"is_diged":true,"is_planted":false,"max_grow_time":5},{"crop_type":"","grow_time":0,"is_dead":false,"is_diged":true,"is_planted":false,"max_grow_time":5}],"farm_name":farmname,"level":0,"money":1000,"user_name":user_name,"user_password":user_password}
-
- if user_name == "" or user_password == "":
- print("用户名或密码不能为空!")
- return
- if farmname == "":
- print("农场名称不能为空!")
- return
- if user_password != user_password_2:
- print("前后密码不相同!")
- return
-
- if is_valid_qq_number(user_name) == false:
+ # 状态不匹配,忽略更新
+ print("忽略不匹配的作物更新,当前访问模式:", is_visiting_mode, ",更新类型:", is_visiting_update)
return
+
+ # 更新UI显示
+ _update_farm_lots_state()
+
+
+# 处理玩家动作到服务端响应消息
+func _handle_action_response(response_data):
+ var action_type = response_data.get("action_type", "")
+ var success = response_data.get("success", false)
+ var message = response_data.get("message", "")
+ var updated_data = response_data.get("updated_data", {})
+
+ match action_type:
+ "harvest_crop":
+ if success:
+ # 更新玩家数据
+ if updated_data.has("money"):
+ money = updated_data["money"]
+ if updated_data.has("experience"):
+ experience = updated_data["experience"]
+ if updated_data.has("level"):
+ level = updated_data["level"]
+
+ # 更新UI
+ _update_ui()
+ Toast.show(message, Color.GREEN)
+ else:
+ Toast.show(message, Color.RED)
+
+ "plant_crop":
+ if success:
+ # 更新玩家背包
+ if updated_data.has("player_bag"):
+ player_bag = updated_data["player_bag"]
+
+ # 更新玩家背包UI
+ player_bag_panel.update_player_bag_ui()
+ Toast.show(message, Color.GREEN)
+ else:
+ Toast.show(message, Color.RED)
+
+ "buy_seed":
+ if success:
+ # 更新玩家数据
+ if updated_data.has("money"):
+ money = updated_data["money"]
+ if updated_data.has("player_bag"):
+ player_bag = updated_data["player_bag"]
+
+ # 更新UI
+ _update_ui()
+ player_bag_panel.update_player_bag_ui()
+ Toast.show(message, Color.GREEN)
+ else:
+ Toast.show(message, Color.RED)
+
+ "dig_ground":
+ if success:
+ # 更新玩家数据
+ if updated_data.has("money"):
+ money = updated_data["money"]
+ if updated_data.has("farm_lots"):
+ farm_lots = updated_data["farm_lots"]
+
+ # 更新UI
+ _update_ui()
+ _update_farm_lots_state()
+ Toast.show(message, Color.GREEN)
+ else:
+ Toast.show(message, Color.RED)
+
+# 处理玩家排行榜响应
+func _handle_player_rankings_response(data):
+ if player_ranking_panel and player_ranking_panel.has_method("_handle_player_rankings_response"):
+ player_ranking_panel._handle_player_rankings_response(data)
+
+# 处理玩家游玩时间响应
+func _handle_play_time_response(data):
+ # 如果需要在主游戏中处理游玩时间,可以在这里添加代码
+ # 目前只是将响应转发给排行榜面板
+ if player_ranking_panel and player_ranking_panel.has_method("handle_play_time_response"):
+ player_ranking_panel.handle_play_time_response(data)
+
+# 处理访问玩家响应
+func _handle_visit_player_response(data):
+ var success = data.get("success", false)
+ var message = data.get("message", "")
+
+ if success:
+ var target_player_data = data.get("player_data", {})
- send_request("register", HTTPClient.METHOD_POST, init_player_data)
- pass
+ # 保存当前玩家数据
+ if not is_visiting_mode:
+ original_player_data = {
+ "user_name": user_name,
+ "player_name": show_player_name.text.replace("玩家昵称:", ""),
+ "farm_name": show_farm_name.text.replace("农场名称:", ""),
+ "level": level,
+ "money": money,
+ "experience": experience,
+ "farm_lots": farm_lots.duplicate(true),
+ "player_bag": player_bag.duplicate(true)
+ }
+
+ # 切换到访问模式
+ is_visiting_mode = true
+ visited_player_data = target_player_data
+
+ # 更新显示数据
+ money = target_player_data.get("money", 0)
+ experience = target_player_data.get("experience", 0)
+ level = target_player_data.get("level", 1)
+ farm_lots = target_player_data.get("farm_lots", [])
+ player_bag = target_player_data.get("player_bag", [])
+
+ # 更新UI显示
+ show_player_name.text = "玩家昵称:" + target_player_data.get("player_name", "未知")
+ show_farm_name.text = "农场名称:" + target_player_data.get("farm_name", "未知农场")
+ show_tip.text = "访问模式"
+ show_tip.modulate = Color.ORANGE
+
+ _update_ui()
+
+ # 重新创建地块按钮以显示被访问玩家的农场
+ _create_farm_buttons()
+ _update_farm_lots_state()
+
+ # 更新背包UI
+ if player_bag_panel and player_bag_panel.has_method("update_player_bag_ui"):
+ player_bag_panel.update_player_bag_ui()
+
+ # 隐藏排行榜面板
+ if player_ranking_panel:
+ player_ranking_panel.hide()
+
+ Toast.show("正在访问 " + target_player_data.get("player_name", "未知") + " 的农场", Color.CYAN)
+ print("成功进入访问模式,访问玩家:", target_player_data.get("player_name", "未知"))
+ else:
+ Toast.show("访问失败:" + message, Color.RED)
+ print("访问玩家失败:", message)
+
+# 处理返回自己农场响应
+func _handle_return_my_farm_response(data):
+ var success = data.get("success", false)
+ var message = data.get("message", "")
+
+ if success:
+ var player_data = data.get("player_data", {})
+
+ # 恢复玩家数据
+ money = player_data.get("money", 500)
+ experience = player_data.get("experience", 0)
+ level = player_data.get("level", 1)
+ farm_lots = player_data.get("farm_lots", [])
+ player_bag = player_data.get("player_bag", [])
+
+ # 恢复UI显示
+ show_player_name.text = "玩家昵称:" + player_data.get("player_name", "未知")
+ show_farm_name.text = "农场名称:" + player_data.get("farm_name", "我的农场")
+ show_tip.text = "欢迎回到自己的农场"
+ show_tip.modulate = Color.WHITE
+
+ # 退出访问模式
+ is_visiting_mode = false
+ visited_player_data.clear()
+ original_player_data.clear()
+
+ # 更新UI
+ _update_ui()
+
+ # 重新创建地块按钮以显示自己的农场
+ _create_farm_buttons()
+ _update_farm_lots_state()
+
+ # 更新背包UI
+ if player_bag_panel and player_bag_panel.has_method("update_player_bag_ui"):
+ player_bag_panel.update_player_bag_ui()
+
+ Toast.show("已返回自己的农场", Color.GREEN)
+ print("成功返回自己的农场")
+ else:
+ Toast.show("返回农场失败:" + message, Color.RED)
+ print("返回农场失败:", message)
#-------------Godot自带方法-----------------
#-------------自定义方法-----------------
-# 保存玩家数据到node.js后端
-func save_game_to_server():
- var player_data = {
- "user_name":user_name,
- "user_password":user_password,
- "farm_name":farmname,
- "money": money,
- "experience": experience,
- "level": level,
- "farm_lots": farm_lots
- }
-
- send_request("save", HTTPClient.METHOD_POST, player_data)
- pass
-
-# 加载玩家数据从node.js后端
-func load_game_from_server():
- send_request("login", HTTPClient.METHOD_POST, login_data)
- pass
-
-#更新保存玩家数据的时间倒计时
-func _update_save_time():
- tip.text = "游戏自动保存剩余【"+str(save_time)+"】秒"
- save_time -= 1
- if save_time < 0:
- _save_game()
- save_time = 10
- pass
- pass
+#创建作物按钮
func _create_crop_button(crop_name: String, crop_quality: String) -> Button:
# 根据品质选择相应的进度条
var button = null
@@ -256,158 +348,90 @@ func _create_crop_button(crop_name: String, crop_quality: String) -> Button:
"普通":
button = green_bar.duplicate()
"优良":
- button = white_blue_bar.duplicate()
- "稀有":
button = orange_bar.duplicate()
+ "稀有":
+ button = white_blue_bar.duplicate()
"史诗":
button = pink_bar.duplicate()
"传奇":
button = black_blue_bar.duplicate()
+ _: # 默认情况
+ button = green_bar.duplicate()
- # 添加按钮事件
- button.connect("pressed", Callable(self, "_on_crop_selected").bind(crop_name))
- button.text = str(crop_name)
+ # 确保按钮可见并可点击
+ button.visible = true
+ button.disabled = false
+ button.focus_mode = Control.FOCUS_ALL
+
+ # 设置按钮文本
+ button.text = str(crop_quality + "-" + crop_name)
+
+ # 如果按钮有标题标签,设置标题
+ if button.has_node("Title"):
+ button.get_node("Title").text = crop_quality
+
return button
-#地块闪烁代码-已废弃
-func _update_blinking(lot: Dictionary):
- if lot["grow_time"] >= lot["max_grow_time"]:
- lot["grow_time"] = lot["max_grow_time"]
- blink_counter += blink_speed * update_interval
- is_blink_on = int(blink_counter) % 2 == 0
- else:
- is_blink_on = false
- blink_counter = 0.0
-
-# 写入 TXT 文件
-func write_txt_file(file_path: String, text: String, append: bool = false) -> void:
- var file
- if append == true:
- file = FileAccess.open(file_path, FileAccess.READ_WRITE) # 追加模式
- if file:
- file.seek_end() # 移动光标到文件末尾
- else:
- file = FileAccess.open(file_path, FileAccess.WRITE) # 覆盖模式
- if file:
- file.store_string(text)
- file.close()
- Toast.show("游戏已保存!", Color.GREEN)
- else:
- print("写入文件时打开失败: ", file_path)
- Toast.show("写入文件时打开失败!", Color.RED)
-
-# 读取 TXT 文件
-func read_txt_file(file_path: String) -> String:
- var file = FileAccess.open(file_path, FileAccess.READ)
- if file:
- var text = file.get_as_text()
- file.close()
- return text
- else:
- print("打开文件失败: ", file_path)
- return "false"
-
-#生成随机数-用于作物随机死亡
-func random_probability(probability: float) -> bool:
- # 确保传入的概率值在 0 到 1 之间
- if probability*0.001 < 0.0 or probability*0.001 > 1.0:
- print("概率值必须在 0 和 1 之间")
- return false
+# 打开商店按钮处理函数
+func _on_open_store_button_pressed():
+ # 如果处于访问模式,不允许打开商店
+ if is_visiting_mode:
+ Toast.show("访问模式下无法使用商店", Color.ORANGE)
+ return
- # 生成一个 0 到 1 之间的随机数
- var random_value = randf()
-
- # 如果随机数小于等于概率值,则返回 true
- return random_value <= (probability*0.001)
+ # 确保商店面板已初始化
+ crop_store_panel.init_store()
+ # 显示商店面板
+ crop_store_panel.show()
+ # 确保在最前面显示
+ crop_store_panel.move_to_front()
+ pass
-# 保存游戏数据
-func _save_game():
- ## 创建一个字典来保存游戏状态
- #var save_data = {
- #"user_name":username_input.text,
- #"user_password":password_input.text,
- #"farm_name":farmname_input.text,
- #"money": money,
- #"experience": experience,
- #"level": level,
- #"farm_lots": farm_lots
- #}
- #write_txt_file(game_path+username_input.text+".txt", str(save_data), false)
- ## 将字典写入文件
- save_game_to_server()
-# 加载游戏数据
-func _load_game():
-
- ## 从本地读取字典
- #var save_data = JSON.parse_string(read_txt_file(game_path+username_input.text+".txt"))
- #money = save_data["money"]
- #experience = save_data["experience"]
- #level = save_data["level"]
- #farm_lots = save_data["farm_lots"]
- load_game_from_server()
-
- Toast.show("游戏已加载!", Color.GREEN)
- _update_ui()
- _update_farm_lots()
- _init_crop_list2()
-
-# 初始化农场地块
-func _init_farm_lots(num_lots):
- for i in range(num_lots):
- farm_lots.append({
- "is_diged": false, # 是否开垦
- "is_planted": false, # 是否种植
- "is_dead": false, # 是否作物已死亡
- "crop_type": "", # 作物类型
- "grow_time": 0, # 生长时间
- "max_grow_time": 5 # 作物需要的最大生长时间(假设5秒成熟)
-
- })
-
-# 初始化作物选择列表
-func _init_crop_list2():
- # 清空已有的作物按钮
- for child in crop_grid_container.get_children():
- child.queue_free()
-
- # 遍历可种植的作物
- for crop_name in can_planted_crop:
- var crop = can_planted_crop[crop_name]
-
- # 只显示当前等级可以种植的作物
- if crop["等级"] <= level:
- var level_btn = _create_crop_button(crop_name, crop["品质"])
- crop_grid_container.add_child(level_btn)
-
-# 更新农场地块状态到 GridContainer
-func _update_farm_lots(): # 每一秒更新一次状态
+# 初始化农场地块按钮 - 只在游戏开始时调用一次
+func _create_farm_buttons():
# 清空当前显示的地块
for child in grid_container.get_children():
child.queue_free()
+
+ # 创建所有地块按钮
+ for i in range(len(farm_lots)):
+ var button = crop_item.duplicate()
+ button.name = "FarmLot_" + str(i)
+
+ # 根据是否处于访问模式连接不同的事件
+ if is_visiting_mode:
+ # 访问模式下,点击地块只显示提示信息
+ button.connect("pressed", Callable(self, "_on_visit_item_selected").bind(i))
+ else:
+ # 正常模式下,连接正常的地块操作
+ button.connect("pressed", Callable(self, "_on_item_selected").bind(i))
+
+ grid_container.add_child(button)
+
+# 更新农场地块状态到 GridContainer 更新现有按钮的状态
+func _update_farm_lots_state():
var digged_count = 0 # 统计已开垦地块的数量
for i in range(len(farm_lots)):
+ if i >= grid_container.get_child_count():
+ break # 防止越界
+
var lot = farm_lots[i]
- var button = crop_item.duplicate()
+ var button = grid_container.get_child(i)
var label = button.get_node("Label")
var progressbar = button.get_node("ProgressBar")
+ # 更新作物图片
+ _update_lot_crop_sprite(button, lot)
+
if lot["is_diged"]:
digged_count += 1 # 增加已开垦地块计数
if lot["is_planted"]:
- # 寒冷环境配置,作物随机概率死亡
- climate_death_timer += 1
- if climate_death_timer >= 60:
- if random_probability(can_planted_crop[lot["crop_type"]]["耐候性"]):
- lot["is_dead"] = true
- climate_death_timer = 0
-
# 如果作物已死亡
if lot["is_dead"]:
- print("[" + farm_lots[i]["crop_type"] + "]" + "已死亡!")
label.modulate = Color.NAVY_BLUE
label.text = "[" + farm_lots[i]["crop_type"] + "已死亡" + "]"
else:
@@ -417,148 +441,104 @@ func _update_farm_lots(): # 每一秒更新一次状态
# 根据品质显示颜色
match can_planted_crop[crop_name]["品质"]:
"普通":
- label.modulate = Color.GAINSBORO
+ label.modulate = Color.HONEYDEW#白色
"优良":
- label.modulate = Color.DODGER_BLUE
+ label.modulate = Color.DODGER_BLUE#深蓝色
"稀有":
- label.modulate = Color.PURPLE
+ label.modulate = Color.HOT_PINK#品红色
"史诗":
- label.modulate = Color.YELLOW
+ label.modulate = Color.YELLOW#黄色
"传奇":
- label.modulate = Color.ORANGE_RED
+ label.modulate = Color.ORANGE_RED#红色
progressbar.show()
progressbar.max_value = int(lot["max_grow_time"])
- progressbar.set_target_value(int(lot["grow_time"]))
+ progressbar.value = int(lot["grow_time"]) # 直接设置值,不使用动画
else:
# 已开垦但未种植的地块显示为空地
- label.modulate = Color.GREEN
+ label.modulate = Color.GREEN#绿色
label.text = "[" + "空地" + "]"
progressbar.hide()
+
else:
# 未开垦的地块
- label.modulate = Color.WEB_GRAY
+ label.modulate = Color.WEB_GRAY#深褐色
label.text = "[" + "未开垦" + "]"
progressbar.hide()
- # 连接按钮点击事件
- button.connect("pressed", Callable(self, "_on_item_selected").bind(i))
- grid_container.add_child(button)
-
# 根据已开垦地块数量更新 dig_money
dig_money = digged_count * 1000
- dig_button.text = "开垦" + "[" + str(dig_money) + "]"
+
+
+# 仅在加载游戏或特定情况下完全刷新地块 - 用于与服务器同步时
+func _refresh_farm_lots():
+ _create_farm_buttons()
+ _update_farm_lots_state()
# 更新玩家信息显示
func _update_ui():
show_money.text = "当前金钱:" + str(money) + " 元"
- show_money.modulate = Color.ORANGE
show_experience.text = "当前经验:" + str(experience) + " 点"
- show_experience.modulate = Color.GREEN
show_level.text = "当前等级:" + str(level) + " 级"
- show_level.modulate = Color.DODGER_BLUE
+
# 处理地块点击事件
func _on_item_selected(index):
+ # 如果处于访问模式,不允许操作
+ if is_visiting_mode:
+ Toast.show("访问模式下无法操作地块", Color.ORANGE)
+ return
+
+ land_panel.show()
+ land_panel.selected_lot_index = index
+ selected_lot_index = index
+
+# 处理访问模式下的地块点击事件
+func _on_visit_item_selected(index):
+ # 显示被访问玩家的地块信息
var lot = farm_lots[index]
+ var info_text = ""
+
if lot["is_diged"]:
if lot["is_planted"]:
if lot["is_dead"]:
- print(lot["crop_type"]+"已被铲除")
- root_out_crop(index)
- pass
+ info_text = "地块 " + str(index + 1) + ": " + lot["crop_type"] + " (已死亡)"
else:
- _harvest_crop(index)
- pass
- pass
+ var crop_name = lot["crop_type"]
+ var progress = float(lot["grow_time"]) / float(lot["max_grow_time"]) * 100.0
+ var quality = "未知品质"
+
+ # 获取作物品质
+ if can_planted_crop.has(crop_name):
+ quality = can_planted_crop[crop_name]["品质"]
+
+ if lot["grow_time"] >= lot["max_grow_time"]:
+ info_text = "地块 " + str(index + 1) + ": " + quality + "-" + crop_name + " (已成熟)"
+ else:
+ info_text = "地块 " + str(index + 1) + ": " + quality + "-" + crop_name + " (成熟度: " + str(int(progress)) + "%)"
else:
- # 记录选中的地块索引,显示作物选择列表
- selected_lot_index = index
- double_click_close(crop_grid_container)
- pass
- pass
- else :
- double_click_close(land_panel)
- dig_index = index
- pass
-
-#双击切换UI事件-比如按一下打开再按一下关闭
-func double_click_close(node):
- if node.visible == false:
- node.show()
- pass
- else :
- node.hide()
- pass
- pass
-
-# 处理作物选择事件
-func _on_crop_selected(crop_index):
- print(crop_index)
- #var crop_name = crop_list.get_item_text(crop_index).split(" (")[0]
- var crop_name = crop_index
+ info_text = "地块 " + str(index + 1) + ": 空地 (已开垦)"
+ else:
+ info_text = "地块 " + str(index + 1) + ": 未开垦"
- if selected_lot_index != -1:
- _plant_crop(selected_lot_index, crop_name)
- selected_lot_index = -1
-
- #crop_list.hide() # 种植完成后隐藏作物选择列表
- crop_grid_container.hide()
+ Toast.show(info_text, Color.CYAN)
+ print("查看地块信息: ", info_text)
-# 种植作物
-func _plant_crop(index, crop_name):
- var crop = can_planted_crop[crop_name]
- if money < crop["花费"]:
- print("金钱不足,无法种植 " + crop_name)
- Toast.show("金钱不足,无法种植 " + crop_name, Color.RED)
- return
-
- money -= crop["花费"]
- farm_lots[index]["is_planted"] = true
- farm_lots[index]["crop_type"] = crop_name
- farm_lots[index]["grow_time"] = 0
- farm_lots[index]["max_grow_time"] = crop["生长时间"]
-
- print("在地块[[" + str(index) + "]种植了[" + crop_name + "]")
- Toast.show("在地块[[" + str(index) + "]种植了[" + crop_name + "]", Color.GREEN)
- Toast.show(
- "名称:"+crop_name+"\n"+
- "花费:"+str(crop["花费"])+"\n"+
- "成熟时间:"+str(crop["生长时间"])+"\n"+
- "收益:"+str(crop["收益"])+"\n"+
- "品质:"+str(crop["品质"])+"\n"+
- "描述:"+str(crop["描述"])+"\n"+
- "耐候性:"+str(crop["耐候性"])+"\n"+
- "种植等级:"+str(crop["等级"])+"\n"+
- "获得经验:"+str(crop["经验"])+"\n"
- , Color.ORANGE)
-
- _update_ui()
- _update_farm_lots()
# 收获作物
func _harvest_crop(index):
var lot = farm_lots[index]
if lot["grow_time"] >= lot["max_grow_time"]:
- var crop = can_planted_crop[lot["crop_type"]]
- money += crop["收益"]+crop["花费"]
- experience += crop["经验"]
- Toast.show("从地块[" + str(index) + "]收获了[" + lot["crop_type"] + "]作物", Color.YELLOW)
- print("从地块[" + str(index) + "]收获了[" + lot["crop_type"] + "]作物")
-
- lot["is_planted"] = false
- lot["crop_type"] = ""
- lot["grow_time"] = 0
-
- _check_level_up()
- _update_ui()
- _update_farm_lots()
+ # 发送收获请求到服务器
+ if network_manager and network_manager.sendHarvestCrop(index):
+ pass
else:
- print("作物还未成熟")
+ #print("作物还未成熟")
Toast.show("作物还未成熟", Color.RED)
-#铲除作物-好像还未实现这个功能
+
+#铲除已死亡作物
func root_out_crop(index):
var lot = farm_lots[index]
lot["is_planted"] = false
@@ -567,96 +547,372 @@ func root_out_crop(index):
lot["crop_type"] = ""
_check_level_up()
_update_ui()
- _update_farm_lots()
+ _update_farm_lots_state()
pass
+
# 检查玩家是否可以升级
func _check_level_up():
var level_up_experience = 100 * level
if experience >= level_up_experience:
level += 1
experience -= level_up_experience
- print("恭喜!你升到了等级 ", level)
+ #print("恭喜!你升到了等级 ", level)
Toast.show("恭喜!你升到了" + str(level) + "级 ", Color.SKY_BLUE)
- _init_crop_list2()
+ crop_store_panel.init_store()
-#-------------http传输的两个关键方法-----------------
-func send_request(endpoint: String, method: int, data: Dictionary = {}):
- var http_request = HTTPRequest.new()
- add_child(http_request)
- http_request.request_completed.connect(self._on_request_completed)
- var json_body = JSON.stringify(data)
- var headers = ["Content-Type: application/json"]
- var error = http_request.request("http://localhost:3000/" + endpoint, headers, method, json_body)
- if error != OK:
- push_error("请求失败: %s" % str(error))
+
+
+#-------------自定义方法----------------
+
+
+func _on_player_ranking_button_pressed() -> void:
+ player_ranking_panel.show()
+ pass
+
+func _on_return_my_farm_button_pressed() -> void:
+ # 如果当前处于访问模式,返回自己的农场
+ if is_visiting_mode:
+ return_to_my_farm()
else:
- #print("请求已发送: ", endpoint, json_body)
- pass
-func _on_request_completed(result, response_code, headers, body):
- var response_text = body.get_string_from_utf8()
- #print("返回 code: %d" % response_code)
- #print("返回 body: %s" % response_text)
+ # 如果不在访问模式,这个按钮可能用于其他功能或者不做任何操作
+ print("当前已在自己的农场")
+
+# 返回自己的农场
+func return_to_my_farm():
+ if not is_visiting_mode:
+ return
+
+ # 发送返回自己农场的请求到服务器
+ if network_manager and network_manager.has_method("sendReturnMyFarm"):
+ var success = network_manager.sendReturnMyFarm()
+ if success:
+ Toast.show("正在返回自己的农场...", Color.YELLOW)
+ print("已发送返回自己农场的请求")
+ else:
+ Toast.show("网络未连接,无法返回农场", Color.RED)
+ print("发送返回农场请求失败,网络未连接")
+ else:
+ Toast.show("网络管理器不可用", Color.RED)
+ print("网络管理器不可用")
+
+# 从服务器获取作物数据
+func _load_crop_data():
+ var network_manager = get_node("/root/main/UI/TCPNerworkManager")
+ if network_manager and network_manager.is_connected_to_server():
+ # 从服务器请求作物数据
+ print("正在从服务器获取作物数据...")
+ network_manager.sendGetCropData()
+ else:
+ # 如果无法连接服务器,尝试加载本地数据
+ print("无法连接服务器,尝试加载本地作物数据...")
+ _load_local_crop_data()
+
+# 尝试从服务器加载最新数据
+func _try_load_from_server():
+
+ if network_manager and network_manager.is_connected_to_server():
+ # 从服务器请求最新作物数据
+ print("尝试从服务器获取最新作物数据...")
+ network_manager.sendGetCropData()
+ else:
+ print("服务器未连接,使用当前作物数据")
+
+# 处理服务器作物数据响应
+func _handle_crop_data_response(response_data):
+ var success = response_data.get("success", false)
+
+ if success:
+ var crop_data = response_data.get("crop_data", {})
+ if crop_data:
+ # 保存到本地文件
+ _save_crop_data_to_local(crop_data)
+ # 设置全局变量
+ can_planted_crop = crop_data
+ print("作物数据已从服务器更新")
+
+ # 重新初始化商店和背包UI,因为现在有了作物数据
+ _refresh_ui_after_crop_data_loaded()
+ else:
+ print("服务器返回的作物数据为空")
+ _load_local_crop_data()
+ else:
+ var message = response_data.get("message", "未知错误")
+ print("从服务器获取作物数据失败:", message)
+ _load_local_crop_data()
+
+# 从本地文件加载作物数据(备用方案)
+func _load_local_crop_data():
+ # 优先尝试加载用户目录下的缓存文件
+ var file = FileAccess.open("user://crop_data.json", FileAccess.READ)
+ if file:
+ var json_text = file.get_as_text()
+ file.close()
+
+ var json = JSON.new()
+ var parse_result = json.parse(json_text)
+ if parse_result == OK:
+ can_planted_crop = json.get_data()
+ print("已加载本地缓存的作物数据")
+ _refresh_ui_after_crop_data_loaded()
+ return
+ else:
+ print("本地缓存作物数据JSON解析错误:", json.get_error_message())
+
+ # 如果缓存文件不存在或解析失败,加载默认数据
+ file = FileAccess.open("res://Data/crop_data.json", FileAccess.READ)
+ if not file:
+ print("无法读取默认作物数据文件!")
+ return
+
+ var json_text = file.get_as_text()
+ file.close()
var json = JSON.new()
- var parse_result = json.parse(response_text)
-
- if parse_result == OK:
- var parsed_data = json.get_data()
- data = parsed_data # 将解析后的数据赋值给 data
- #print("解析成功: ", data)
+ var parse_result = json.parse(json_text)
+ if parse_result != OK:
+ print("默认作物数据JSON解析错误:", json.get_error_message())
+ return
- if data["message"] == "登录成功":
- print("登录成功")
- if data.has("data"):
- var user_data = data["data"]
- #print("用户数据: ", user_data)
- experience = user_data.get("experience", 0)
- farm_lots = user_data.get("farm_lots", [])
- level = user_data.get("level", 1)
- money = user_data.get("money", 0)
- farmname_input.text = user_data.get("farm_name", 0)
- start_game = true
- login_panel.hide()
- # 确保在更新数据后调用 UI 更新函数
- _update_ui()
- _update_farm_lots()
-
-
- elif data["message"] == "密码错误":
- printerr("密码错误")
- pass
- elif data["message"] == "服务器错误":
- if data.has("error"):
- printerr("服务器错误"+str(data["error"]))
- pass
- elif data["message"] == "用户不存在":
- printerr("用户不存在")
- elif data["message"] == "注册成功":
- print("注册成功")
- {"user_name": user_name,"user_password": user_password}
- send_request("login", HTTPClient.METHOD_POST, {"user_name": user_name,"user_password": user_password})
- elif data["message"] == "用户名已存在":
- printerr("用户名已存在")
-
+ can_planted_crop = json.get_data()
+ print("已加载默认作物数据")
+ _refresh_ui_after_crop_data_loaded()
-
- else:
- print("JSON 解析错误: ", json.get_error_message())
-#-------------http传输的两个关键方法-----------------
-
-#是否为有效QQ号
-func is_valid_qq_number(qq_number: String) -> bool:
- # QQ号的标准格式是5到12位的数字
- var qq_regex = RegEx.new()
- var pattern = r"^\d{5,12}$"
+# 作物数据加载后刷新UI
+func _refresh_ui_after_crop_data_loaded():
+ # 重新初始化商店和背包UI,因为现在有了作物数据
+ if crop_store_panel and crop_store_panel.has_method("init_store"):
+ crop_store_panel.init_store()
+ print("商店已根据作物数据重新初始化")
- var error = qq_regex.compile(pattern)
- if error != OK:
- print("格式错误,请输入正确的QQ号码!")
- return false
+ if player_bag_panel and player_bag_panel.has_method("init_player_bag"):
+ player_bag_panel.init_player_bag()
+ print("背包已根据作物数据重新初始化")
- return qq_regex.search(qq_number) != null
+# 保存作物数据到本地文件
+func _save_crop_data_to_local(crop_data):
+ var file = FileAccess.open("user://crop_data.json", FileAccess.WRITE)
+ if not file:
+ print("无法创建本地作物数据缓存文件!")
+ return
+
+ var json_string = JSON.stringify(crop_data, "\t")
+ file.store_string(json_string)
+ file.close()
+ print("作物数据已保存到本地缓存")
-#-------------自定义方法-----------------
+# 加载作物图片序列帧
+func _load_crop_textures(crop_name: String) -> Array:
+ """
+ 加载指定作物的所有序列帧图片
+ 返回图片数组,如果作物不存在则返回默认图片
+ """
+ if crop_textures_cache.has(crop_name):
+ return crop_textures_cache[crop_name]
+
+ var textures = []
+ var crop_path = "res://assets/作物/" + crop_name + "/"
+ var default_path = "res://assets/作物/默认/"
+
+ # 检查作物文件夹是否存在
+ if DirAccess.dir_exists_absolute(crop_path):
+ # 尝试加载作物的序列帧(从0开始)
+ var frame_index = 0
+ while true:
+ var texture_path = crop_path + str(frame_index) + ".png"
+ if ResourceLoader.exists(texture_path):
+ var texture = load(texture_path)
+ if texture:
+ textures.append(texture)
+ frame_index += 1
+ else:
+ break
+ else:
+ break
+
+ if textures.size() > 0:
+ print("成功加载作物 ", crop_name, " 的 ", textures.size(), " 帧图片")
+ else:
+ print("作物 ", crop_name, " 文件夹存在但没有找到有效图片,使用默认图片")
+ textures = _load_default_textures()
+ else:
+ print("作物 ", crop_name, " 的文件夹不存在,使用默认图片")
+ textures = _load_default_textures()
+
+ # 缓存结果
+ crop_textures_cache[crop_name] = textures
+ crop_frame_counts[crop_name] = textures.size()
+
+ return textures
+
+# 加载默认图片
+func _load_default_textures() -> Array:
+ """
+ 加载默认作物图片
+ """
+ if crop_textures_cache.has("默认"):
+ return crop_textures_cache["默认"]
+
+ var textures = []
+ var default_path = "res://assets/作物/默认/"
+
+ # 尝试加载默认图片序列帧
+ var frame_index = 0
+ while true:
+ var texture_path = default_path + str(frame_index) + ".png"
+ if ResourceLoader.exists(texture_path):
+ var texture = load(texture_path)
+ if texture:
+ textures.append(texture)
+ frame_index += 1
+ else:
+ break
+ else:
+ break
+
+ # 如果没有找到序列帧,尝试加载单个默认图片
+ if textures.size() == 0:
+ var single_texture_path = default_path + "0.png"
+ if ResourceLoader.exists(single_texture_path):
+ var texture = load(single_texture_path)
+ if texture:
+ textures.append(texture)
+
+ # 缓存默认图片
+ crop_textures_cache["默认"] = textures
+ crop_frame_counts["默认"] = textures.size()
+
+ print("加载了 ", textures.size(), " 个默认作物图片")
+ return textures
+
+# 根据生长进度获取对应的作物图片
+func _get_crop_texture_by_progress(crop_name: String, progress: float) -> Texture2D:
+ """
+ 根据作物名称和生长进度获取对应的图片
+ progress: 0.0 到 1.0 的生长进度
+ """
+ var textures = _load_crop_textures(crop_name)
+
+ if textures.size() == 0:
+ return null
+
+ if textures.size() == 1:
+ return textures[0]
+
+ # 根据进度计算应该显示的帧
+ var frame_index = int(progress * (textures.size() - 1))
+ frame_index = clamp(frame_index, 0, textures.size() - 1)
+
+ return textures[frame_index]
+
+# 更新地块的作物图片
+func _update_lot_crop_sprite(button: Button, lot_data: Dictionary):
+ """
+ 更新单个地块按钮的作物图片
+ """
+ var crop_sprite = button.get_node("crop_sprite")
+
+ if not lot_data["is_diged"]:
+ # 未开垦的地块,隐藏作物图片
+ crop_sprite.visible = false
+ return
+
+ if not lot_data["is_planted"] or lot_data["crop_type"] == "":
+ # 空地,隐藏作物图片
+ crop_sprite.visible = false
+ return
+
+ # 有作物的地块
+ crop_sprite.visible = true
+
+ var crop_name = lot_data["crop_type"]
+ var grow_time = float(lot_data["grow_time"])
+ var max_grow_time = float(lot_data["max_grow_time"])
+ var is_dead = lot_data.get("is_dead", false)
+
+ # 计算生长进度
+ var progress = 0.0
+ if max_grow_time > 0:
+ progress = grow_time / max_grow_time
+ progress = clamp(progress, 0.0, 1.0)
+
+ # 如果作物死亡,显示最后一帧并调整颜色
+ if is_dead:
+ var texture = _get_crop_texture_by_progress(crop_name, 1.0) # 使用最后一帧
+ if texture:
+ crop_sprite.texture = texture
+ crop_sprite.modulate = Color(0.5, 0.5, 0.5, 0.8) # 变暗表示死亡
+ else:
+ crop_sprite.visible = false
+ else:
+ # 正常作物,恢复正常颜色
+ crop_sprite.modulate = Color.WHITE
+
+ # 获取对应的图片
+ var texture = _get_crop_texture_by_progress(crop_name, progress)
+
+ if texture:
+ crop_sprite.texture = texture
+ else:
+ print("无法获取作物 ", crop_name, " 的图片")
+ crop_sprite.visible = false
+
+# 预加载常用作物图片
+func _preload_common_crop_textures():
+ """
+ 预加载一些常用的作物图片,提高游戏性能
+ """
+ print("开始预加载作物图片...")
+
+ # 首先加载默认图片
+ _load_default_textures()
+
+ # 预加载一些常见作物(可以根据实际情况调整)
+ var common_crops = ["草莓", "胡萝卜", "土豆", "玉米", "小麦", "番茄"]
+
+ for crop_name in common_crops:
+ _load_crop_textures(crop_name)
+
+ print("作物图片预加载完成,已缓存 ", crop_textures_cache.size(), " 种作物")
+
+# 清理作物图片缓存
+func _clear_crop_textures_cache():
+ """
+ 清理作物图片缓存,释放内存
+ """
+ crop_textures_cache.clear()
+ crop_frame_counts.clear()
+ print("作物图片缓存已清理")
+
+# 获取作物图片缓存信息
+func _get_crop_cache_info() -> String:
+ """
+ 获取当前作物图片缓存的信息
+ """
+ var info = "作物图片缓存信息:\n"
+ for crop_name in crop_textures_cache.keys():
+ var frame_count = crop_frame_counts.get(crop_name, 0)
+ info += "- " + crop_name + ": " + str(frame_count) + " 帧\n"
+ return info
+
+# 调试:打印作物图片缓存信息
+func _debug_print_crop_cache():
+ """
+ 调试用:打印当前作物图片缓存信息
+ """
+ print(_get_crop_cache_info())
+
+# 调试:强制刷新所有地块的作物图片
+func _debug_refresh_all_crop_sprites():
+ """
+ 调试用:强制刷新所有地块的作物图片
+ """
+ print("强制刷新所有地块的作物图片...")
+ for i in range(len(farm_lots)):
+ if i >= grid_container.get_child_count():
+ break
+ var button = grid_container.get_child(i)
+ var lot = farm_lots[i]
+ _update_lot_crop_sprite(button, lot)
+ print("作物图片刷新完成")
diff --git a/MainGame.gd.uid b/MainGame.gd.uid
new file mode 100644
index 0000000..7a16985
--- /dev/null
+++ b/MainGame.gd.uid
@@ -0,0 +1 @@
+uid://2pt11sfcaxf7
diff --git a/MainGame.tscn b/MainGame.tscn
index 7dcd047..692e6e9 100644
--- a/MainGame.tscn
+++ b/MainGame.tscn
@@ -1,343 +1,744 @@
-[gd_scene load_steps=11 format=3 uid="uid://dgh61dttaas5a"]
+[gd_scene load_steps=25 format=3 uid="uid://dgh61dttaas5a"]
-[ext_resource type="Script" path="res://MainGame.gd" id="1_v3yaj"]
+[ext_resource type="Script" uid="uid://2pt11sfcaxf7" path="res://MainGame.gd" id="1_v3yaj"]
+[ext_resource type="Texture2D" uid="uid://b4wi8yusmbbu8" path="res://assets/GUI/玩家昵称.png" id="2_ma1re"]
+[ext_resource type="Script" uid="uid://cka0r4g8tbf0" path="res://GUI/login_panel.gd" id="2_mi4js"]
[ext_resource type="Texture2D" uid="uid://cbjtfrej7iq3x" path="res://assets/background2.jpg" id="2_psm5w"]
-[ext_resource type="PackedScene" uid="uid://bkivlkirrx6u8" path="res://crop_item.tscn" id="3_isiom"]
-[ext_resource type="PackedScene" uid="uid://ffw2vjwnwvew" path="res://components/ToastShow.tscn" id="4_7kdbl"]
-[ext_resource type="Texture2D" uid="uid://b7yavo67sf4v7" path="res://assets/GUI/green_bar.tres" id="5_vtsi2"]
-[ext_resource type="Texture2D" uid="uid://d0h1s3wrx45a7" path="res://assets/GUI/white_blue_bar.tres" id="6_0sxhs"]
-[ext_resource type="Texture2D" uid="uid://bc0rsd5x4pxhn" path="res://assets/GUI/orange_bar.tres" id="7_2f3e4"]
-[ext_resource type="Texture2D" uid="uid://beckne13egl8u" path="res://assets/GUI/pink_bar.tres" id="8_qyoht"]
-[ext_resource type="Texture2D" uid="uid://bh73krj8mnojv" path="res://assets/GUI/black_blue_bar.tres" id="9_tunh0"]
-[ext_resource type="Texture2D" uid="uid://b73vvxnp31xs4" path="res://assets/GUI/red_bar.tres" id="10_duo33"]
+[ext_resource type="Texture2D" uid="uid://clvhlo0mc3e7v" path="res://assets/GUI/农场名称.png" id="3_28psf"]
+[ext_resource type="Script" uid="uid://bljtkxil64h14" path="res://GUI/land_panel.gd" id="3_401ut"]
+[ext_resource type="PackedScene" uid="uid://bkivlkirrx6u8" path="res://CopyItems/crop_item.tscn" id="3_isiom"]
+[ext_resource type="PackedScene" uid="uid://2m54c0f1ejir" path="res://CopyItems/green_crop.tscn" id="3_o8l48"]
+[ext_resource type="Script" uid="uid://mtfp0ct42nrx" path="res://GUI/crop_store_panel.gd" id="3_qtrx8"]
+[ext_resource type="Texture2D" uid="uid://cwloibftcmp76" path="res://assets/GUI/经验球.png" id="4_a6adi"]
+[ext_resource type="Script" uid="uid://cgr332wsx63a8" path="res://GUI/player_bag_panel.gd" id="4_led80"]
+[ext_resource type="Script" uid="uid://fk4q3x6uqydd" path="res://GUI/player_ranking_panel.gd" id="4_yphxy"]
+[ext_resource type="PackedScene" uid="uid://cm1e72lhd7j7v" path="res://CopyItems/black_blue_crop.tscn" id="5_o8l48"]
+[ext_resource type="Texture2D" uid="uid://c87kujyuxnx2s" path="res://assets/GUI/等级.png" id="5_va67g"]
+[ext_resource type="PackedScene" uid="uid://crd28qnymob7" path="res://GUI/player_ranking_item.tscn" id="5_yphxy"]
+[ext_resource type="PackedScene" uid="uid://forqk66f354p" path="res://CopyItems/orange_crop.tscn" id="6_0v7qb"]
+[ext_resource type="Texture2D" uid="uid://c6i00d35fnl12" path="res://assets/GUI/钱币.png" id="6_t0yo1"]
+[ext_resource type="Texture2D" uid="uid://ckqy5yq2ltax6" path="res://assets/GUI/小提示.png" id="7_6brkw"]
+[ext_resource type="PackedScene" uid="uid://cpxiaqh0y6a5d" path="res://Network/TCPNetworkManager.tscn" id="7_401ut"]
+[ext_resource type="PackedScene" uid="uid://cmdoymcviv0ai" path="res://CopyItems/pink_crop.tscn" id="7_qtrx8"]
+[ext_resource type="Texture2D" uid="uid://by5qcip8tel1f" path="res://assets/GUI/服务器连接状态.png" id="8_cgwad"]
+[ext_resource type="PackedScene" uid="uid://d3ve4qeggsdqy" path="res://CopyItems/red_crop.tscn" id="8_led80"]
+[ext_resource type="PackedScene" uid="uid://dagh3u5med30i" path="res://CopyItems/white_blue_crop.tscn" id="9_mi4js"]
+[ext_resource type="Script" uid="uid://c7bxje0wvvgo4" path="res://game_camera.gd" id="10_o8l48"]
[node name="main" type="Node"]
script = ExtResource("1_v3yaj")
-[node name="background" type="Sprite2D" parent="."]
-position = Vector2(590, 344)
-scale = Vector2(0.658482, 0.666992)
-texture = ExtResource("2_psm5w")
+[node name="UI" type="CanvasLayer" parent="."]
-[node name="ItemList" type="ItemList" parent="."]
-visible = false
-offset_left = 80.0
-offset_top = 156.0
-offset_right = 1050.0
-offset_bottom = 606.0
-scale = Vector2(1.02983, 1.02983)
-size_flags_horizontal = 3
-size_flags_vertical = 3
-theme_override_font_sizes/font_size = 20
-allow_reselect = true
-allow_rmb_select = true
-auto_height = true
-max_columns = 100
-same_column_width = true
-fixed_column_width = 100
-icon_mode = 0
+[node name="GUI" type="Control" parent="UI"]
+layout_mode = 3
+anchors_preset = 0
-[node name="GridContainer" type="GridContainer" parent="."]
-custom_minimum_size = Vector2(100, 100)
-offset_top = 143.0
-offset_right = 100.0
-offset_bottom = 243.0
-columns = 10
+[node name="HBox2" type="HBoxContainer" parent="UI/GUI"]
+layout_mode = 0
+offset_top = 55.0
+offset_right = 1400.0
+offset_bottom = 111.0
-[node name="CropItem" parent="." instance=ExtResource("3_isiom")]
-offset_left = -538.0
-offset_top = 37.0
-offset_right = -438.0
-offset_bottom = 137.0
-
-[node name="CropList" type="ItemList" parent="."]
-visible = false
-custom_minimum_size = Vector2(100, 100)
-offset_left = 1.0
-offset_top = 41.0
-offset_right = 1152.0
-offset_bottom = 141.0
-size_flags_horizontal = 3
-size_flags_vertical = 3
-theme_override_font_sizes/font_size = 20
-allow_reselect = true
-allow_rmb_select = true
-max_columns = 8
-same_column_width = true
-fixed_column_width = 222
-icon_mode = 0
-
-[node name="ToastShow" parent="." instance=ExtResource("4_7kdbl")]
-visible = false
-offset_top = 580.0
-offset_bottom = 603.0
-
-[node name="ToastShow2" parent="." instance=ExtResource("4_7kdbl")]
-visible = false
-offset_left = 1.0
-offset_top = 41.0
-offset_right = 65.0
-offset_bottom = 64.0
-
-[node name="ScrollContainer" type="ScrollContainer" parent="."]
-offset_left = 1.0
-offset_top = 42.0
-offset_right = 2065.0
-offset_bottom = 244.0
-scale = Vector2(0.5, 0.5)
-horizontal_scroll_mode = 0
-
-[node name="Crop_GridContainer" type="GridContainer" parent="ScrollContainer"]
+[node name="player_name_image" type="TextureRect" parent="UI/GUI/HBox2"]
layout_mode = 2
-columns = 5
+texture = ExtResource("2_ma1re")
+expand_mode = 2
-[node name="Copy_Nodes" type="Node2D" parent="."]
-position = Vector2(-1000, 0)
+[node name="player_name" type="Label" parent="UI/GUI/HBox2"]
+modulate = Color(1, 0.670588, 0.490196, 1)
+layout_mode = 2
+theme_override_font_sizes/font_size = 30
+text = "树萌芽"
-[node name="Green" type="Button" parent="Copy_Nodes"]
-offset_left = 1.0
-offset_top = 42.0
-offset_right = 409.0
-offset_bottom = 138.0
-theme_override_font_sizes/font_size = 40
-text = "普通"
-icon = ExtResource("5_vtsi2")
-icon_alignment = 1
+[node name="farm_name_image" type="TextureRect" parent="UI/GUI/HBox2"]
+layout_mode = 2
+texture = ExtResource("3_28psf")
+expand_mode = 3
-[node name="White_Blue" type="Button" parent="Copy_Nodes"]
-offset_left = -5.0
-offset_top = 148.0
-offset_right = 403.0
-offset_bottom = 244.0
-theme_override_font_sizes/font_size = 40
-text = "稀有"
-icon = ExtResource("6_0sxhs")
-icon_alignment = 1
+[node name="farm_name" type="Label" parent="UI/GUI/HBox2"]
+modulate = Color(1, 0.858824, 0.623529, 1)
+layout_mode = 2
+theme_override_font_sizes/font_size = 30
+text = "树萌芽的农场"
-[node name="Orange" type="Button" parent="Copy_Nodes"]
-offset_left = -6.0
-offset_top = 252.0
-offset_right = 402.0
-offset_bottom = 348.0
-theme_override_font_sizes/font_size = 40
-text = "优良"
-icon = ExtResource("7_2f3e4")
-icon_alignment = 1
+[node name="status_label_image" type="TextureRect" parent="UI/GUI/HBox2"]
+layout_mode = 2
+texture = ExtResource("8_cgwad")
+expand_mode = 2
-[node name="Pink" type="Button" parent="Copy_Nodes"]
-offset_left = -16.0
-offset_top = 362.0
-offset_right = 392.0
-offset_bottom = 458.0
-theme_override_font_sizes/font_size = 40
-text = "史诗"
-icon = ExtResource("8_qyoht")
-icon_alignment = 1
+[node name="StatusLabel" type="Label" parent="UI/GUI/HBox2"]
+layout_mode = 2
+theme_override_font_sizes/font_size = 30
+text = "服务器状态:正在检测中"
-[node name="Black_Blue" type="Button" parent="Copy_Nodes"]
-offset_left = -5.0
-offset_top = 481.0
-offset_right = 403.0
-offset_bottom = 577.0
-theme_override_font_sizes/font_size = 40
-text = "传奇"
-icon = ExtResource("9_tunh0")
-icon_alignment = 1
+[node name="HBox" type="HBoxContainer" parent="UI/GUI"]
+layout_mode = 0
+offset_right = 1400.0
+offset_bottom = 56.0
-[node name="Red" type="Button" parent="Copy_Nodes"]
-offset_left = 7.0
-offset_top = 596.0
-offset_right = 415.0
-offset_bottom = 692.0
-theme_override_font_sizes/font_size = 40
-text = "神话"
-icon = ExtResource("10_duo33")
-icon_alignment = 1
+[node name="experience_image" type="TextureRect" parent="UI/GUI/HBox"]
+layout_mode = 2
+texture = ExtResource("4_a6adi")
+expand_mode = 2
-[node name="HTTPRequest" type="HTTPRequest" parent="."]
-
-[node name="GUI" type="Node2D" parent="."]
-
-[node name="level" type="Label" parent="GUI"]
-offset_left = 632.0
-offset_right = 773.0
-offset_bottom = 42.0
-theme_override_font_sizes/font_size = 20
-text = "等级:100"
-
-[node name="experience" type="Label" parent="GUI"]
-offset_left = 334.0
-offset_right = 475.0
-offset_bottom = 42.0
-theme_override_font_sizes/font_size = 20
+[node name="experience" type="Label" parent="UI/GUI/HBox"]
+modulate = Color(0, 1, 0, 1)
+layout_mode = 2
+theme_override_font_sizes/font_size = 30
text = "经验:999"
-[node name="LoginPanel" type="Panel" parent="GUI"]
-offset_left = 379.0
-offset_top = 156.0
-offset_right = 765.0
-offset_bottom = 444.0
-
-[node name="VBox" type="VBoxContainer" parent="GUI/LoginPanel"]
-layout_mode = 0
-offset_top = 2.0
-offset_right = 386.0
-offset_bottom = 286.0
-
-[node name="Title" type="Label" parent="GUI/LoginPanel/VBox"]
+[node name="level_image" type="TextureRect" parent="UI/GUI/HBox"]
layout_mode = 2
+texture = ExtResource("5_va67g")
+expand_mode = 2
+
+[node name="level" type="Label" parent="UI/GUI/HBox"]
+modulate = Color(0, 1, 1, 1)
+layout_mode = 2
+theme_override_font_sizes/font_size = 30
+text = "等级:100"
+
+[node name="money_image" type="TextureRect" parent="UI/GUI/HBox"]
+layout_mode = 2
+texture = ExtResource("6_t0yo1")
+expand_mode = 2
+
+[node name="money" type="Label" parent="UI/GUI/HBox"]
+modulate = Color(1, 1, 0, 1)
+layout_mode = 2
+theme_override_font_sizes/font_size = 30
+text = "钱币:999"
+
+[node name="tip_image" type="TextureRect" parent="UI/GUI/HBox"]
+layout_mode = 2
+texture = ExtResource("7_6brkw")
+expand_mode = 2
+
+[node name="tip" type="Label" parent="UI/GUI/HBox"]
+layout_mode = 2
+theme_override_colors/font_color = Color(1, 0, 1, 1)
+theme_override_font_sizes/font_size = 30
+text = "游戏小提示"
+
+[node name="VBox" type="VBoxContainer" parent="UI/GUI"]
+layout_mode = 0
+offset_left = 5.0
+offset_top = 522.0
+offset_right = 253.0
+offset_bottom = 719.0
+alignment = 2
+
+[node name="ReturnMyFarmButton" type="Button" parent="UI/GUI/VBox"]
+visible = false
+layout_mode = 2
+theme_override_font_sizes/font_size = 40
+text = "返回我的农场"
+
+[node name="OpenStoreButton" type="Button" parent="UI/GUI/VBox"]
+layout_mode = 2
+theme_override_font_sizes/font_size = 40
+text = "种子商店"
+
+[node name="PlayerRankingButton" type="Button" parent="UI/GUI/VBox"]
+layout_mode = 2
+theme_override_font_sizes/font_size = 40
+text = "玩家排行榜"
+
+[node name="LoginPanel" type="PanelContainer" parent="UI"]
+offset_left = 486.0
+offset_top = 143.0
+offset_right = 989.0
+offset_bottom = 616.0
+script = ExtResource("2_mi4js")
+
+[node name="VBox" type="VBoxContainer" parent="UI/LoginPanel"]
+layout_mode = 2
+
+[node name="Title" type="Label" parent="UI/LoginPanel/VBox"]
+layout_mode = 2
+theme_override_font_sizes/font_size = 25
text = "登录/注册面板"
horizontal_alignment = 1
vertical_alignment = 1
-[node name="HBox" type="HBoxContainer" parent="GUI/LoginPanel/VBox"]
+[node name="UserName" type="HBoxContainer" parent="UI/LoginPanel/VBox"]
layout_mode = 2
-[node name="Label" type="Label" parent="GUI/LoginPanel/VBox/HBox"]
+[node name="Label" type="Label" parent="UI/LoginPanel/VBox/UserName"]
layout_mode = 2
+theme_override_font_sizes/font_size = 20
text = "账号"
horizontal_alignment = 1
vertical_alignment = 1
-[node name="username_input" type="LineEdit" parent="GUI/LoginPanel/VBox/HBox"]
+[node name="username_input" type="LineEdit" parent="UI/LoginPanel/VBox/UserName"]
layout_mode = 2
size_flags_horizontal = 3
+theme_override_font_sizes/font_size = 20
placeholder_text = "请输入QQ号..."
metadata/_edit_use_anchors_ = true
-[node name="HBox2" type="HBoxContainer" parent="GUI/LoginPanel/VBox"]
+[node name="Password1" type="HBoxContainer" parent="UI/LoginPanel/VBox"]
layout_mode = 2
-[node name="Label2" type="Label" parent="GUI/LoginPanel/VBox/HBox2"]
+[node name="Label2" type="Label" parent="UI/LoginPanel/VBox/Password1"]
layout_mode = 2
+theme_override_font_sizes/font_size = 20
text = "密码"
horizontal_alignment = 1
vertical_alignment = 1
-[node name="password_input" type="LineEdit" parent="GUI/LoginPanel/VBox/HBox2"]
+[node name="password_input" type="LineEdit" parent="UI/LoginPanel/VBox/Password1"]
layout_mode = 2
size_flags_horizontal = 3
+theme_override_font_sizes/font_size = 20
placeholder_text = "请输入密码..."
-[node name="Title3" type="Label" parent="GUI/LoginPanel/VBox"]
+[node name="Title3" type="Label" parent="UI/LoginPanel/VBox"]
layout_mode = 2
+theme_override_font_sizes/font_size = 20
text = "以下为注册填写内容"
horizontal_alignment = 1
vertical_alignment = 1
-[node name="HBox5" type="HBoxContainer" parent="GUI/LoginPanel/VBox"]
+[node name="Password2" type="HBoxContainer" parent="UI/LoginPanel/VBox"]
layout_mode = 2
-[node name="Label2" type="Label" parent="GUI/LoginPanel/VBox/HBox5"]
+[node name="Label2" type="Label" parent="UI/LoginPanel/VBox/Password2"]
layout_mode = 2
-text = "密码[选填]"
+theme_override_font_sizes/font_size = 20
+text = "确认密码"
horizontal_alignment = 1
vertical_alignment = 1
-[node name="password_input2" type="LineEdit" parent="GUI/LoginPanel/VBox/HBox5"]
+[node name="password_input2" type="LineEdit" parent="UI/LoginPanel/VBox/Password2"]
layout_mode = 2
size_flags_horizontal = 3
+theme_override_font_sizes/font_size = 20
placeholder_text = "请再次输入密码(登录不需要)..."
-[node name="HBox3" type="HBoxContainer" parent="GUI/LoginPanel/VBox"]
+[node name="VerificationCode" type="HBoxContainer" parent="UI/LoginPanel/VBox"]
layout_mode = 2
-[node name="Label" type="Label" parent="GUI/LoginPanel/VBox/HBox3"]
+[node name="Label" type="Label" parent="UI/LoginPanel/VBox/VerificationCode"]
layout_mode = 2
-text = "名称[选填]"
+theme_override_font_sizes/font_size = 20
+text = "验证码"
horizontal_alignment = 1
vertical_alignment = 1
-[node name="farmname_input" type="LineEdit" parent="GUI/LoginPanel/VBox/HBox3"]
+[node name="verificationcode_input" type="LineEdit" parent="UI/LoginPanel/VBox/VerificationCode"]
layout_mode = 2
size_flags_horizontal = 3
+theme_override_font_sizes/font_size = 20
+placeholder_text = "请输入您的QQ邮箱收到的验证码..."
+metadata/_edit_use_anchors_ = true
+
+[node name="SendButton" type="Button" parent="UI/LoginPanel/VBox/VerificationCode"]
+layout_mode = 2
+theme_override_font_sizes/font_size = 20
+text = "发送验证码"
+
+[node name="PlayerName" type="HBoxContainer" parent="UI/LoginPanel/VBox"]
+layout_mode = 2
+
+[node name="Label2" type="Label" parent="UI/LoginPanel/VBox/PlayerName"]
+layout_mode = 2
+theme_override_font_sizes/font_size = 20
+text = "玩家昵称"
+horizontal_alignment = 1
+vertical_alignment = 1
+
+[node name="playername_input" type="LineEdit" parent="UI/LoginPanel/VBox/PlayerName"]
+layout_mode = 2
+size_flags_horizontal = 3
+theme_override_font_sizes/font_size = 20
+placeholder_text = "请输入您的玩家昵称..."
+
+[node name="FarmName" type="HBoxContainer" parent="UI/LoginPanel/VBox"]
+layout_mode = 2
+
+[node name="Label" type="Label" parent="UI/LoginPanel/VBox/FarmName"]
+layout_mode = 2
+theme_override_font_sizes/font_size = 20
+text = "农场名称"
+horizontal_alignment = 1
+vertical_alignment = 1
+
+[node name="farmname_input" type="LineEdit" parent="UI/LoginPanel/VBox/FarmName"]
+layout_mode = 2
+size_flags_horizontal = 3
+theme_override_font_sizes/font_size = 20
placeholder_text = "请输入您的农场名称(登录不需要)..."
metadata/_edit_use_anchors_ = true
-[node name="HBox4" type="HBoxContainer" parent="GUI/LoginPanel/VBox"]
+[node name="LoginRegister" type="HBoxContainer" parent="UI/LoginPanel/VBox"]
layout_mode = 2
-[node name="login_button" type="Button" parent="GUI/LoginPanel/VBox/HBox4"]
+[node name="login_button" type="Button" parent="UI/LoginPanel/VBox/LoginRegister"]
layout_mode = 2
size_flags_horizontal = 3
+theme_override_font_sizes/font_size = 20
text = "登录"
-[node name="register_button" type="Button" parent="GUI/LoginPanel/VBox/HBox4"]
+[node name="register_button" type="Button" parent="UI/LoginPanel/VBox/LoginRegister"]
layout_mode = 2
size_flags_horizontal = 3
+theme_override_font_sizes/font_size = 20
text = "注册"
-[node name="Title2" type="Label" parent="GUI/LoginPanel/VBox"]
+[node name="Note" type="Label" parent="UI/LoginPanel/VBox"]
layout_mode = 2
-text = "注意:账号请输入您的QQ号,方便匹配QQ好友,
-账号,密码请不要和您的QQ密码相同,防止信息泄露"
+theme_override_font_sizes/font_size = 20
+text = "注意:账号请直接使用您的QQ号,系统会直接向您的QQ
+邮箱发送一串验证码进行注册验证,密码请设置的复杂一
+点,以免被暴力破解"
horizontal_alignment = 1
vertical_alignment = 1
-[node name="tip" type="Label" parent="GUI"]
-offset_left = 878.0
-offset_right = 1150.0
-offset_bottom = 42.0
-theme_override_colors/font_color = Color(1, 0, 1, 1)
+[node name="status_label" type="Label" parent="UI/LoginPanel/VBox"]
+layout_mode = 2
theme_override_font_sizes/font_size = 20
-text = "游戏自动保存剩余【10】秒"
+text = "连接状态"
+horizontal_alignment = 1
-[node name="money" type="Label" parent="GUI"]
-offset_left = 1.0
-offset_right = 142.0
-offset_bottom = 42.0
-theme_override_font_sizes/font_size = 20
-text = "钱币:999"
-
-[node name="Land_Panel" type="PanelContainer" parent="GUI"]
+[node name="LandPanel" type="Panel" parent="UI"]
visible = false
-offset_right = 556.0
-offset_bottom = 58.0
+offset_left = 475.0
+offset_top = 145.0
+offset_right = 991.0
+offset_bottom = 616.0
+script = ExtResource("3_401ut")
-[node name="VBox" type="VBoxContainer" parent="GUI/Land_Panel"]
-layout_mode = 2
+[node name="Quit_Button" type="Button" parent="UI/LandPanel"]
+layout_mode = 0
+offset_left = 465.0
+offset_right = 515.0
+offset_bottom = 50.0
+theme_override_font_sizes/font_size = 30
+text = "X"
-[node name="Title" type="Label" parent="GUI/Land_Panel/VBox"]
+[node name="HBox" type="HBoxContainer" parent="UI/LandPanel"]
+layout_mode = 0
+offset_right = 40.0
+offset_bottom = 40.0
+
+[node name="Title" type="Label" parent="UI/LandPanel"]
layout_mode = 2
+offset_right = 516.0
+offset_bottom = 42.0
+theme_override_font_sizes/font_size = 30
text = "土地面板"
horizontal_alignment = 1
vertical_alignment = 1
-[node name="HBox" type="HBoxContainer" parent="GUI/Land_Panel/VBox"]
+[node name="Grid" type="GridContainer" parent="UI/LandPanel"]
layout_mode = 2
+offset_top = 46.0
+offset_right = 500.0
+offset_bottom = 210.0
+columns = 5
-[node name="Dig_button" type="Button" parent="GUI/Land_Panel/VBox/HBox"]
+[node name="Dig_Button" type="Button" parent="UI/LandPanel/Grid"]
+modulate = Color(1, 0.419608, 0.352941, 1)
+custom_minimum_size = Vector2(100, 100)
layout_mode = 2
+theme_override_font_sizes/font_size = 30
text = "开垦"
-[node name="Description" type="Label" parent="GUI/Land_Panel/VBox/HBox"]
+[node name="Plant_Button" type="Button" parent="UI/LandPanel/Grid"]
+modulate = Color(1, 0.682353, 0, 1)
+custom_minimum_size = Vector2(100, 100)
layout_mode = 2
-text = "土地需要开垦才能种植,开垦所需费用随玩家已开垦土地数量增多而增多"
+theme_override_font_sizes/font_size = 30
+text = "种植"
-[node name="HBox2" type="HBoxContainer" parent="GUI/Land_Panel/VBox"]
+[node name="Remove_Button" type="Button" parent="UI/LandPanel/Grid"]
visible = false
+modulate = Color(1, 1, 0, 1)
+custom_minimum_size = Vector2(100, 100)
layout_mode = 2
+theme_override_font_sizes/font_size = 30
+text = "铲除"
-[node name="Button" type="Button" parent="GUI/Land_Panel/VBox/HBox2"]
+[node name="Harvest_Button" type="Button" parent="UI/LandPanel/Grid"]
+modulate = Color(0.223529, 1, 0.290196, 1)
+custom_minimum_size = Vector2(100, 100)
layout_mode = 2
+theme_override_font_sizes/font_size = 30
+text = "收获"
+
+[node name="Water_Button" type="Button" parent="UI/LandPanel/Grid"]
+visible = false
+modulate = Color(0, 1, 1, 1)
+custom_minimum_size = Vector2(100, 100)
+layout_mode = 2
+theme_override_font_sizes/font_size = 30
+text = "浇水"
+
+[node name="Fertilize_Button" type="Button" parent="UI/LandPanel/Grid"]
+visible = false
+modulate = Color(0.592157, 0.337255, 1, 1)
+custom_minimum_size = Vector2(80, 80)
+layout_mode = 2
+theme_override_font_sizes/font_size = 30
+text = "施肥"
+
+[node name="Upgrade_Button" type="Button" parent="UI/LandPanel/Grid"]
+visible = false
+modulate = Color(0.0784314, 0.470588, 1, 1)
+custom_minimum_size = Vector2(100, 100)
+layout_mode = 2
+theme_override_font_sizes/font_size = 30
text = "升级"
-[node name="Description" type="Label" parent="GUI/Land_Panel/VBox/HBox2"]
-layout_mode = 2
-text = "升级描述"
-
-[node name="HBox3" type="HBoxContainer" parent="GUI/Land_Panel/VBox"]
+[node name="PlayerRankingPanel" type="Panel" parent="UI"]
visible = false
+offset_right = 1400.0
+offset_bottom = 720.0
+script = ExtResource("4_yphxy")
+
+[node name="Scroll" type="ScrollContainer" parent="UI/PlayerRankingPanel"]
+layout_mode = 2
+offset_top = 68.0
+offset_right = 1400.0
+offset_bottom = 720.0
+size_flags_vertical = 3
+
+[node name="PlayerList" type="VBoxContainer" parent="UI/PlayerRankingPanel/Scroll"]
+layout_mode = 2
+size_flags_horizontal = 3
+size_flags_vertical = 3
+
+[node name="player_ranking_item" parent="UI/PlayerRankingPanel/Scroll/PlayerList" instance=ExtResource("5_yphxy")]
layout_mode = 2
-[node name="Button" type="Button" parent="GUI/Land_Panel/VBox/HBox3"]
+[node name="Title" type="RichTextLabel" parent="UI/PlayerRankingPanel"]
layout_mode = 2
-text = "恢复"
+offset_left = 2.0
+offset_right = 1395.0
+offset_bottom = 56.0
+size_flags_vertical = 3
+theme_override_font_sizes/normal_font_size = 40
+bbcode_enabled = true
+text = "玩家排行榜"
+horizontal_alignment = 1
-[node name="Description" type="Label" parent="GUI/Land_Panel/VBox/HBox3"]
+[node name="QuitButton" type="Button" parent="UI/PlayerRankingPanel"]
+custom_minimum_size = Vector2(55, 55)
+layout_mode = 0
+offset_left = 1338.0
+offset_top = 3.0
+offset_right = 1395.0
+offset_bottom = 60.0
+theme_override_font_sizes/font_size = 35
+text = "X"
+
+[node name="RefreshButton" type="Button" parent="UI/PlayerRankingPanel"]
+custom_minimum_size = Vector2(55, 55)
+layout_mode = 0
+offset_left = 1.0
+offset_top = 3.0
+offset_right = 79.0
+offset_bottom = 60.0
+theme_override_font_sizes/font_size = 35
+text = "刷新"
+
+[node name="CropStorePanel" type="Panel" parent="UI"]
+visible = false
+offset_left = 1.0
+offset_right = 1400.0
+offset_bottom = 720.0
+size_flags_horizontal = 3
+size_flags_vertical = 3
+script = ExtResource("3_qtrx8")
+
+[node name="SortContainer" type="HBoxContainer" parent="UI/CropStorePanel"]
+layout_mode = 0
+offset_top = 58.0
+offset_right = 1399.0
+offset_bottom = 121.0
+
+[node name="SortLabel" type="Label" parent="UI/CropStorePanel/SortContainer"]
layout_mode = 2
-text = "恢复描述"
+theme_override_font_sizes/font_size = 30
+text = "排序:"
-[connection signal="pressed" from="GUI/LoginPanel/VBox/HBox4/login_button" to="." method="_on_login_button_pressed"]
-[connection signal="pressed" from="GUI/LoginPanel/VBox/HBox4/register_button" to="." method="_on_register_button_pressed"]
-[connection signal="pressed" from="GUI/Land_Panel/VBox/HBox/Dig_button" to="." method="_on_dig_button_pressed"]
+[node name="Sort_All" type="Button" parent="UI/CropStorePanel/SortContainer"]
+layout_mode = 2
+theme_override_font_sizes/font_size = 30
+text = "全部"
+
+[node name="Sort_Common" type="Button" parent="UI/CropStorePanel/SortContainer"]
+layout_mode = 2
+theme_override_font_sizes/font_size = 30
+text = "普通"
+
+[node name="Sort_Superior" type="Button" parent="UI/CropStorePanel/SortContainer"]
+layout_mode = 2
+theme_override_font_sizes/font_size = 30
+text = "优良"
+
+[node name="Sort_Rare" type="Button" parent="UI/CropStorePanel/SortContainer"]
+layout_mode = 2
+theme_override_font_sizes/font_size = 30
+text = "稀有"
+
+[node name="Sort_Epic" type="Button" parent="UI/CropStorePanel/SortContainer"]
+layout_mode = 2
+theme_override_font_sizes/font_size = 30
+text = "史诗"
+
+[node name="Sort_Legendary" type="Button" parent="UI/CropStorePanel/SortContainer"]
+layout_mode = 2
+theme_override_font_sizes/font_size = 30
+text = "传奇"
+
+[node name="Sort_Price" type="Button" parent="UI/CropStorePanel/SortContainer"]
+layout_mode = 2
+theme_override_font_sizes/font_size = 30
+text = "按价格"
+
+[node name="Sort_GrowTime" type="Button" parent="UI/CropStorePanel/SortContainer"]
+layout_mode = 2
+theme_override_font_sizes/font_size = 30
+text = "按生长时间"
+
+[node name="Sort_Profit" type="Button" parent="UI/CropStorePanel/SortContainer"]
+layout_mode = 2
+theme_override_font_sizes/font_size = 30
+text = "按收益"
+
+[node name="Sort_Level" type="Button" parent="UI/CropStorePanel/SortContainer"]
+layout_mode = 2
+theme_override_font_sizes/font_size = 30
+text = "按等级"
+
+[node name="ScrollContainer" type="ScrollContainer" parent="UI/CropStorePanel"]
+layout_mode = 2
+offset_top = 134.0
+offset_right = 4657.0
+offset_bottom = 2087.0
+scale = Vector2(0.3, 0.3)
+size_flags_vertical = 3
+horizontal_scroll_mode = 0
+
+[node name="Crop_Grid" type="GridContainer" parent="UI/CropStorePanel/ScrollContainer"]
+layout_mode = 2
+size_flags_horizontal = 3
+size_flags_vertical = 3
+columns = 11
+
+[node name="Title" type="Label" parent="UI/CropStorePanel"]
+layout_mode = 2
+offset_right = 1397.0
+offset_bottom = 55.0
+size_flags_horizontal = 3
+theme_override_font_sizes/font_size = 40
+text = "种子商店"
+horizontal_alignment = 1
+
+[node name="QuitButton" type="Button" parent="UI/CropStorePanel"]
+custom_minimum_size = Vector2(60, 60)
+layout_mode = 2
+offset_left = 1337.0
+offset_top = 3.0
+offset_right = 1397.0
+offset_bottom = 66.0
+theme_override_font_sizes/font_size = 40
+text = "X"
+
+[node name="PlayerBagPanel" type="Panel" parent="UI"]
+visible = false
+offset_left = 1.0
+offset_right = 1398.0
+offset_bottom = 720.0
+size_flags_horizontal = 3
+size_flags_vertical = 3
+script = ExtResource("4_led80")
+
+[node name="SortContainer" type="HBoxContainer" parent="UI/PlayerBagPanel"]
+layout_mode = 0
+offset_top = 58.0
+offset_right = 1397.0
+offset_bottom = 121.0
+
+[node name="SortLabel" type="Label" parent="UI/PlayerBagPanel/SortContainer"]
+layout_mode = 2
+theme_override_font_sizes/font_size = 30
+text = "排序:"
+
+[node name="Sort_All" type="Button" parent="UI/PlayerBagPanel/SortContainer"]
+layout_mode = 2
+theme_override_font_sizes/font_size = 30
+text = "全部"
+
+[node name="Sort_Common" type="Button" parent="UI/PlayerBagPanel/SortContainer"]
+layout_mode = 2
+theme_override_font_sizes/font_size = 30
+text = "普通"
+
+[node name="Sort_Superior" type="Button" parent="UI/PlayerBagPanel/SortContainer"]
+layout_mode = 2
+theme_override_font_sizes/font_size = 30
+text = "优良"
+
+[node name="Sort_Rare" type="Button" parent="UI/PlayerBagPanel/SortContainer"]
+layout_mode = 2
+theme_override_font_sizes/font_size = 30
+text = "稀有"
+
+[node name="Sort_Epic" type="Button" parent="UI/PlayerBagPanel/SortContainer"]
+layout_mode = 2
+theme_override_font_sizes/font_size = 30
+text = "史诗"
+
+[node name="Sort_Legendary" type="Button" parent="UI/PlayerBagPanel/SortContainer"]
+layout_mode = 2
+theme_override_font_sizes/font_size = 30
+text = "传奇"
+
+[node name="Sort_Price" type="Button" parent="UI/PlayerBagPanel/SortContainer"]
+layout_mode = 2
+theme_override_font_sizes/font_size = 30
+text = "按价格"
+
+[node name="Sort_GrowTime" type="Button" parent="UI/PlayerBagPanel/SortContainer"]
+layout_mode = 2
+theme_override_font_sizes/font_size = 30
+text = "按生长时间"
+
+[node name="Sort_Profit" type="Button" parent="UI/PlayerBagPanel/SortContainer"]
+layout_mode = 2
+theme_override_font_sizes/font_size = 30
+text = "按收益"
+
+[node name="Sort_Level" type="Button" parent="UI/PlayerBagPanel/SortContainer"]
+layout_mode = 2
+theme_override_font_sizes/font_size = 30
+text = "按等级"
+
+[node name="ScrollContainer" type="ScrollContainer" parent="UI/PlayerBagPanel"]
+layout_mode = 2
+offset_top = 128.0
+offset_right = 4657.0
+offset_bottom = 2101.0
+scale = Vector2(0.3, 0.3)
+size_flags_vertical = 3
+horizontal_scroll_mode = 0
+
+[node name="Bag_Grid" type="GridContainer" parent="UI/PlayerBagPanel/ScrollContainer"]
+layout_mode = 2
+size_flags_horizontal = 3
+size_flags_vertical = 3
+columns = 11
+
+[node name="Title" type="Label" parent="UI/PlayerBagPanel"]
+layout_mode = 2
+offset_right = 1276.0
+offset_bottom = 55.0
+size_flags_horizontal = 3
+theme_override_font_sizes/font_size = 40
+text = "玩家背包"
+horizontal_alignment = 1
+
+[node name="QuitButton" type="Button" parent="UI/PlayerBagPanel"]
+custom_minimum_size = Vector2(60, 60)
+layout_mode = 2
+offset_left = 1337.0
+offset_right = 1397.0
+offset_bottom = 63.0
+theme_override_font_sizes/font_size = 40
+text = "X"
+
+[node name="TCPNetworkManager" parent="UI" instance=ExtResource("7_401ut")]
+visible = false
+offset_left = 2.00012
+offset_top = 143.0
+offset_right = 2.00012
+offset_bottom = 143.0
+scale = Vector2(0.7, 0.7)
+
+[node name="BackgroundUI" type="CanvasLayer" parent="."]
+layer = -1
+
+[node name="background" type="Sprite2D" parent="BackgroundUI"]
+modulate = Color(1, 1, 1, 0.372549)
+show_behind_parent = true
+z_index = -100
+z_as_relative = false
+position = Vector2(702.875, 360)
+scale = Vector2(0.779157, 0.703125)
+texture = ExtResource("2_psm5w")
+
+[node name="GridContainer" type="GridContainer" parent="."]
+z_as_relative = false
+custom_minimum_size = Vector2(100, 100)
+offset_top = 3.0
+offset_right = 1400.0
+offset_bottom = 720.0
+columns = 10
+
+[node name="CopyNodes" type="Node2D" parent="."]
+position = Vector2(-1000, 0)
+
+[node name="CropItem" parent="CopyNodes" instance=ExtResource("3_isiom")]
+z_index = 2
+z_as_relative = false
+offset_left = -1433.0
+offset_top = -161.0
+offset_right = -1333.0
+offset_bottom = -61.0
+
+[node name="GreenCrop" parent="CopyNodes" instance=ExtResource("3_o8l48")]
+offset_left = 16.0
+offset_top = 143.0
+offset_right = 416.0
+offset_bottom = 543.0
+
+[node name="BlackBlueCrop" parent="CopyNodes" instance=ExtResource("5_o8l48")]
+offset_left = -24.0
+offset_top = -27.0
+offset_right = 376.0
+offset_bottom = 373.0
+
+[node name="OrangeCrop" parent="CopyNodes" instance=ExtResource("6_0v7qb")]
+offset_left = 57.0
+offset_top = -184.0
+offset_right = 457.0
+offset_bottom = 216.0
+
+[node name="PinkCrop" parent="CopyNodes" instance=ExtResource("7_qtrx8")]
+offset_left = -149.0
+offset_top = -185.0
+offset_right = 251.0
+offset_bottom = 215.0
+
+[node name="RedCrop" parent="CopyNodes" instance=ExtResource("8_led80")]
+offset_left = -311.0
+offset_top = -18.0
+offset_right = 89.0
+offset_bottom = 382.0
+
+[node name="WhiteBlueCrop" parent="CopyNodes" instance=ExtResource("9_mi4js")]
+offset_left = -212.0
+offset_top = 134.0
+offset_right = 188.0
+offset_bottom = 534.0
+
+[node name="GameCamera" type="Camera2D" parent="."]
+anchor_mode = 0
+position_smoothing_enabled = true
+script = ExtResource("10_o8l48")
+bounds_enabled = true
+bounds_min = Vector2(-500, -500)
+bounds_max = Vector2(500, 500)
+
+[node name="GameManager" type="Node" parent="."]
+
+[connection signal="pressed" from="UI/GUI/VBox/ReturnMyFarmButton" to="." method="_on_return_my_farm_button_pressed"]
+[connection signal="pressed" from="UI/GUI/VBox/OpenStoreButton" to="." method="_on_open_store_button_pressed"]
+[connection signal="pressed" from="UI/GUI/VBox/PlayerRankingButton" to="." method="_on_player_ranking_button_pressed"]
+[connection signal="pressed" from="UI/CropStorePanel/QuitButton" to="." method="_on_quit_button_pressed"]
+[connection signal="pressed" from="UI/PlayerBagPanel/QuitButton" to="." method="_on_quit_button_pressed"]
diff --git a/Network/TCPClient.gd b/Network/TCPClient.gd
new file mode 100644
index 0000000..a8bf71c
--- /dev/null
+++ b/Network/TCPClient.gd
@@ -0,0 +1,157 @@
+extends Node
+#一个基本的TCP客户端API
+class_name TCPClient
+
+signal connected_to_server#连接到服务器信号
+signal connection_failed#连接失败信号
+signal connection_closed#连接关闭信号
+signal data_received(data)#收到数据信号
+
+var tcp: StreamPeerTCP = StreamPeerTCP.new()
+var host: String = "127.0.0.1"
+var port: int = 4040
+var is_connected: bool = false
+var auto_reconnect: bool = true
+var reconnect_delay: float = 2.0
+
+# 缓冲区管理
+var buffer = ""
+
+func _ready():
+ pass
+
+func _process(_delta):
+ # 更新连接状态
+ tcp.poll()
+ _update_connection_status()
+ _check_for_data()
+
+
+func connect_to_server(custom_host = null, custom_port = null):
+ if custom_host != null:
+ host = custom_host
+ if custom_port != null:
+ port = custom_port
+
+ if tcp.get_status() != StreamPeerTCP.STATUS_CONNECTED:
+ tcp.disconnect_from_host()
+ print("连接到服务器: %s:%s" % [host, port])
+ var error = tcp.connect_to_host(host, port)
+ if error != OK:
+ print("连接错误: %s" % error)
+ emit_signal("connection_failed")
+
+
+func disconnect_from_server():
+ tcp.disconnect_from_host()
+ is_connected = false
+ emit_signal("connection_closed")
+
+
+func _update_connection_status():
+ var status = tcp.get_status()
+
+ match status:
+ StreamPeerTCP.STATUS_NONE:
+ if is_connected:
+ is_connected = false
+ print("连接已断开")
+ emit_signal("connection_closed")
+
+ if auto_reconnect:
+ var timer = get_tree().create_timer(reconnect_delay)
+ await timer.timeout
+ connect_to_server()
+
+ StreamPeerTCP.STATUS_CONNECTING:
+ pass
+
+ StreamPeerTCP.STATUS_CONNECTED:
+ if not is_connected:
+ is_connected = true
+ tcp.set_no_delay(true) # 禁用Nagle算法提高响应速度
+ print("已连接到服务器")
+ emit_signal("connected_to_server")
+
+ StreamPeerTCP.STATUS_ERROR:
+ is_connected = false
+ print("连接错误")
+ emit_signal("connection_failed")
+
+ if auto_reconnect:
+ var timer = get_tree().create_timer(reconnect_delay)
+ await timer.timeout
+ connect_to_server()
+
+
+func _check_for_data():
+ if tcp.get_status() == StreamPeerTCP.STATUS_CONNECTED and tcp.get_available_bytes() > 0:
+ var bytes = tcp.get_available_bytes()
+ var data = tcp.get_utf8_string(bytes)
+
+ # 将数据添加到缓冲区进行处理
+ buffer += data
+ _process_buffer()
+
+
+func _process_buffer():
+ # 处理缓冲区中的JSON消息
+ # 假设每条消息以换行符结尾
+ while "\n" in buffer:
+ var message_end = buffer.find("\n")
+ var message_text = buffer.substr(0, message_end)
+ buffer = buffer.substr(message_end + 1)
+
+ # 处理JSON数据
+ if message_text.strip_edges() != "":
+ var json = JSON.new()
+ var error = json.parse(message_text)
+
+ if error == OK:
+ var data = json.get_data()
+ #print("收到JSON数据: ", data)
+ emit_signal("data_received", data)
+ else:
+ # 非JSON格式数据,直接传递
+ #print("收到原始数据: ", message_text)
+ emit_signal("data_received", message_text)
+
+func send_data(data):
+ if not is_connected:
+ print("未连接,无法发送数据")
+ return false
+
+ var message: String
+
+ # 如果是字典/数组,转换为JSON
+ if typeof(data) == TYPE_DICTIONARY or typeof(data) == TYPE_ARRAY:
+ message = JSON.stringify(data) + "\n"
+ else:
+ # 否则简单转换为字符串
+ message = str(data) + "\n"
+
+ var result = tcp.put_data(message.to_utf8_buffer())
+ return result == OK
+
+func is_client_connected() -> bool:
+ return is_connected
+
+# 示例: 如何使用此客户端
+#
+# func _ready():
+# var client = TCPClient.new()
+# add_child(client)
+#
+# client.connected_to_server.connect(_on_connected)
+# client.connection_failed.connect(_on_connection_failed)
+# client.connection_closed.connect(_on_connection_closed)
+# client.data_received.connect(_on_data_received)
+#
+# client.connect_to_server("127.0.0.1", 9000)
+#
+# func _on_connected():
+# print("已连接")
+# client.send_data({"type": "greeting", "content": "Hello Server!"})
+#
+# func _on_data_received(data):
+# print("收到数据: ", data)
diff --git a/Network/TCPClient.gd.uid b/Network/TCPClient.gd.uid
new file mode 100644
index 0000000..0fb78b0
--- /dev/null
+++ b/Network/TCPClient.gd.uid
@@ -0,0 +1 @@
+uid://cylhhkh8ooxcu
diff --git a/Network/TCPNetworkManager.gd b/Network/TCPNetworkManager.gd
new file mode 100644
index 0000000..e1ed281
--- /dev/null
+++ b/Network/TCPNetworkManager.gd
@@ -0,0 +1,377 @@
+extends Panel
+
+# TCP客户端演示
+# 这个脚本展示如何在UI中使用TCPClient类
+
+# UI组件引用
+@onready var status_label = $StatusLabel
+@onready var message_input = $MessageInput
+@onready var send_button = $SendButton
+@onready var response_label = $Scroll/ResponseLabel
+@onready var connection_button = $ConnectionButton
+@onready var login_panel = $"/root/main/UI/LoginPanel"
+@onready var main_game = get_node("/root/main")
+
+# TCP客户端
+var client: TCPClient = TCPClient.new()
+
+# 服务器配置 - 支持多个服务器地址
+var server_configs = [
+ #{"host": "127.0.0.1", "port": 4040, "name": "本地服务器"},
+ #{"host": "192.168.1.110", "port": 4040, "name": "局域网服务器"},
+ {"host": "47.108.90.0", "port": 4040, "name": "公网服务器"}#成都内网穿透
+]
+
+var current_server_index = 0
+var auto_retry = true
+var retry_delay = 3.0
+
+func _ready():
+ # 创建TCP客户端实例
+ self.add_child(client)
+
+ # 连接信号
+ client.connected_to_server.connect(_on_connected)
+ client.connection_failed.connect(_on_connection_failed)
+ client.connection_closed.connect(_on_connection_closed)
+ client.data_received.connect(_on_data_received)
+
+ # 连接按钮事件
+ connection_button.pressed.connect(_on_connection_button_pressed)
+ send_button.pressed.connect(_on_send_button_pressed)
+
+ # 初始设置
+ status_label.text = "未连接"
+ response_label.text = "等待响应..."
+ connection_button.text = "连接"
+
+func _on_connected():
+ status_label.text = "已连接"
+ status_label.modulate = Color.GREEN
+ connection_button.text = "断开"
+
+ # 发送连接成功消息
+ client.send_data({
+ "type": "greeting",
+ "content": "你好,服务器!"
+ })
+
+ # 连接成功后立即请求作物数据
+ print("连接成功,正在请求最新作物数据...")
+ sendGetCropData()
+
+func _on_connection_failed():
+ status_label.text = "连接失败"
+ status_label.modulate = Color.RED
+ connection_button.text = "连接"
+
+ # 自动尝试下一个服务器
+ if auto_retry:
+ try_next_server()
+
+func _on_connection_closed():
+ status_label.text = "连接断开"
+ status_label.modulate = Color.RED
+ connection_button.text = "连接"
+
+ # 自动重连当前服务器
+ if auto_retry:
+ var timer = get_tree().create_timer(retry_delay)
+ await timer.timeout
+ if not client.is_client_connected():
+ _on_connection_button_pressed()
+
+func _on_data_received(data):
+ # 根据数据类型处理数据
+ response_label.text = "收到: %s" % JSON.stringify(data)
+ match typeof(data):
+
+ TYPE_DICTIONARY:
+ # 处理JSON对象
+ var message_type = data.get("type", "")
+
+ match message_type:
+ "ping":
+ return
+ "response":
+ # 显示服务器响应
+ if data.has("original"):
+ var original = data.get("original", {})
+ return
+ "login_response":
+ # 处理登录响应
+ var status = data.get("status", "")
+ var message = data.get("message", "")
+ var player_data = data.get("player_data", {})
+ if login_panel:
+ # 调用登录面板的响应处理方法
+ login_panel._on_login_response_received(status == "success", message, player_data)
+ "register_response":
+ # 处理注册响应
+ var status = data.get("status", "")
+ var message = data.get("message", "")
+ if login_panel:
+ # 调用登录面板的响应处理方法
+ login_panel._on_register_response_received(status == "success", message)
+ "verification_code_response":
+ # 处理验证码发送响应
+ var success = data.get("success", false)
+ var message = data.get("message", "")
+ if login_panel:
+ # 调用登录面板的验证码响应处理方法
+ login_panel._on_verification_code_response(success, message)
+ "verify_code_response":
+ # 处理验证码验证响应
+ var success = data.get("success", false)
+ var message = data.get("message", "")
+ if login_panel:
+ # 调用登录面板的验证码验证响应处理方法
+ login_panel._on_verify_code_response(success, message)
+ "crop_update":
+ # 处理作物生长更新
+ if main_game:
+ main_game._handle_crop_update(data)
+ "action_response":
+ # 处理玩家动作响应
+ if main_game:
+ main_game._handle_action_response(data)
+ "play_time_response":
+ # 处理玩家游玩时间响应
+ if main_game and main_game.has_method("_handle_play_time_response"):
+ main_game._handle_play_time_response(data)
+ "player_rankings_response":
+ # 处理玩家排行榜响应
+ if main_game and main_game.has_method("_handle_player_rankings_response"):
+ main_game._handle_player_rankings_response(data)
+ "crop_data_response":
+ # 处理作物数据响应
+ if main_game and main_game.has_method("_handle_crop_data_response"):
+ main_game._handle_crop_data_response(data)
+ "visit_player_response":
+ # 处理访问玩家响应
+ if main_game and main_game.has_method("_handle_visit_player_response"):
+ main_game._handle_visit_player_response(data)
+ "return_my_farm_response":
+ # 处理返回自己农场响应
+ if main_game and main_game.has_method("_handle_return_my_farm_response"):
+ main_game._handle_return_my_farm_response(data)
+ _:
+ # 显示其他类型的消息
+ return
+ _:
+ # 处理非JSON数据
+ return
+
+func _on_connection_button_pressed():
+ if client.is_client_connected():
+ # 断开连接
+ client.disconnect_from_server()
+ else:
+ # 连接服务器
+ status_label.text = "正在连接..."
+ client.connect_to_server(server_configs[current_server_index]["host"], server_configs[current_server_index]["port"])
+
+func _on_send_button_pressed():
+ if not client.is_client_connected():
+ status_label.text = "未连接,无法发送"
+ return
+
+ # 获取输入文本
+ var text = message_input.text.strip_edges()
+ if text.is_empty():
+ return
+
+ # 发送消息
+ client.send_data({
+ "type": "message",
+ "content": text,
+ "timestamp": Time.get_unix_time_from_system()
+ })
+
+ # 清空输入
+ message_input.text = ""
+
+#发送登录信息
+func sendLoginInfo(username, password):
+ client.send_data({
+ "type": "login",
+ "username": username,
+ "password": password
+ })
+
+#发送注册信息
+func sendRegisterInfo(username, password, farmname, player_name="", verification_code=""):
+ client.send_data({
+ "type": "register",
+ "username": username,
+ "password": password,
+ "farm_name": farmname,
+ "player_name": player_name,
+ "verification_code": verification_code
+ })
+
+#发送收获作物信息
+func sendHarvestCrop(lot_index):
+ if not client.is_client_connected():
+ return false
+
+ client.send_data({
+ "type": "harvest_crop",
+ "lot_index": lot_index,
+ "timestamp": Time.get_unix_time_from_system()
+ })
+ return true
+
+#发送种植作物信息
+func sendPlantCrop(lot_index, crop_name):
+ if not client.is_client_connected():
+ return false
+
+ client.send_data({
+ "type": "plant_crop",
+ "lot_index": lot_index,
+ "crop_name": crop_name,
+ "timestamp": Time.get_unix_time_from_system()
+ })
+ return true
+
+#发送开垦土地信息
+func sendDigGround(lot_index):
+ if not client.is_client_connected():
+ return false
+
+ client.send_data({
+ "type": "dig_ground",
+ "lot_index": lot_index,
+ "timestamp": Time.get_unix_time_from_system()
+ })
+ return true
+
+#发送购买种子信息
+func sendBuySeed(crop_name):
+ if not client.is_client_connected():
+ return false
+
+ client.send_data({
+ "type": "buy_seed",
+ "crop_name": crop_name,
+ "timestamp": Time.get_unix_time_from_system()
+ })
+ return true
+
+#发送获取游玩时间请求
+func sendGetPlayTime():
+ if not client.is_client_connected():
+ return false
+
+ client.send_data({
+ "type": "get_play_time"
+ })
+ return true
+
+#发送更新游玩时间请求
+func sendUpdatePlayTime():
+ if not client.is_client_connected():
+ return false
+
+ client.send_data({
+ "type": "update_play_time"
+ })
+ return true
+
+#发送获取玩家排行榜请求
+func sendGetPlayerRankings():
+ if not client.is_client_connected():
+ return false
+
+ client.send_data({
+ "type": "request_player_rankings"
+ })
+ return true
+
+#发送验证码请求
+func sendVerificationCodeRequest(qq_number):
+ if not client.is_client_connected():
+ return false
+
+ client.send_data({
+ "type": "request_verification_code",
+ "qq_number": qq_number,
+ "timestamp": Time.get_unix_time_from_system()
+ })
+ return true
+
+#发送验证码验证
+func sendVerifyCode(qq_number, code):
+ if not client.is_client_connected():
+ return false
+
+ client.send_data({
+ "type": "verify_code",
+ "qq_number": qq_number,
+ "code": code,
+ "timestamp": Time.get_unix_time_from_system()
+ })
+ return true
+
+#发送获取作物数据请求
+func sendGetCropData():
+ if not client.is_client_connected():
+ return false
+
+ client.send_data({
+ "type": "request_crop_data"
+ })
+ return true
+
+#发送访问玩家请求
+func sendVisitPlayer(target_username):
+ if not client.is_client_connected():
+ return false
+
+ client.send_data({
+ "type": "visit_player",
+ "target_username": target_username,
+ "timestamp": Time.get_unix_time_from_system()
+ })
+ return true
+
+#发送返回自己农场请求
+func sendReturnMyFarm():
+ if not client.is_client_connected():
+ return false
+
+ client.send_data({
+ "type": "return_my_farm",
+ "timestamp": Time.get_unix_time_from_system()
+ })
+ return true
+
+#检查是否连接到服务器
+func is_connected_to_server():
+ return client.is_client_connected()
+
+# 尝试连接下一个服务器
+func try_next_server():
+ current_server_index = (current_server_index + 1) % server_configs.size()
+ var config = server_configs[current_server_index]
+
+ status_label.text = "尝试连接 " + config["name"]
+ print("尝试连接服务器: ", config["name"], " (", config["host"], ":", config["port"], ")")
+
+ var timer = get_tree().create_timer(retry_delay)
+ await timer.timeout
+
+ if not client.is_client_connected():
+ client.connect_to_server(config["host"], config["port"])
+
+# 检查网络连接状态
+func check_network_status():
+ # 检查设备是否有网络连接
+ if OS.get_name() == "Android":
+ # 在Android上检查网络状态
+ status_label.text = "检查网络状态..."
+
+ # 尝试连接到当前配置的服务器
+ if not client.is_client_connected():
+ _on_connection_button_pressed()
diff --git a/Network/TCPNetworkManager.gd.uid b/Network/TCPNetworkManager.gd.uid
new file mode 100644
index 0000000..d437dbf
--- /dev/null
+++ b/Network/TCPNetworkManager.gd.uid
@@ -0,0 +1 @@
+uid://q1f3tubmdsrk
diff --git a/Network/TCPNetworkManager.tscn b/Network/TCPNetworkManager.tscn
new file mode 100644
index 0000000..6623c45
--- /dev/null
+++ b/Network/TCPNetworkManager.tscn
@@ -0,0 +1,69 @@
+[gd_scene load_steps=2 format=3 uid="uid://cpxiaqh0y6a5d"]
+
+[ext_resource type="Script" uid="uid://q1f3tubmdsrk" path="res://Network/TCPNetworkManager.gd" id="1_tfd57"]
+
+[node name="TCPNetworkManager" type="Panel"]
+script = ExtResource("1_tfd57")
+
+[node name="Scroll" type="ScrollContainer" parent="."]
+layout_mode = 0
+offset_left = 1.0
+offset_top = 142.0
+offset_right = 401.0
+offset_bottom = 647.0
+horizontal_scroll_mode = 0
+
+[node name="ResponseLabel" type="Label" parent="Scroll"]
+custom_minimum_size = Vector2(400, 500)
+layout_mode = 2
+theme_override_colors/font_outline_color = Color(1, 1, 1, 1)
+theme_override_font_sizes/font_size = 20
+text = "回应"
+autowrap_mode = 3
+
+[node name="Title" type="Label" parent="."]
+layout_mode = 0
+offset_right = 400.0
+offset_bottom = 42.0
+theme_override_font_sizes/font_size = 30
+text = "TCP网络调试面板"
+horizontal_alignment = 1
+
+[node name="ColorRect" type="ColorRect" parent="."]
+layout_mode = 0
+offset_right = 400.0
+offset_bottom = 647.0
+color = Color(0.104753, 0.146763, 0.23013, 0.427451)
+
+[node name="StatusLabel" type="Label" parent="."]
+layout_mode = 0
+offset_top = 100.0
+offset_right = 120.0
+offset_bottom = 142.0
+theme_override_font_sizes/font_size = 30
+text = "连接状态"
+
+[node name="MessageInput" type="LineEdit" parent="."]
+layout_mode = 0
+offset_left = 136.0
+offset_top = 50.0
+offset_right = 400.0
+offset_bottom = 100.0
+theme_override_font_sizes/font_size = 30
+
+[node name="SendButton" type="Button" parent="."]
+layout_mode = 0
+offset_left = 68.0
+offset_top = 50.0
+offset_right = 136.0
+offset_bottom = 100.0
+theme_override_font_sizes/font_size = 30
+text = "发送"
+
+[node name="ConnectionButton" type="Button" parent="."]
+layout_mode = 0
+offset_top = 50.0
+offset_right = 68.0
+offset_bottom = 100.0
+theme_override_font_sizes/font_size = 30
+text = "连接"
diff --git a/Server/JsonEdit/README.md b/Server/JsonEdit/README.md
new file mode 100644
index 0000000..ebd3a7a
--- /dev/null
+++ b/Server/JsonEdit/README.md
@@ -0,0 +1,100 @@
+# JSON 批量编辑器
+
+一个简洁强大的JSON编辑工具,专门用于批量添加键值对到JSON文件中的所有对象。
+
+## 🚀 功能特点
+
+- **批量添加属性**: 一键为JSON中所有对象添加新的键值对
+- **智能类型识别**: 自动识别并转换数据类型
+- **支持所有JSON数据类型**: 字符串、数字、布尔值、对象、数组、null
+- **文件上传**: 支持JSON文件拖拽上传
+- **即时下载**: 编辑完成后立即下载修改后的JSON文件
+- **无需服务器**: 纯前端实现,直接在浏览器中运行
+
+## 📋 支持的数据类型
+
+| 类型 | 输入示例 | 转换结果 |
+|------|----------|----------|
+| 字符串 | `hello world` | `"hello world"` |
+| 整数 | `123` | `123` |
+| 小数 | `3.14` | `3.14` |
+| 布尔值 | `true` 或 `false` | `true` 或 `false` |
+| 空值 | `null` | `null` |
+| 对象 | `{"key": "value"}` | `{"key": "value"}` |
+| 数组 | `[1, 2, 3]` | `[1, 2, 3]` |
+| 空字符串 | *(留空)* | `""` |
+
+## 🎯 使用方法
+
+### 1. 加载JSON数据
+- **方法一**: 点击"上传JSON文件"按钮选择文件
+- **方法二**: 直接在编辑器中粘贴JSON数据
+- **方法三**: 点击"加载示例数据"使用预设数据
+
+### 2. 批量添加属性
+1. 在"键名"字段输入要添加的属性名,如: `能否购买`
+2. 在"键值"字段输入属性值,如: `true`
+3. 点击"批量添加到所有对象"按钮
+4. 系统会自动为JSON中的每个对象添加该属性
+
+### 3. 下载结果
+点击"下载修改后的JSON"按钮保存编辑后的文件
+
+## 💡 使用示例
+
+### 原始JSON:
+```json
+{
+ "小麦": {
+ "花费": 120,
+ "收益": 100,
+ "品质": "普通"
+ },
+ "稻谷": {
+ "花费": 100,
+ "收益": 120,
+ "品质": "普通"
+ }
+}
+```
+
+### 添加属性: 键名=`能否购买`, 键值=`true`
+
+### 结果JSON:
+```json
+{
+ "小麦": {
+ "花费": 120,
+ "收益": 100,
+ "品质": "普通",
+ "能否购买": true
+ },
+ "稻谷": {
+ "花费": 100,
+ "收益": 120,
+ "品质": "普通",
+ "能否购买": true
+ }
+}
+```
+
+## 🔧 快速开始
+
+1. 直接在浏览器中打开 `templates/json_editor.html` 文件
+2. 无需安装任何依赖或服务器
+3. 开始使用批量编辑功能
+
+## ⚠️ 注意事项
+
+- 工具会递归处理嵌套对象,为所有找到的对象添加指定属性
+- 数组元素如果是对象,也会被添加属性
+- 确保JSON格式正确,否则无法处理
+- 修改前建议备份原始文件
+
+## 🎨 界面说明
+
+- **左侧边栏**: 文件操作、批量编辑功能、快速示例
+- **右侧编辑区**: JSON数据显示和编辑
+- **智能提示**: 实时显示操作结果和错误信息
+
+这个工具特别适合游戏开发、配置文件管理等需要批量修改JSON数据的场景。
\ No newline at end of file
diff --git a/Server/JsonEdit/example_formats.md b/Server/JsonEdit/example_formats.md
new file mode 100644
index 0000000..cd836a7
--- /dev/null
+++ b/Server/JsonEdit/example_formats.md
@@ -0,0 +1,65 @@
+# JSON格式化示例
+
+以下展示三种不同的JSON格式化效果:
+
+## 原始数据
+```json
+{"小麦":{"花费":120,"收益":100,"品质":"普通"},"稻谷":{"花费":100,"收益":120,"品质":"普通"}}
+```
+
+## 1. 标准格式化(2空格缩进)
+```json
+{
+ "小麦": {
+ "花费": 120,
+ "收益": 100,
+ "品质": "普通"
+ },
+ "稻谷": {
+ "花费": 100,
+ "收益": 120,
+ "品质": "普通"
+ }
+}
+```
+
+## 2. 最小化(压缩)
+```json
+{"小麦":{"花费":120,"收益":100,"品质":"普通"},"稻谷":{"花费":100,"收益":120,"品质":"普通"}}
+```
+
+## 3. 一行化(一个对象一行)
+```json
+{
+ "小麦": {"花费":120,"收益":100,"品质":"普通"},
+ "稻谷": {"花费":100,"收益":120,"品质":"普通"}
+}
+```
+
+## 使用场景
+
+- **标准格式化**: 适合阅读和编辑,开发时使用
+- **最小化**: 适合网络传输,节省带宽
+- **一行化**: 适合比较不同对象,每行一个对象便于查看差异
+
+## 批量添加属性示例
+
+添加键名: `能否购买`, 键值: `true`
+
+### 结果:
+```json
+{
+ "小麦": {
+ "花费": 120,
+ "收益": 100,
+ "品质": "普通",
+ "能否购买": true
+ },
+ "稻谷": {
+ "花费": 100,
+ "收益": 120,
+ "品质": "普通",
+ "能否购买": true
+ }
+}
+```
\ No newline at end of file
diff --git a/Server/JsonEdit/json_editor.py b/Server/JsonEdit/json_editor.py
new file mode 100644
index 0000000..eac0890
--- /dev/null
+++ b/Server/JsonEdit/json_editor.py
@@ -0,0 +1,267 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+
+from flask import Flask, request, jsonify, render_template, send_file
+import json
+import os
+from datetime import datetime
+
+app = Flask(__name__)
+
+class JSONFormatter:
+ """JSON格式化工具类"""
+
+ @staticmethod
+ def format_standard(data, indent=2):
+ """标准格式化 - 带缩进的可读格式"""
+ return json.dumps(data, ensure_ascii=False, indent=indent)
+
+ @staticmethod
+ def minify(data):
+ """最小化 - 压缩去除空格"""
+ return json.dumps(data, ensure_ascii=False, separators=(',', ':'))
+
+ @staticmethod
+ def one_line_per_object(data):
+ """一行化 - 每个对象/元素占一行"""
+ if isinstance(data, list):
+ # 如果是数组,每个元素占一行
+ lines = ['[']
+ for i, item in enumerate(data):
+ comma = ',' if i < len(data) - 1 else ''
+ lines.append(f' {json.dumps(item, ensure_ascii=False)}{comma}')
+ lines.append(']')
+ return '\n'.join(lines)
+
+ elif isinstance(data, dict):
+ # 如果是对象,每个键值对占一行
+ lines = ['{']
+ keys = list(data.keys())
+ for i, key in enumerate(keys):
+ comma = ',' if i < len(keys) - 1 else ''
+ value_str = json.dumps(data[key], ensure_ascii=False)
+ lines.append(f' {json.dumps(key, ensure_ascii=False)}: {value_str}{comma}')
+ lines.append('}')
+ return '\n'.join(lines)
+
+ else:
+ # 基本类型直接返回
+ return json.dumps(data, ensure_ascii=False)
+
+@app.route('/')
+def index():
+ """主页"""
+ return render_template('json_editor.html')
+
+@app.route('/api/format', methods=['POST'])
+def format_json():
+ """JSON格式化API"""
+ try:
+ data = request.get_json()
+ content = data.get('content', '')
+ format_type = data.get('format_type', 'standard') # standard, minify, oneline
+
+ if not content.strip():
+ return jsonify({'success': False, 'message': '请提供JSON内容'})
+
+ # 解析JSON
+ try:
+ json_data = json.loads(content)
+ except json.JSONDecodeError as e:
+ return jsonify({'success': False, 'message': f'JSON格式错误: {str(e)}'})
+
+ # 根据类型格式化
+ formatter = JSONFormatter()
+
+ if format_type == 'standard':
+ formatted = formatter.format_standard(json_data)
+ message = 'JSON标准格式化完成'
+ elif format_type == 'minify':
+ formatted = formatter.minify(json_data)
+ message = 'JSON最小化完成'
+ elif format_type == 'oneline':
+ formatted = formatter.one_line_per_object(json_data)
+ message = 'JSON一行化格式完成'
+ else:
+ return jsonify({'success': False, 'message': '不支持的格式化类型'})
+
+ return jsonify({
+ 'success': True,
+ 'message': message,
+ 'formatted': formatted,
+ 'original_length': len(content),
+ 'formatted_length': len(formatted)
+ })
+
+ except Exception as e:
+ return jsonify({'success': False, 'message': f'处理错误: {str(e)}'})
+
+@app.route('/api/batch_add', methods=['POST'])
+def batch_add_property():
+ """批量添加属性API"""
+ try:
+ data = request.get_json()
+ content = data.get('content', '')
+ key_name = data.get('key_name', '')
+ key_value = data.get('key_value', '')
+
+ if not content.strip():
+ return jsonify({'success': False, 'message': '请提供JSON内容'})
+
+ if not key_name.strip():
+ return jsonify({'success': False, 'message': '请提供键名'})
+
+ # 解析JSON
+ try:
+ json_data = json.loads(content)
+ except json.JSONDecodeError as e:
+ return jsonify({'success': False, 'message': f'JSON格式错误: {str(e)}'})
+
+ # 智能解析键值
+ parsed_value = parse_value(key_value)
+
+ # 批量添加属性
+ count = add_property_to_all_objects(json_data, key_name, parsed_value)
+
+ # 格式化输出
+ formatted = JSONFormatter.format_standard(json_data)
+
+ return jsonify({
+ 'success': True,
+ 'message': f'成功为 {count} 个对象添加了属性 "{key_name}": {json.dumps(parsed_value, ensure_ascii=False)}',
+ 'formatted': formatted,
+ 'count': count
+ })
+
+ except Exception as e:
+ return jsonify({'success': False, 'message': f'处理错误: {str(e)}'})
+
+def parse_value(value_str):
+ """智能解析值的类型"""
+ if value_str == '':
+ return ''
+
+ # null
+ if value_str.lower() == 'null':
+ return None
+
+ # boolean
+ if value_str.lower() == 'true':
+ return True
+ if value_str.lower() == 'false':
+ return False
+
+ # number
+ try:
+ if '.' in value_str:
+ return float(value_str)
+ else:
+ return int(value_str)
+ except ValueError:
+ pass
+
+ # JSON object or array
+ if (value_str.startswith('{') and value_str.endswith('}')) or \
+ (value_str.startswith('[') and value_str.endswith(']')):
+ try:
+ return json.loads(value_str)
+ except json.JSONDecodeError:
+ pass
+
+ # string
+ return value_str
+
+def add_property_to_all_objects(obj, key, value):
+ """递归为所有对象添加属性"""
+ count = 0
+
+ def traverse(current):
+ nonlocal count
+ if isinstance(current, dict):
+ current[key] = value
+ count += 1
+ # 继续递归处理嵌套对象
+ for val in current.values():
+ if isinstance(val, (dict, list)) and val != current:
+ traverse(val)
+ elif isinstance(current, list):
+ for item in current:
+ traverse(item)
+
+ traverse(obj)
+ return count
+
+@app.route('/api/validate', methods=['POST'])
+def validate_json():
+ """JSON验证API"""
+ try:
+ data = request.get_json()
+ content = data.get('content', '')
+
+ if not content.strip():
+ return jsonify({'success': False, 'message': '请提供JSON内容'})
+
+ try:
+ json_data = json.loads(content)
+ return jsonify({
+ 'success': True,
+ 'message': 'JSON格式正确 ✓',
+ 'valid': True
+ })
+ except json.JSONDecodeError as e:
+ return jsonify({
+ 'success': False,
+ 'message': f'JSON格式错误: {str(e)}',
+ 'valid': False,
+ 'error': str(e)
+ })
+
+ except Exception as e:
+ return jsonify({'success': False, 'message': f'验证错误: {str(e)}'})
+
+@app.route('/api/download', methods=['POST'])
+def download_json():
+ """下载JSON文件"""
+ try:
+ data = request.get_json()
+ content = data.get('content', '')
+ format_type = data.get('format_type', 'standard')
+
+ if not content.strip():
+ return jsonify({'success': False, 'message': '没有可下载的内容'})
+
+ # 验证JSON格式
+ try:
+ json_data = json.loads(content)
+ except json.JSONDecodeError as e:
+ return jsonify({'success': False, 'message': f'JSON格式错误: {str(e)}'})
+
+ # 格式化
+ formatter = JSONFormatter()
+ if format_type == 'minify':
+ formatted_content = formatter.minify(json_data)
+ elif format_type == 'oneline':
+ formatted_content = formatter.one_line_per_object(json_data)
+ else:
+ formatted_content = formatter.format_standard(json_data)
+
+ # 生成文件名
+ timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
+ filename = f"edited_json_{format_type}_{timestamp}.json"
+
+ # 创建临时文件
+ temp_file = f"temp_{filename}"
+ with open(temp_file, 'w', encoding='utf-8') as f:
+ f.write(formatted_content)
+
+ return send_file(temp_file, as_attachment=True, download_name=filename)
+
+ except Exception as e:
+ return jsonify({'success': False, 'message': f'下载错误: {str(e)}'})
+
+if __name__ == '__main__':
+ # 确保templates目录存在
+ os.makedirs('templates', exist_ok=True)
+
+ # 运行应用
+ app.run(debug=True, host='0.0.0.0', port=5000)
diff --git a/Server/JsonEdit/requirements.txt b/Server/JsonEdit/requirements.txt
new file mode 100644
index 0000000..c4988fb
--- /dev/null
+++ b/Server/JsonEdit/requirements.txt
@@ -0,0 +1,2 @@
+Flask==2.3.3
+Werkzeug==2.3.7
\ No newline at end of file
diff --git a/Server/JsonEdit/templates/json_editor.html b/Server/JsonEdit/templates/json_editor.html
new file mode 100644
index 0000000..fbe7316
--- /dev/null
+++ b/Server/JsonEdit/templates/json_editor.html
@@ -0,0 +1,627 @@
+
+
+
+
+
+ 简易JSON编辑器 - 批量添加键值
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Server/QQEmailSend.py b/Server/QQEmailSend.py
new file mode 100644
index 0000000..6728fa4
--- /dev/null
+++ b/Server/QQEmailSend.py
@@ -0,0 +1,337 @@
+import smtplib
+from email.mime.text import MIMEText
+from email.mime.multipart import MIMEMultipart
+from email.mime.application import MIMEApplication
+from email.header import Header
+import random
+import string
+import json
+import os
+
+# 邮件发送配置
+SENDER_EMAIL = '3205788256@qq.com' # 发件人邮箱
+SENDER_AUTH_CODE = 'szcaxvbftusqddhi' # 授权码
+SMTP_SERVER = 'smtp.qq.com' # QQ邮箱SMTP服务器
+SMTP_PORT = 465 # QQ邮箱SSL端口
+
+# 验证码缓存文件
+VERIFICATION_CACHE_FILE = os.path.join("config", "verification_codes.json")
+
+class QQMailAPI:
+ """QQ邮箱发送邮件API类"""
+
+ def __init__(self, sender_email, authorization_code):
+ """
+ 初始化邮箱配置
+ :param sender_email: 发送方QQ邮箱地址
+ :param authorization_code: QQ邮箱授权码
+ """
+ self.sender_email = sender_email
+ self.authorization_code = authorization_code
+ self.smtp_server = 'smtp.qq.com'
+ self.smtp_port = 465 # SSL端口
+
+ def send_text_email(self, receiver_email, subject, content, cc_emails=None):
+ """
+ 发送纯文本邮件
+ :param receiver_email: 接收方邮箱地址(单个)
+ :param subject: 邮件主题
+ :param content: 邮件正文内容
+ :param cc_emails: 抄送邮箱列表
+ :return: 发送成功返回True,失败返回False
+ """
+ try:
+ # 创建邮件对象
+ message = MIMEText(content, 'plain', 'utf-8')
+ message['From'] = Header(self.sender_email, 'utf-8')
+ message['To'] = Header(receiver_email, 'utf-8')
+ message['Subject'] = Header(subject, 'utf-8')
+
+ # 添加抄送
+ if cc_emails:
+ message['Cc'] = Header(",".join(cc_emails), 'utf-8')
+ all_receivers = [receiver_email] + cc_emails
+ else:
+ all_receivers = [receiver_email]
+
+ # 连接SMTP服务器并发送邮件
+ with smtplib.SMTP_SSL(self.smtp_server, self.smtp_port) as server:
+ server.login(self.sender_email, self.authorization_code)
+ server.sendmail(self.sender_email, all_receivers, message.as_string())
+
+ print(f"邮件发送成功:主题='{subject}', 收件人='{receiver_email}'")
+ return True
+ except Exception as e:
+ print(f"邮件发送失败:{str(e)}")
+ return False
+
+ def send_html_email(self, receiver_email, subject, html_content, cc_emails=None, attachments=None):
+ """
+ 发送HTML格式邮件,可带附件
+ :param receiver_email: 接收方邮箱地址(单个)
+ :param subject: 邮件主题
+ :param html_content: HTML格式的邮件正文
+ :param cc_emails: 抄送邮箱列表
+ :param attachments: 附件文件路径列表
+ :return: 发送成功返回True,失败返回False
+ """
+ try:
+ # 创建带附件的邮件对象
+ message = MIMEMultipart()
+ message['From'] = Header(self.sender_email, 'utf-8')
+ message['To'] = Header(receiver_email, 'utf-8')
+ message['Subject'] = Header(subject, 'utf-8')
+
+ # 添加抄送
+ if cc_emails:
+ message['Cc'] = Header(",".join(cc_emails), 'utf-8')
+ all_receivers = [receiver_email] + cc_emails
+ else:
+ all_receivers = [receiver_email]
+
+ # 添加HTML正文
+ message.attach(MIMEText(html_content, 'html', 'utf-8'))
+
+ # 添加附件
+ if attachments:
+ for file_path in attachments:
+ try:
+ with open(file_path, 'rb') as file:
+ attachment = MIMEApplication(file.read(), _subtype="octet-stream")
+ attachment.add_header('Content-Disposition', 'attachment', filename=file_path.split("/")[-1])
+ message.attach(attachment)
+ except Exception as e:
+ print(f"添加附件失败 {file_path}: {str(e)}")
+
+ # 连接SMTP服务器并发送邮件
+ with smtplib.SMTP_SSL(self.smtp_server, self.smtp_port) as server:
+ server.login(self.sender_email, self.authorization_code)
+ server.sendmail(self.sender_email, all_receivers, message.as_string())
+
+ print(f"HTML邮件发送成功:主题='{subject}', 收件人='{receiver_email}'")
+ return True
+ except Exception as e:
+ print(f"HTML邮件发送失败:{str(e)}")
+ return False
+
+class EmailVerification:
+ @staticmethod
+ def generate_verification_code(length=6):
+ """
+ 生成指定长度的随机验证码
+
+ 参数:
+ length (int): 验证码长度,默认6位
+
+ 返回:
+ str: 生成的验证码
+ """
+ # 生成包含大写字母和数字的验证码
+ chars = string.ascii_uppercase + string.digits
+ return ''.join(random.choice(chars) for _ in range(length))
+
+ @staticmethod
+ def send_verification_email(qq_number, verification_code):
+ """
+ 发送验证码邮件到QQ邮箱
+
+ 参数:
+ qq_number (str): 接收者QQ号
+ verification_code (str): 验证码
+
+ 返回:
+ bool: 发送成功返回True,否则返回False
+ str: 成功或错误信息
+ """
+ receiver_email = f"{qq_number}@qq.com"
+
+ # 创建邮件内容
+ message = MIMEText(f'''
+
+
+
+
萌芽农场 - 邮箱验证码
+
亲爱的玩家,您好!
+
您正在注册萌芽农场游戏账号,您的验证码是:
+
+ {verification_code}
+
+
该验证码有效期为5分钟,请勿泄露给他人。
+
如果这不是您本人的操作,请忽略此邮件。
+
+ 本邮件由系统自动发送,请勿直接回复。
+
+
+
+
+ ''', 'html', 'utf-8')
+
+ # 修正From头格式,符合QQ邮箱的要求
+ message['From'] = SENDER_EMAIL
+ message['To'] = receiver_email
+ message['Subject'] = Header('【萌芽农场】注册验证码', 'utf-8')
+
+ try:
+ # 使用SSL/TLS连接而不是STARTTLS
+ smtp_obj = smtplib.SMTP_SSL(SMTP_SERVER, 465)
+ smtp_obj.login(SENDER_EMAIL, SENDER_AUTH_CODE)
+ smtp_obj.sendmail(SENDER_EMAIL, [receiver_email], message.as_string())
+ smtp_obj.quit()
+ return True, "验证码发送成功"
+ except Exception as e:
+ return False, f"发送验证码失败: {str(e)}"
+
+ @staticmethod
+ def save_verification_code(qq_number, verification_code, expiry_time=300):
+ """
+ 保存验证码到缓存文件
+
+ 参数:
+ qq_number (str): QQ号
+ verification_code (str): 验证码
+ expiry_time (int): 过期时间(秒),默认5分钟
+
+ 返回:
+ bool: 保存成功返回True,否则返回False
+ """
+ import time
+
+ # 创建目录(如果不存在)
+ os.makedirs(os.path.dirname(VERIFICATION_CACHE_FILE), exist_ok=True)
+
+ # 读取现有的验证码数据
+ verification_data = {}
+ if os.path.exists(VERIFICATION_CACHE_FILE):
+ try:
+ with open(VERIFICATION_CACHE_FILE, 'r', encoding='utf-8') as file:
+ verification_data = json.load(file)
+ except:
+ verification_data = {}
+
+ # 添加新的验证码
+ expire_at = time.time() + expiry_time
+ verification_data[qq_number] = {
+ "code": verification_code,
+ "expire_at": expire_at
+ }
+
+ # 保存到文件
+ try:
+ with open(VERIFICATION_CACHE_FILE, 'w', encoding='utf-8') as file:
+ json.dump(verification_data, file, indent=2, ensure_ascii=False)
+ return True
+ except Exception as e:
+ print(f"保存验证码失败: {str(e)}")
+ return False
+
+ @staticmethod
+ def verify_code(qq_number, input_code):
+ """
+ 验证用户输入的验证码
+
+ 参数:
+ qq_number (str): QQ号
+ input_code (str): 用户输入的验证码
+
+ 返回:
+ bool: 验证成功返回True,否则返回False
+ str: 成功或错误信息
+ """
+ import time
+
+ # 检查缓存文件是否存在
+ if not os.path.exists(VERIFICATION_CACHE_FILE):
+ return False, "验证码不存在或已过期"
+
+ # 读取验证码数据
+ try:
+ with open(VERIFICATION_CACHE_FILE, 'r', encoding='utf-8') as file:
+ verification_data = json.load(file)
+ except:
+ return False, "验证码数据损坏"
+
+ # 检查该QQ号是否有验证码
+ if qq_number not in verification_data:
+ return False, "验证码不存在,请重新获取"
+
+ # 获取存储的验证码信息
+ code_info = verification_data[qq_number]
+ stored_code = code_info.get("code", "")
+ expire_at = code_info.get("expire_at", 0)
+
+ # 检查验证码是否过期
+ current_time = time.time()
+ if current_time > expire_at:
+ # 移除过期的验证码
+ del verification_data[qq_number]
+ with open(VERIFICATION_CACHE_FILE, 'w', encoding='utf-8') as file:
+ json.dump(verification_data, file, indent=2, ensure_ascii=False)
+ return False, "验证码已过期,请重新获取"
+
+ # 验证码比较(不区分大小写)
+ if input_code.upper() == stored_code.upper():
+ # 验证成功后移除该验证码
+ del verification_data[qq_number]
+ with open(VERIFICATION_CACHE_FILE, 'w', encoding='utf-8') as file:
+ json.dump(verification_data, file, indent=2, ensure_ascii=False)
+ return True, "验证码正确"
+ else:
+ return False, "验证码错误"
+
+ @staticmethod
+ def clean_expired_codes():
+ """
+ 清理过期的验证码
+ """
+ import time
+
+ if not os.path.exists(VERIFICATION_CACHE_FILE):
+ return
+
+ try:
+ with open(VERIFICATION_CACHE_FILE, 'r', encoding='utf-8') as file:
+ verification_data = json.load(file)
+
+ current_time = time.time()
+ removed_keys = []
+
+ # 找出过期的验证码
+ for qq_number, code_info in verification_data.items():
+ expire_at = code_info.get("expire_at", 0)
+ if current_time > expire_at:
+ removed_keys.append(qq_number)
+
+ # 移除过期的验证码
+ for key in removed_keys:
+ del verification_data[key]
+
+ # 保存更新后的数据
+ with open(VERIFICATION_CACHE_FILE, 'w', encoding='utf-8') as file:
+ json.dump(verification_data, file, indent=2, ensure_ascii=False)
+
+ except Exception as e:
+ print(f"清理过期验证码失败: {str(e)}")
+
+
+# 测试邮件发送
+if __name__ == "__main__":
+ # 清理过期验证码
+ EmailVerification.clean_expired_codes()
+
+ # 生成验证码
+ test_qq = input("请输入测试QQ号: ")
+ verification_code = EmailVerification.generate_verification_code()
+ print(f"生成的验证码: {verification_code}")
+
+ # 发送测试邮件
+ success, message = EmailVerification.send_verification_email(test_qq, verification_code)
+ print(f"发送结果: {success}, 消息: {message}")
+
+ if success:
+ # 保存验证码
+ EmailVerification.save_verification_code(test_qq, verification_code)
+
+ # 测试验证
+ test_input = input("请输入收到的验证码: ")
+ verify_success, verify_message = EmailVerification.verify_code(test_qq, test_input)
+ print(f"验证结果: {verify_success}, 消息: {verify_message}")
\ No newline at end of file
diff --git a/Server/QQEmailSend.zip b/Server/QQEmailSend.zip
new file mode 100644
index 0000000..e520114
Binary files /dev/null and b/Server/QQEmailSend.zip differ
diff --git a/Server/TCPGameServer.py b/Server/TCPGameServer.py
new file mode 100644
index 0000000..3ce4008
--- /dev/null
+++ b/Server/TCPGameServer.py
@@ -0,0 +1,1519 @@
+from TCPServer import TCPServer
+import time
+import json
+
+server_host: str = "0.0.0.0"
+server_port: int = 4040
+buffer_size: int = 4096
+
+#由于方法数量众多,所以将方法分组
+#1.服务端对本地的操作
+#2.服务端对客户端的操作
+
+class TCPGameServer(TCPServer):
+ #初始化TCP游戏服务器
+ def __init__(self, server_host=server_host, server_port=server_port, buffer_size=buffer_size):
+ super().__init__(server_host, server_port, buffer_size)
+ self.user_data = {} # 存储用户相关数据
+ self.crop_timer = None # 作物生长计时器
+ self.log('INFO', "TCP游戏服务器初始化", 'SERVER')
+
+ # 启动作物生长计时器
+ self.start_crop_growth_timer()
+
+
+ #检查用户是否已登录的通用方法
+ def _check_user_logged_in(self, client_id, action_name, action_type=None):
+ """
+ 检查用户是否已登录的通用方法
+
+ 参数:
+ client_id (str): 客户端ID
+ action_name (str): 操作名称,用于日志记录
+ action_type (str, optional): 操作类型,用于响应消息
+
+ 返回:
+ tuple: (bool, response)
+ - bool: True表示已登录,False表示未登录
+ - response: 如果未登录,返回发送给客户端的错误响应,否则为None
+ """
+ if client_id not in self.user_data or not self.user_data[client_id].get("logged_in", False):
+ self.log('WARNING', f"未登录用户 {client_id} 尝试{action_name}", 'SERVER')
+
+ # 构建响应
+ response = {
+ "success": False,
+ "message": "您需要先登录才能执行此操作"
+ }
+
+ # 如果提供了action_type,添加到响应中
+ if action_type:
+ response["type"] = "action_response"
+ response["action_type"] = action_type
+ else:
+ # 否则使用通用的响应类型
+ response["type"] = f"{action_name}_response"
+
+ return False, response
+
+ # 用户已登录
+ return True, None
+
+
+
+ #从JSON文件加载玩家数据
+ def load_player_data(self, account_id):
+ """
+ 从game_saves文件夹加载玩家数据
+
+ 参数:
+ account_id (str): 玩家账号ID
+
+ 返回:
+ dict: 玩家数据字典,如果文件不存在则返回None
+ """
+ import os
+
+ file_path = os.path.join("game_saves", f"{account_id}.json")
+
+ try:
+ if os.path.exists(file_path):
+ with open(file_path, 'r', encoding='utf-8') as file:
+ player_data = json.load(file)
+ #self.log('INFO', f"已加载玩家 {account_id} 的数据", 'SERVER')
+ return player_data
+ else:
+ #self.log('WARNING', f"玩家 {account_id} 的数据文件不存在", 'SERVER')
+ return None
+ except Exception as e:
+ #self.log('ERROR', f"读取玩家 {account_id} 的数据时出错: {str(e)}", 'SERVER')
+ return None
+
+ #通用加载玩家数据方法,带错误处理
+ def _load_player_data_with_check(self, client_id, action_type=None):
+ """
+ 加载玩家数据并进行错误检查的通用方法
+
+ 参数:
+ client_id (str): 客户端ID
+ action_type (str, optional): 操作类型,用于错误响应
+
+ 返回:
+ tuple: (player_data, username, response)
+ - player_data: 成功加载的玩家数据,如果加载失败则为None
+ - username: 玩家用户名
+ - response: 如果加载失败,返回发送给客户端的错误响应,否则为None
+ """
+ username = self.user_data[client_id]["username"]
+ player_data = self.load_player_data(username)
+
+ if not player_data:
+ self.log('ERROR', f"无法加载玩家 {username} 的数据", 'SERVER')
+
+ # 构建错误响应
+ response = {
+ "success": False,
+ "message": "无法加载玩家数据"
+ }
+
+ # 如果提供了action_type,添加到响应中
+ if action_type:
+ response["type"] = "action_response"
+ response["action_type"] = action_type
+ else:
+ # 否则使用通用的响应类型
+ response["type"] = "data_response"
+
+ return None, username, response
+
+ # 成功加载玩家数据
+ return player_data, username, None
+
+
+ #保存玩家数据到JSON文件
+ def save_player_data(self, account_id, player_data):
+ """
+ 保存玩家数据到game_saves文件夹
+
+ 参数:
+ account_id (str): 玩家账号ID
+ player_data (dict): 玩家数据字典
+
+ 返回:
+ bool: 保存成功返回True,否则返回False
+ """
+ import os
+
+ file_path = os.path.join("game_saves", f"{account_id}.json")
+
+ try:
+ with open(file_path, 'w', encoding='utf-8') as file:
+ json.dump(player_data, file, indent=2, ensure_ascii=False)
+ #self.log('INFO', f"已保存玩家 {account_id} 的数据", 'SERVER')
+ return True
+ except Exception as e:
+ self.log('ERROR', f"保存玩家 {account_id} 的数据时出错: {str(e)}", 'SERVER')
+ return False
+
+
+ #更新作物生长状态
+ def update_crops_growth(self):
+ """
+ 更新所有玩家的作物生长状态
+ 每秒钟对有作物的地块增加生长时间
+ 并向在线玩家推送更新
+ """
+ import os
+ import glob
+
+ # 获取所有玩家存档文件
+ save_files = glob.glob(os.path.join("game_saves", "*.json"))
+
+ for save_file in save_files:
+ try:
+ # 从文件名提取账号ID
+ account_id = os.path.basename(save_file).split('.')[0]
+
+ # 加载玩家数据
+ player_data = self.load_player_data(account_id)
+ if not player_data:
+ continue
+
+ # 检查是否有作物需要更新
+ growth_updated = False
+
+ # 遍历每个农场地块
+ for farm_lot in player_data.get("farm_lots", []):
+ # 如果地块有作物且未死亡
+ if farm_lot.get("crop_type") and farm_lot.get("is_planted") and not farm_lot.get("is_dead") and farm_lot["grow_time"] < farm_lot["max_grow_time"]:
+ # 增加生长时间
+ farm_lot["grow_time"] += 1
+ growth_updated = True
+
+ # 如果有作物更新,保存玩家数据
+ if growth_updated:
+ self.save_player_data(account_id, player_data)
+
+ # 向在线玩家推送更新
+ self._push_crop_update_to_player(account_id, player_data)
+
+ except Exception as e:
+ self.log('ERROR', f"更新作物生长状态时出错: {str(e)}", 'SERVER')
+
+
+ #向在线玩家推送作物更新
+ def _push_crop_update_to_player(self, account_id, player_data):
+ """
+ 向在线玩家推送作物生长更新
+
+ 参数:
+ account_id (str): 玩家账号ID
+ player_data (dict): 玩家数据
+ """
+ # 查找对应的客户端ID
+ client_id = None
+ for cid, user_info in self.user_data.items():
+ if user_info.get("username") == account_id and user_info.get("logged_in", False):
+ client_id = cid
+ break
+
+ # 如果玩家在线,检查是否处于访问模式
+ if client_id:
+ # 检查玩家是否处于访问模式
+ visiting_mode = self.user_data[client_id].get("visiting_mode", False)
+ visiting_target = self.user_data[client_id].get("visiting_target", "")
+
+ if visiting_mode and visiting_target:
+ # 如果处于访问模式,发送被访问玩家的更新数据
+ target_player_data = self.load_player_data(visiting_target)
+ if target_player_data:
+ update_message = {
+ "type": "crop_update",
+ "farm_lots": target_player_data.get("farm_lots", []),
+ "timestamp": time.time(),
+ "is_visiting": True,
+ "visited_player": visiting_target
+ }
+ self.send_data(client_id, update_message)
+ self.log('DEBUG', f"已向访问模式中的玩家 {account_id} 推送被访问玩家 {visiting_target} 的作物更新", 'SERVER')
+ else:
+ # 正常模式,发送自己的农场更新
+ update_message = {
+ "type": "crop_update",
+ "farm_lots": player_data.get("farm_lots", []),
+ "timestamp": time.time(),
+ "is_visiting": False
+ }
+ self.send_data(client_id, update_message)
+ self.log('DEBUG', f"已向玩家 {account_id} 推送作物更新", 'SERVER')
+
+
+ #设置一个计时器,每秒更新一次作物生长状态
+ def start_crop_growth_timer(self):
+ """
+ 启动作物生长计时器,每秒更新一次
+ """
+ import threading
+
+ # 更新作物生长状态
+ self.update_crops_growth()
+
+ # 创建下一个计时器
+ self.crop_timer = threading.Timer(1.0, self.start_crop_growth_timer)
+ self.crop_timer.daemon = True
+ self.crop_timer.start()
+
+
+ #覆盖客户端移除方法,添加用户离开通知
+ def _remove_client(self, client_id):
+ # 通知其他用户
+ if client_id in self.clients:
+ # 获取用户名以便记录日志
+ username = self.user_data.get(client_id, {}).get("username", client_id)
+
+ # 如果用户已登录,更新总游玩时间并标记其登出
+ if client_id in self.user_data and self.user_data[client_id].get("logged_in", False):
+ login_timestamp = self.user_data[client_id].get("login_timestamp", time.time())
+ play_time_seconds = int(time.time() - login_timestamp)
+
+ # 清除访问状态
+ self.user_data[client_id]["visiting_mode"] = False
+ self.user_data[client_id]["visiting_target"] = ""
+
+ # 加载玩家数据
+ player_data = self.load_player_data(username)
+ if player_data:
+ import datetime
+ import re
+
+ # 解析现有的总游玩时间
+ total_time_str = player_data.get("total_login_time", "0时0分0秒")
+ time_parts = re.match(r"(?:(\d+)时)?(?:(\d+)分)?(?:(\d+)秒)?", total_time_str)
+
+ if time_parts:
+ hours = int(time_parts.group(1) or 0)
+ minutes = int(time_parts.group(2) or 0)
+ seconds = int(time_parts.group(3) or 0)
+
+ # 计算新的总游玩时间
+ total_seconds = hours * 3600 + minutes * 60 + seconds + play_time_seconds
+ new_hours = total_seconds // 3600
+ new_minutes = (total_seconds % 3600) // 60
+ new_seconds = total_seconds % 60
+
+ # 更新总游玩时间
+ player_data["total_login_time"] = f"{new_hours}时{new_minutes}分{new_seconds}秒"
+
+ # 保存玩家数据
+ self.save_player_data(username, player_data)
+
+ self.log('INFO', f"用户 {username} 本次游玩时间: {play_time_seconds} 秒,总游玩时间: {player_data['total_login_time']}", 'SERVER')
+
+ self.log('INFO', f"用户 {username} 登出", 'SERVER')
+
+ self.broadcast(
+ {
+ "type": "user_left",
+ "user_id": client_id,
+ "timestamp": time.time(),
+ "remaining_users": len(self.clients) - 1
+ },
+ exclude=[client_id]
+ )
+
+ # 清理用户数据
+ if client_id in self.user_data:
+ del self.user_data[client_id]
+
+ self.log('INFO', f"用户 {username} 已离开游戏", 'SERVER')
+
+ # 调用父类方法完成实际断开
+ super()._remove_client(client_id)
+
+
+ #覆盖停止方法,停止作物生长计时器
+ def stop(self):
+ # 停止作物生长计时器
+ if self.crop_timer:
+ self.crop_timer.cancel()
+ self.crop_timer = None
+ self.log('INFO', "作物生长计时器已停止", 'SERVER')
+
+ # 调用父类方法完成实际停止
+ super().stop()
+
+
+ #接收客户端消息并处理
+ def _handle_message(self, client_id, message):
+ message_type = message.get("type", "")
+ match message_type:
+ case "greeting":
+ return self._handle_greeting(client_id, message)
+ case "message":
+ return self._handle_chat_message(client_id, message)
+ case "login":
+ return self._handle_login(client_id, message)
+ case "register":
+ return self._handle_register(client_id, message)
+ case "request_verification_code":
+ return self._handle_verification_code_request(client_id, message)
+ case "verify_code":
+ return self._handle_verify_code(client_id, message)
+ #玩家基本游戏操作
+ case "harvest_crop":
+ return self._handle_harvest_crop(client_id, message)
+ case "plant_crop":
+ return self._handle_plant_crop(client_id, message)
+ case "buy_seed":
+ return self._handle_buy_seed(client_id, message)
+ case "dig_ground":
+ return self._handle_dig_ground(client_id, message)
+ #玩家基本游戏操作
+ case "get_play_time":
+ return self._handle_get_play_time(client_id)
+ case "update_play_time":
+ return self._handle_update_play_time(client_id)
+ case "request_player_rankings":
+ return self._handle_player_rankings_request(client_id)
+ case "request_crop_data":
+ return self._handle_crop_data_request(client_id)
+ case "visit_player":
+ return self._handle_visit_player_request(client_id, message)
+ case "return_my_farm":
+ return self._handle_return_my_farm_request(client_id, message)
+ case _:
+ # 未知类型,使用默认处理
+ return super()._handle_message(client_id, message)
+
+
+ #处理登录消息
+ def _handle_login(self, client_id, message):
+ username = message.get("username", "")
+ password = message.get("password", "")
+
+ # 读取玩家数据
+ player_data = self.load_player_data(username)
+
+ if player_data and player_data.get("user_password") == password:
+ # 登录成功
+ self.log('INFO', f"用户 {username} 登录成功", 'SERVER')
+
+ # 更新最后登录时间
+ import datetime
+ current_time = datetime.datetime.now()
+ player_data["last_login_time"] = current_time.strftime("%Y年%m月%d日%H时%M分%S秒")
+
+ # 保存用户会话信息
+ self.user_data[client_id] = {
+ "username": username,
+ "last_active": time.time(),
+ "messages_count": 0,
+ "logged_in": True,
+ "login_timestamp": time.time() # 记录登录时间戳用于计算游玩时间
+ }
+
+ # 保存更新后的玩家数据
+ self.save_player_data(username, player_data)
+
+ # 立即向客户端发送一次作物状态
+ farm_lots = player_data.get("farm_lots", [])
+ initial_crop_update = {
+ "type": "crop_update",
+ "farm_lots": farm_lots,
+ "timestamp": time.time()
+ }
+ self.send_data(client_id, initial_crop_update)
+
+ # 发送最新的作物数据配置
+ try:
+ with open("config/crop_data.json", 'r', encoding='utf-8') as file:
+ crop_data = json.load(file)
+
+ crop_data_message = {
+ "type": "crop_data_response",
+ "success": True,
+ "crop_data": crop_data
+ }
+ self.send_data(client_id, crop_data_message)
+ self.log('INFO', f"已向登录用户 {username} 发送作物数据配置", 'SERVER')
+ except Exception as e:
+ self.log('ERROR', f"无法向登录用户发送作物数据: {str(e)}", 'SERVER')
+
+ # 返回登录成功消息
+ response = {
+ "type": "login_response",
+ "status": "success",
+ "message": "登录成功",
+ "player_data": player_data
+ }
+ else:
+ # 登录失败
+ self.log('WARNING', f"用户 {username} 登录失败: 账号或密码错误", 'SERVER')
+ response = {
+ "type": "login_response",
+ "status": "failed",
+ "message": "账号或密码错误"
+ }
+
+ return self.send_data(client_id, response)
+
+
+ #处理注册消息
+ def _handle_register(self, client_id, message):
+ username = message.get("username", "")
+ password = message.get("password", "")
+ farm_name = message.get("farm_name", "")
+ player_name = message.get("player_name", "")
+ verification_code = message.get("verification_code", "")
+
+ # 验证必填字段
+ if not username or not password:
+ self.log('WARNING', f"注册失败: 用户名或密码为空", 'SERVER')
+ return self.send_data(client_id, {
+ "type": "register_response",
+ "status": "failed",
+ "message": "用户名或密码不能为空"
+ })
+
+ # 验证用户名是否是QQ号 (5-12位数字)
+ import re
+ if not re.match(r'^\d{5,12}$', username):
+ self.log('WARNING', f"注册失败: 用户名 {username} 不是有效的QQ号码", 'SERVER')
+ return self.send_data(client_id, {
+ "type": "register_response",
+ "status": "failed",
+ "message": "用户名必须是5-12位的QQ号码"
+ })
+
+ # 验证验证码
+ if verification_code:
+ from QQEmailSend import EmailVerification
+ success, verify_message = EmailVerification.verify_code(username, verification_code)
+ if not success:
+ self.log('WARNING', f"注册失败: 验证码错误 - {verify_message}", 'SERVER')
+ return self.send_data(client_id, {
+ "type": "register_response",
+ "status": "failed",
+ "message": f"验证码错误: {verify_message}"
+ })
+
+ # 检查用户是否已存在
+ import os
+ file_path = os.path.join("game_saves", f"{username}.json")
+ if os.path.exists(file_path):
+ self.log('WARNING', f"注册失败: 用户 {username} 已存在", 'SERVER')
+ return self.send_data(client_id, {
+ "type": "register_response",
+ "status": "failed",
+ "message": "该用户名已被注册"
+ })
+
+ try:
+ # 从模板加载初始玩家数据
+ template_path = os.path.join("config", "initial_player_data_template.json")
+ if not os.path.exists(template_path):
+ self.log('ERROR', f"无法找到玩家数据模板文件", 'SERVER')
+ return self.send_data(client_id, {
+ "type": "register_response",
+ "status": "failed",
+ "message": "服务器配置错误,无法注册新用户"
+ })
+
+ with open(template_path, 'r', encoding='utf-8') as file:
+ player_data = json.load(file)
+
+ # 更新玩家数据
+ player_data["user_name"] = username
+ player_data["user_password"] = password
+
+ # 设置农场名称,如果没有提供则使用默认名称
+ if farm_name:
+ player_data["farm_name"] = farm_name
+
+ # 设置玩家昵称,如果没有提供则使用QQ号或默认昵称
+ if player_name:
+ player_data["player_name"] = player_name
+ else:
+ player_data["player_name"] = username
+
+ # 确保所有必要的字段都存在
+ if "experience" not in player_data:
+ player_data["experience"] = 0
+ if "level" not in player_data:
+ player_data["level"] = 1
+ if "money" not in player_data:
+ player_data["money"] = 1000
+ if "farm_lots" not in player_data:
+ # 创建空的农场地块
+ player_data["farm_lots"] = []
+ for i in range(40):
+ player_data["farm_lots"].append({
+ "crop_type": "",
+ "grow_time": 0,
+ "is_dead": False,
+ "is_diged": i < 5, # 默认开垦前5块地
+ "is_planted": False,
+ "max_grow_time": 5 if i >= 5 else 3
+ })
+ if "player_bag" not in player_data:
+ player_data["player_bag"] = []
+
+ # 更新注册时间和登录时间
+ import datetime
+ current_time = datetime.datetime.now()
+ time_str = current_time.strftime("%Y年%m月%d日%H时%M分%S秒")
+ player_data["last_login_time"] = time_str
+
+ if "total_login_time" not in player_data:
+ player_data["total_login_time"] = "0时0分0秒"
+
+ # 保存新用户数据
+ with open(file_path, 'w', encoding='utf-8') as file:
+ json.dump(player_data, file, indent=2, ensure_ascii=False)
+
+ self.log('INFO', f"用户 {username} 注册成功", 'SERVER')
+
+ # 返回成功响应
+ return self.send_data(client_id, {
+ "type": "register_response",
+ "status": "success",
+ "message": "注册成功,请登录游戏"
+ })
+
+ except Exception as e:
+ self.log('ERROR', f"注册用户 {username} 时出错: {str(e)}", 'SERVER')
+ return self.send_data(client_id, {
+ "type": "register_response",
+ "status": "failed",
+ "message": f"注册过程中出现错误: {str(e)}"
+ })
+
+
+
+
+ #处理问候消息
+ def _handle_greeting(self, client_id, message):
+ content = message.get("content", "")
+ self.log('INFO', f"收到来自客户端 {client_id} 的问候: {content}", 'CLIENT')
+
+ # 保存用户会话信息
+ self.user_data[client_id] = {
+ "last_active": time.time(),
+ "messages_count": 0
+ }
+
+ # 回复欢迎消息
+ response = {
+ "type": "greeting_response",
+ "content": f"欢迎 {client_id}!",
+ "server_time": time.time(),
+ "active_users": len(self.clients)
+ }
+
+ # 通知其他用户有新用户加入
+ self.broadcast(
+ {
+ "type": "user_joined",
+ "user_id": client_id,
+ "timestamp": time.time(),
+ "active_users": len(self.clients)
+ },
+ exclude=[client_id]
+ )
+
+ self.log('INFO', f"用户 {client_id} 已加入游戏", 'SERVER')
+ return self.send_data(client_id, response)
+
+
+
+
+ #处理收获作物请求
+ def _handle_harvest_crop(self, client_id, message):
+ """
+ 处理玩家收获作物的请求
+
+ 参数:
+ client_id (str): 客户端ID
+ message (dict): 消息内容
+ """
+ # 检查用户是否已登录
+ logged_in, response = self._check_user_logged_in(client_id, "收获作物", "harvest_crop")
+ if not logged_in:
+ return self.send_data(client_id, response)
+
+ # 获取玩家数据
+ player_data, username, response = self._load_player_data_with_check(client_id, "harvest_crop")
+ if not player_data:
+ return self.send_data(client_id, response)
+
+ # 获取地块索引
+ lot_index = message.get("lot_index", -1)
+
+ # 验证地块索引
+ if lot_index < 0 or lot_index >= len(player_data.get("farm_lots", [])):
+ self.log('WARNING', f"玩家 {username} 请求收获无效地块 {lot_index}", 'SERVER')
+ return self.send_data(client_id, {
+ "type": "action_response",
+ "action_type": "harvest_crop",
+ "success": False,
+ "message": "无效的地块索引"
+ })
+
+ # 获取地块数据
+ lot = player_data["farm_lots"][lot_index]
+
+ # 检查地块是否有作物且已成熟
+ if not lot.get("is_planted", False) or not lot.get("crop_type", ""):
+ self.log('WARNING', f"玩家 {username} 尝试收获空地块 {lot_index}", 'SERVER')
+ return self.send_data(client_id, {
+ "type": "action_response",
+ "action_type": "harvest_crop",
+ "success": False,
+ "message": "此地块没有种植作物"
+ })
+
+ if lot.get("is_dead", False):
+ # 处理已死亡的作物
+ self.log('INFO', f"玩家 {username} 铲除了地块 {lot_index} 上已死亡的作物", 'SERVER')
+
+ # 清理地块
+ lot["is_planted"] = False
+ lot["crop_type"] = ""
+ lot["grow_time"] = 0
+
+ # 保存玩家数据
+ self.save_player_data(username, player_data)
+
+ # 发送作物更新
+ self._push_crop_update_to_player(username, player_data)
+
+ return self.send_data(client_id, {
+ "type": "action_response",
+ "action_type": "harvest_crop",
+ "success": True,
+ "message": f"已铲除死亡的作物",
+ "updated_data": {
+ "money": player_data["money"],
+ "experience": player_data["experience"],
+ "level": player_data["level"]
+ }
+ })
+
+ if lot["grow_time"] < lot["max_grow_time"]:
+ self.log('WARNING', f"玩家 {username} 尝试收获未成熟的作物 {lot_index}", 'SERVER')
+ return self.send_data(client_id, {
+ "type": "action_response",
+ "action_type": "harvest_crop",
+ "success": False,
+ "message": "作物尚未成熟"
+ })
+
+ # 读取作物配置 (假设在服务器上也有作物配置)
+ import json
+ crop_data = {}
+ try:
+ with open("config/crop_data.json", 'r', encoding='utf-8') as file:
+ crop_data = json.load(file)
+ except Exception as e:
+ self.log('ERROR', f"无法加载作物数据: {str(e)}", 'SERVER')
+ # 使用默认收益
+ crop_income = 100
+ crop_exp = 10
+
+ # 获取作物收益和经验
+ crop_type = lot["crop_type"]
+ if crop_type in crop_data:
+ crop_income = crop_data[crop_type].get("收益", 100) + crop_data[crop_type].get("花费", 0)
+ crop_exp = crop_data[crop_type].get("经验", 10)
+ else:
+ # 默认收益
+ crop_income = 100
+ crop_exp = 10
+
+ # 更新玩家数据
+ player_data["money"] += crop_income
+ player_data["experience"] += crop_exp
+
+ # 检查升级
+ level_up_experience = 100 * player_data["level"]
+ if player_data["experience"] >= level_up_experience:
+ player_data["level"] += 1
+ player_data["experience"] -= level_up_experience
+ self.log('INFO', f"玩家 {username} 升级到 {player_data['level']} 级", 'SERVER')
+
+ # 清理地块
+ lot["is_planted"] = False
+ lot["crop_type"] = ""
+ lot["grow_time"] = 0
+
+ # 保存玩家数据
+ self.save_player_data(username, player_data)
+
+ # 发送作物更新
+ self._push_crop_update_to_player(username, player_data)
+
+ self.log('INFO', f"玩家 {username} 从地块 {lot_index} 收获了作物,获得 {crop_income} 金钱和 {crop_exp} 经验", 'SERVER')
+
+ return self.send_data(client_id, {
+ "type": "action_response",
+ "action_type": "harvest_crop",
+ "success": True,
+ "message": f"收获成功,获得 {crop_income} 金钱和 {crop_exp} 经验",
+ "updated_data": {
+ "money": player_data["money"],
+ "experience": player_data["experience"],
+ "level": player_data["level"]
+ }
+ })
+
+
+ #处理种植作物请求
+ def _handle_plant_crop(self, client_id, message):
+ """
+ 处理玩家种植作物的请求
+
+ 参数:
+ client_id (str): 客户端ID
+ message (dict): 消息内容
+ """
+ # 检查用户是否已登录
+ logged_in, response = self._check_user_logged_in(client_id, "种植作物", "plant_crop")
+ if not logged_in:
+ return self.send_data(client_id, response)
+
+ # 获取玩家数据
+ player_data, username, response = self._load_player_data_with_check(client_id, "plant_crop")
+ if not player_data:
+ return self.send_data(client_id, response)
+
+ # 获取地块索引和作物名称
+ lot_index = message.get("lot_index", -1)
+ crop_name = message.get("crop_name", "")
+
+ # 验证地块索引
+ if lot_index < 0 or lot_index >= len(player_data.get("farm_lots", [])):
+ self.log('WARNING', f"玩家 {username} 请求种植无效地块 {lot_index}", 'SERVER')
+ return self.send_data(client_id, {
+ "type": "action_response",
+ "action_type": "plant_crop",
+ "success": False,
+ "message": "无效的地块索引"
+ })
+
+ # 获取地块数据
+ lot = player_data["farm_lots"][lot_index]
+
+ # 检查地块是否已开垦且未种植
+ if not lot.get("is_diged", False):
+ self.log('WARNING', f"玩家 {username} 尝试在未开垦的地块 {lot_index} 种植", 'SERVER')
+ return self.send_data(client_id, {
+ "type": "action_response",
+ "action_type": "plant_crop",
+ "success": False,
+ "message": "此地块尚未开垦"
+ })
+
+ if lot.get("is_planted", False):
+ self.log('WARNING', f"玩家 {username} 尝试在已种植的地块 {lot_index} 种植", 'SERVER')
+ return self.send_data(client_id, {
+ "type": "action_response",
+ "action_type": "plant_crop",
+ "success": False,
+ "message": "此地块已经种植了作物"
+ })
+
+ # 读取作物配置 (假设在服务器上也有作物配置)
+ import json
+ crop_data = {}
+ try:
+ with open("config/crop_data.json", 'r', encoding='utf-8') as file:
+ crop_data = json.load(file)
+ except Exception as e:
+ self.log('ERROR', f"无法加载作物数据: {str(e)}", 'SERVER')
+ # 如果无法加载作物数据,使用默认生长时间
+ grow_time = 600
+
+ # 检查玩家背包中是否有此种子
+ seed_found = False
+ seed_index = -1
+
+ for i, item in enumerate(player_data.get("player_bag", [])):
+ if item.get("name") == crop_name:
+ seed_found = True
+ seed_index = i
+ break
+
+ if not seed_found:
+ self.log('WARNING', f"玩家 {username} 尝试种植背包中没有的种子 {crop_name}", 'SERVER')
+ return self.send_data(client_id, {
+ "type": "action_response",
+ "action_type": "plant_crop",
+ "success": False,
+ "message": "背包中没有此种子"
+ })
+
+ # 获取作物生长时间
+ if crop_name in crop_data:
+ grow_time = crop_data[crop_name].get("生长时间", 600)
+ else:
+ # 默认生长时间
+ grow_time = 600
+
+ # 从背包中减少种子数量
+ player_data["player_bag"][seed_index]["count"] -= 1
+
+ # 如果种子用完,从背包中移除
+ if player_data["player_bag"][seed_index]["count"] <= 0:
+ player_data["player_bag"].pop(seed_index)
+
+ # 更新地块数据
+ lot["is_planted"] = True
+ lot["crop_type"] = crop_name
+ lot["grow_time"] = 0
+ lot["max_grow_time"] = grow_time
+ lot["is_dead"] = False
+
+ # 保存玩家数据
+ self.save_player_data(username, player_data)
+
+ # 发送作物更新
+ self._push_crop_update_to_player(username, player_data)
+
+ self.log('INFO', f"玩家 {username} 在地块 {lot_index} 种植了 {crop_name}", 'SERVER')
+
+ return self.send_data(client_id, {
+ "type": "action_response",
+ "action_type": "plant_crop",
+ "success": True,
+ "message": f"成功种植 {crop_name}",
+ "updated_data": {
+ "player_bag": player_data["player_bag"]
+ }
+ })
+
+
+ #处理购买种子请求
+ def _handle_buy_seed(self, client_id, message):
+ """
+ 处理玩家购买种子的请求
+
+ 参数:
+ client_id (str): 客户端ID
+ message (dict): 消息内容
+ """
+ # 检查用户是否已登录
+ logged_in, response = self._check_user_logged_in(client_id, "购买种子", "buy_seed")
+ if not logged_in:
+ return self.send_data(client_id, response)
+
+ # 获取玩家数据
+ player_data, username, response = self._load_player_data_with_check(client_id, "buy_seed")
+ if not player_data:
+ return self.send_data(client_id, response)
+
+ # 获取作物名称
+ crop_name = message.get("crop_name", "")
+
+ # 读取作物配置 (假设在服务器上也有作物配置)
+ import json
+ crop_data = {}
+ try:
+ with open("config/crop_data.json", 'r', encoding='utf-8') as file:
+ crop_data = json.load(file)
+ except Exception as e:
+ self.log('ERROR', f"无法加载作物数据: {str(e)}", 'SERVER')
+ return self.send_data(client_id, {
+ "type": "action_response",
+ "action_type": "buy_seed",
+ "success": False,
+ "message": "服务器无法加载作物数据"
+ })
+
+ # 检查作物是否存在
+ if crop_name not in crop_data:
+ self.log('WARNING', f"玩家 {username} 尝试购买不存在的种子 {crop_name}", 'SERVER')
+ return self.send_data(client_id, {
+ "type": "action_response",
+ "action_type": "buy_seed",
+ "success": False,
+ "message": "该种子不存在"
+ })
+
+ # 获取作物数据
+ crop = crop_data[crop_name]
+
+ # 检查玩家等级
+ if player_data["level"] < crop.get("等级", 1):
+ self.log('WARNING', f"玩家 {username} 等级不足,无法购买种子 {crop_name}", 'SERVER')
+ return self.send_data(client_id, {
+ "type": "action_response",
+ "action_type": "buy_seed",
+ "success": False,
+ "message": "等级不足,无法购买此种子"
+ })
+
+ # 检查玩家金钱
+ if player_data["money"] < crop.get("花费", 0):
+ self.log('WARNING', f"玩家 {username} 金钱不足,无法购买种子 {crop_name}", 'SERVER')
+ return self.send_data(client_id, {
+ "type": "action_response",
+ "action_type": "buy_seed",
+ "success": False,
+ "message": "金钱不足,无法购买此种子"
+ })
+
+ # 扣除金钱
+ player_data["money"] -= crop.get("花费", 0)
+
+ # 将种子添加到背包
+ seed_found = False
+
+ for item in player_data.get("player_bag", []):
+ if item.get("name") == crop_name:
+ item["count"] += 1
+ seed_found = True
+ break
+
+ if not seed_found:
+ if "player_bag" not in player_data:
+ player_data["player_bag"] = []
+
+ player_data["player_bag"].append({
+ "name": crop_name,
+ "quality": crop.get("品质", "普通"),
+ "count": 1
+ })
+
+ # 保存玩家数据
+ self.save_player_data(username, player_data)
+
+ self.log('INFO', f"玩家 {username} 购买了种子 {crop_name}", 'SERVER')
+
+ return self.send_data(client_id, {
+ "type": "action_response",
+ "action_type": "buy_seed",
+ "success": True,
+ "message": f"成功购买 {crop_name} 种子",
+ "updated_data": {
+ "money": player_data["money"],
+ "player_bag": player_data["player_bag"]
+ }
+ })
+
+
+ #处理开垦土地请求
+ def _handle_dig_ground(self, client_id, message):
+ """
+ 处理玩家开垦土地的请求
+
+ 参数:
+ client_id (str): 客户端ID
+ message (dict): 消息内容
+ """
+ # 检查用户是否已登录
+ logged_in, response = self._check_user_logged_in(client_id, "开垦土地", "dig_ground")
+ if not logged_in:
+ return self.send_data(client_id, response)
+
+ # 获取玩家数据
+ player_data, username, response = self._load_player_data_with_check(client_id, "dig_ground")
+ if not player_data:
+ return self.send_data(client_id, response)
+
+ # 获取地块索引
+ lot_index = message.get("lot_index", -1)
+
+ # 验证地块索引
+ if lot_index < 0 or lot_index >= len(player_data.get("farm_lots", [])):
+ self.log('WARNING', f"玩家 {username} 请求开垦无效地块 {lot_index}", 'SERVER')
+ return self.send_data(client_id, {
+ "type": "action_response",
+ "action_type": "dig_ground",
+ "success": False,
+ "message": "无效的地块索引"
+ })
+
+ # 获取地块数据
+ lot = player_data["farm_lots"][lot_index]
+
+ # 检查地块是否已开垦
+ if lot.get("is_diged", False):
+ self.log('WARNING', f"玩家 {username} 尝试开垦已开垦的地块 {lot_index}", 'SERVER')
+ return self.send_data(client_id, {
+ "type": "action_response",
+ "action_type": "dig_ground",
+ "success": False,
+ "message": "此地块已经开垦过了"
+ })
+
+ # 计算开垦费用 - 基于已开垦地块数量
+ digged_count = sum(1 for l in player_data["farm_lots"] if l.get("is_diged", False))
+ dig_money = digged_count * 1000
+
+ # 检查玩家金钱是否足够
+ if player_data["money"] < dig_money:
+ self.log('WARNING', f"玩家 {username} 金钱不足,无法开垦地块 {lot_index}", 'SERVER')
+ return self.send_data(client_id, {
+ "type": "action_response",
+ "action_type": "dig_ground",
+ "success": False,
+ "message": f"金钱不足,开垦此地块需要 {dig_money} 金钱"
+ })
+
+ # 执行开垦操作
+ player_data["money"] -= dig_money
+ lot["is_diged"] = True
+
+ # 保存玩家数据
+ self.save_player_data(username, player_data)
+
+ # 发送作物更新
+ self._push_crop_update_to_player(username, player_data)
+
+ self.log('INFO', f"玩家 {username} 成功开垦地块 {lot_index},花费 {dig_money} 金钱", 'SERVER')
+
+ return self.send_data(client_id, {
+ "type": "action_response",
+ "action_type": "dig_ground",
+ "success": True,
+ "message": f"成功开垦地块,花费 {dig_money} 金钱",
+ "updated_data": {
+ "money": player_data["money"],
+ "farm_lots": player_data["farm_lots"]
+ }
+ })
+
+
+ #处理获取游玩时间请求
+ def _handle_get_play_time(self, client_id):
+ """
+ 处理玩家获取游玩时间的请求
+
+ 参数:
+ client_id (str): 客户端ID
+ """
+ # 检查用户是否已登录
+ logged_in, response = self._check_user_logged_in(client_id, "获取游玩时间")
+ if not logged_in:
+ return self.send_data(client_id, response)
+
+ # 获取玩家数据
+ player_data, username, response = self._load_player_data_with_check(client_id, "play_time")
+ if not player_data:
+ return self.send_data(client_id, response)
+
+ # 计算当前会话的游玩时间
+ login_timestamp = self.user_data[client_id].get("login_timestamp", time.time())
+ current_session_seconds = int(time.time() - login_timestamp)
+
+ # 格式化当前会话时间
+ current_hours = current_session_seconds // 3600
+ current_minutes = (current_session_seconds % 3600) // 60
+ current_seconds = current_session_seconds % 60
+ current_session_time = f"{current_hours}时{current_minutes}分{current_seconds}秒"
+
+ # 获取最后登录时间和总游玩时间
+ last_login_time = player_data.get("last_login_time", "未知")
+ total_login_time = player_data.get("total_login_time", "0时0分0秒")
+
+ self.log('INFO', f"玩家 {username} 请求游玩时间统计", 'SERVER')
+
+ return self.send_data(client_id, {
+ "type": "play_time_response",
+ "success": True,
+ "last_login_time": last_login_time,
+ "total_login_time": total_login_time,
+ "current_session_time": current_session_time
+ })
+
+
+ #处理更新游玩时间请求
+ def _handle_update_play_time(self, client_id):
+ """
+ 处理玩家手动更新游玩时间的请求
+ 用于客户端不关闭而希望更新游玩时间的情况
+
+ 参数:
+ client_id (str): 客户端ID
+ """
+ # 检查用户是否已登录
+ logged_in, response = self._check_user_logged_in(client_id, "更新游玩时间", "update_time")
+ if not logged_in:
+ return self.send_data(client_id, response)
+
+ # 获取玩家数据
+ player_data, username, response = self._load_player_data_with_check(client_id, "update_time")
+ if not player_data:
+ return self.send_data(client_id, response)
+
+ # 计算当前会话的游玩时间
+ login_timestamp = self.user_data[client_id].get("login_timestamp", time.time())
+ play_time_seconds = int(time.time() - login_timestamp)
+
+ # 解析现有的总游玩时间
+ import re
+ total_time_str = player_data.get("total_login_time", "0时0分0秒")
+ time_parts = re.match(r"(?:(\d+)时)?(?:(\d+)分)?(?:(\d+)秒)?", total_time_str)
+
+ if time_parts:
+ hours = int(time_parts.group(1) or 0)
+ minutes = int(time_parts.group(2) or 0)
+ seconds = int(time_parts.group(3) or 0)
+
+ # 计算新的总游玩时间
+ total_seconds = hours * 3600 + minutes * 60 + seconds + play_time_seconds
+ new_hours = total_seconds // 3600
+ new_minutes = (total_seconds % 3600) // 60
+ new_seconds = total_seconds % 60
+
+ # 更新总游玩时间
+ player_data["total_login_time"] = f"{new_hours}时{new_minutes}分{new_seconds}秒"
+
+ # 保存玩家数据
+ self.save_player_data(username, player_data)
+
+ # 重置登录时间戳,以便下次计算
+ self.user_data[client_id]["login_timestamp"] = time.time()
+
+ self.log('INFO', f"已更新玩家 {username} 的游玩时间,当前游玩时间: {play_time_seconds} 秒,总游玩时间: {player_data['total_login_time']}", 'SERVER')
+
+ return self.send_data(client_id, {
+ "type": "update_time_response",
+ "success": True,
+ "message": "游玩时间已更新",
+ "total_login_time": player_data["total_login_time"]
+ })
+ else:
+ self.log('ERROR', f"解析玩家 {username} 的游玩时间失败", 'SERVER')
+ return self.send_data(client_id, {
+ "type": "update_time_response",
+ "success": False,
+ "message": "更新游玩时间失败,格式错误"
+ })
+
+
+ #处理玩家排行榜请求
+ def _handle_player_rankings_request(self, client_id):
+ """
+ 处理获取玩家排行榜的请求
+ 返回所有玩家的数据(按等级排序)
+
+ 参数:
+ client_id (str): 客户端ID
+ """
+ import os
+ import glob
+ import json
+
+ # 检查用户是否已登录
+ logged_in, response = self._check_user_logged_in(client_id, "获取玩家排行榜", "player_rankings")
+ if not logged_in:
+ return self.send_data(client_id, response)
+
+ # 获取所有玩家存档文件
+ save_files = glob.glob(os.path.join("game_saves", "*.json"))
+ players_data = []
+
+ for save_file in save_files:
+ try:
+ # 从文件名提取账号ID
+ account_id = os.path.basename(save_file).split('.')[0]
+
+ # 加载玩家数据
+ with open(save_file, 'r', encoding='utf-8') as file:
+ player_data = json.load(file)
+
+ if player_data:
+ # 统计背包中的种子数量
+ seed_count = 0
+ for item in player_data.get("player_bag", []):
+ seed_count += item.get("count", 0)
+
+ # 获取所需的玩家信息
+ player_info = {
+ "user_name": player_data.get("user_name", account_id),
+ "player_name": player_data.get("player_name", player_data.get("user_name", account_id)),
+ "farm_name": player_data.get("farm_name", ""),
+ "level": player_data.get("level", 1),
+ "money": player_data.get("money", 0),
+ "experience": player_data.get("experience", 0),
+ "seed_count": seed_count,
+ "last_login_time": player_data.get("last_login_time", "未知"),
+ "total_login_time": player_data.get("total_login_time", "0时0分0秒")
+ }
+
+ players_data.append(player_info)
+ except Exception as e:
+ self.log('ERROR', f"读取玩家 {account_id} 的数据时出错: {str(e)}", 'SERVER')
+
+ # 按等级降序排序
+ players_data.sort(key=lambda x: x["level"], reverse=True)
+
+ self.log('INFO', f"玩家 {self.user_data[client_id].get('username')} 请求玩家排行榜,返回 {len(players_data)} 个玩家数据", 'SERVER')
+
+ # 返回排行榜数据
+ return self.send_data(client_id, {
+ "type": "player_rankings_response",
+ "success": True,
+ "players": players_data
+ })
+
+
+ #处理作物数据请求
+ def _handle_crop_data_request(self, client_id):
+ """
+ 处理客户端请求作物数据
+
+ 参数:
+ client_id (str): 客户端ID
+ """
+ import json
+
+ try:
+ # 读取服务器上的作物数据
+ with open("config/crop_data.json", 'r', encoding='utf-8') as file:
+ crop_data = json.load(file)
+
+ self.log('INFO', f"向客户端 {client_id} 发送作物数据", 'SERVER')
+
+ return self.send_data(client_id, {
+ "type": "crop_data_response",
+ "success": True,
+ "crop_data": crop_data
+ })
+ except Exception as e:
+ self.log('ERROR', f"读取作物数据时出错: {str(e)}", 'SERVER')
+ return self.send_data(client_id, {
+ "type": "crop_data_response",
+ "success": False,
+ "message": f"无法读取作物数据: {str(e)}"
+ })
+
+
+ #处理验证码请求
+ def _handle_verification_code_request(self, client_id, message):
+ """
+ 处理验证码请求,向指定QQ号对应的邮箱发送验证码
+
+ 参数:
+ client_id (str): 客户端ID
+ message (dict): 消息内容
+ """
+ from QQEmailSend import EmailVerification
+
+ # 获取QQ号
+ qq_number = message.get("qq_number", "")
+
+ # 验证QQ号
+ import re
+ if not re.match(r'^\d{5,12}$', qq_number):
+ self.log('WARNING', f"验证码请求错误: QQ号 {qq_number} 格式无效", 'SERVER')
+ return self.send_data(client_id, {
+ "type": "verification_code_response",
+ "success": False,
+ "message": "QQ号格式无效,请输入5-12位数字"
+ })
+
+ # 生成验证码
+ verification_code = EmailVerification.generate_verification_code()
+
+ # 发送验证码邮件
+ success, send_message = EmailVerification.send_verification_email(qq_number, verification_code)
+
+ if success:
+ # 保存验证码
+ EmailVerification.save_verification_code(qq_number, verification_code)
+ self.log('INFO', f"已向QQ号 {qq_number} 发送验证码", 'SERVER')
+
+ return self.send_data(client_id, {
+ "type": "verification_code_response",
+ "success": True,
+ "message": "验证码已发送到您的QQ邮箱,请查收"
+ })
+ else:
+ self.log('ERROR', f"发送验证码失败: {send_message}", 'SERVER')
+ return self.send_data(client_id, {
+ "type": "verification_code_response",
+ "success": False,
+ "message": f"发送验证码失败: {send_message}"
+ })
+
+
+ #处理验证码验证
+ def _handle_verify_code(self, client_id, message):
+ """
+ 处理验证码验证请求
+
+ 参数:
+ client_id (str): 客户端ID
+ message (dict): 消息内容
+ """
+ from QQEmailSend import EmailVerification
+
+ # 获取QQ号和验证码
+ qq_number = message.get("qq_number", "")
+ input_code = message.get("code", "")
+
+ # 验证码不能为空
+ if not input_code:
+ return self.send_data(client_id, {
+ "type": "verify_code_response",
+ "success": False,
+ "message": "验证码不能为空"
+ })
+
+ # 验证验证码
+ success, verify_message = EmailVerification.verify_code(qq_number, input_code)
+
+ if success:
+ self.log('INFO', f"QQ号 {qq_number} 的验证码验证成功", 'SERVER')
+ return self.send_data(client_id, {
+ "type": "verify_code_response",
+ "success": True,
+ "message": "验证成功"
+ })
+ else:
+ self.log('WARNING', f"QQ号 {qq_number} 的验证码验证失败: {verify_message}", 'SERVER')
+ return self.send_data(client_id, {
+ "type": "verify_code_response",
+ "success": False,
+ "message": verify_message
+ })
+
+
+ #处理访问玩家请求
+ def _handle_visit_player_request(self, client_id, message):
+ """
+ 处理访问其他玩家农场的请求
+
+ 参数:
+ client_id (str): 客户端ID
+ message (dict): 消息内容
+ """
+ # 检查用户是否已登录
+ logged_in, response = self._check_user_logged_in(client_id, "访问玩家农场", "visit_player")
+ if not logged_in:
+ return self.send_data(client_id, response)
+
+ # 获取要访问的玩家用户名
+ target_username = message.get("target_username", "")
+
+ if not target_username:
+ self.log('WARNING', f"访问玩家请求缺少目标用户名", 'SERVER')
+ return self.send_data(client_id, {
+ "type": "visit_player_response",
+ "success": False,
+ "message": "缺少目标用户名"
+ })
+
+ # 加载目标玩家数据
+ target_player_data = self.load_player_data(target_username)
+
+ if not target_player_data:
+ self.log('WARNING', f"无法找到玩家 {target_username} 的数据", 'SERVER')
+ return self.send_data(client_id, {
+ "type": "visit_player_response",
+ "success": False,
+ "message": f"无法找到玩家 {target_username} 的数据"
+ })
+
+ # 返回目标玩家的农场数据(只返回可见的数据,不包含敏感信息如密码)
+ safe_player_data = {
+ "user_name": target_player_data.get("user_name", target_username),
+ "player_name": target_player_data.get("player_name", target_username),
+ "farm_name": target_player_data.get("farm_name", ""),
+ "level": target_player_data.get("level", 1),
+ "money": target_player_data.get("money", 0),
+ "experience": target_player_data.get("experience", 0),
+ "farm_lots": target_player_data.get("farm_lots", []),
+ "player_bag": target_player_data.get("player_bag", []),
+ "last_login_time": target_player_data.get("last_login_time", "未知"),
+ "total_login_time": target_player_data.get("total_login_time", "0时0分0秒")
+ }
+
+ current_username = self.user_data[client_id]["username"]
+ self.log('INFO', f"玩家 {current_username} 访问了玩家 {target_username} 的农场", 'SERVER')
+
+ # 记录玩家的访问状态
+ self.user_data[client_id]["visiting_mode"] = True
+ self.user_data[client_id]["visiting_target"] = target_username
+
+ return self.send_data(client_id, {
+ "type": "visit_player_response",
+ "success": True,
+ "message": f"成功获取玩家 {target_username} 的农场数据",
+ "player_data": safe_player_data,
+ "is_visiting": True
+ })
+
+
+ #处理返回自己农场请求
+ def _handle_return_my_farm_request(self, client_id, message):
+ """
+ 处理玩家返回自己农场的请求
+
+ 参数:
+ client_id (str): 客户端ID
+ message (dict): 消息内容
+ """
+ # 检查用户是否已登录
+ logged_in, response = self._check_user_logged_in(client_id, "返回自己农场", "return_my_farm")
+ if not logged_in:
+ return self.send_data(client_id, response)
+
+ # 获取玩家数据
+ player_data, username, response = self._load_player_data_with_check(client_id, "return_my_farm")
+ if not player_data:
+ return self.send_data(client_id, response)
+
+ # 清除访问状态
+ self.user_data[client_id]["visiting_mode"] = False
+ self.user_data[client_id]["visiting_target"] = ""
+
+ self.log('INFO', f"玩家 {username} 返回了自己的农场", 'SERVER')
+
+ # 返回玩家自己的农场数据
+ return self.send_data(client_id, {
+ "type": "return_my_farm_response",
+ "success": True,
+ "message": "已返回自己的农场",
+ "player_data": {
+ "user_name": player_data.get("user_name", username),
+ "player_name": player_data.get("player_name", username),
+ "farm_name": player_data.get("farm_name", ""),
+ "level": player_data.get("level", 1),
+ "money": player_data.get("money", 0),
+ "experience": player_data.get("experience", 0),
+ "farm_lots": player_data.get("farm_lots", []),
+ "player_bag": player_data.get("player_bag", [])
+ },
+ "is_visiting": False
+ })
+
+
+
+
+
+# 使用示例
+if __name__ == "__main__":
+ import threading
+ import sys
+
+ try:
+ # 创建自定义服务器
+ server = TCPGameServer()
+
+ # 以阻塞方式启动服务器
+ server_thread = threading.Thread(target=server.start)
+ server_thread.daemon = True
+ server_thread.start()
+
+ # 运行直到按Ctrl+C
+ while True:
+ time.sleep(1)
+
+ except KeyboardInterrupt:
+ print("\n程序被用户中断")
+ if 'server' in locals():
+ server.stop()
+ sys.exit(0)
\ No newline at end of file
diff --git a/Server/TCPServer.py b/Server/TCPServer.py
new file mode 100644
index 0000000..1da4818
--- /dev/null
+++ b/Server/TCPServer.py
@@ -0,0 +1,355 @@
+import socket
+import threading
+import json
+import time
+import sys
+import logging
+import colorama
+from datetime import datetime
+
+# 初始化colorama以支持跨平台彩色终端输出
+colorama.init()
+
+# 自定义日志格式化器,带有颜色和分类
+class MinecraftStyleFormatter(logging.Formatter):
+ """Minecraft风格的日志格式化器,带有颜色和分类"""
+
+ # ANSI颜色代码
+ COLORS = {
+ 'RESET': colorama.Fore.RESET,
+ 'BLACK': colorama.Fore.BLACK,
+ 'RED': colorama.Fore.RED,
+ 'GREEN': colorama.Fore.GREEN,
+ 'YELLOW': colorama.Fore.YELLOW,
+ 'BLUE': colorama.Fore.BLUE,
+ 'MAGENTA': colorama.Fore.MAGENTA,
+ 'CYAN': colorama.Fore.CYAN,
+ 'WHITE': colorama.Fore.WHITE,
+ 'BRIGHT_BLACK': colorama.Fore.LIGHTBLACK_EX,
+ 'BRIGHT_RED': colorama.Fore.LIGHTRED_EX,
+ 'BRIGHT_GREEN': colorama.Fore.LIGHTGREEN_EX,
+ 'BRIGHT_YELLOW': colorama.Fore.LIGHTYELLOW_EX,
+ 'BRIGHT_BLUE': colorama.Fore.LIGHTBLUE_EX,
+ 'BRIGHT_MAGENTA': colorama.Fore.LIGHTMAGENTA_EX,
+ 'BRIGHT_CYAN': colorama.Fore.LIGHTCYAN_EX,
+ 'BRIGHT_WHITE': colorama.Fore.LIGHTWHITE_EX,
+ }
+
+ # 日志级别颜色(类似于Minecraft)
+ LEVEL_COLORS = {
+ 'DEBUG': COLORS['BRIGHT_BLACK'],
+ 'INFO': COLORS['WHITE'],
+ 'WARNING': COLORS['YELLOW'],
+ 'ERROR': COLORS['RED'],
+ 'CRITICAL': COLORS['BRIGHT_RED'],
+ }
+
+ # 类别及其颜色
+ CATEGORIES = {
+ 'SERVER': COLORS['BRIGHT_CYAN'],
+ 'NETWORK': COLORS['BRIGHT_GREEN'],
+ 'CLIENT': COLORS['BRIGHT_YELLOW'],
+ 'SYSTEM': COLORS['BRIGHT_MAGENTA'],
+ }
+
+ def format(self, record):
+ # 获取日志级别颜色
+ level_color = self.LEVEL_COLORS.get(record.levelname, self.COLORS['WHITE'])
+
+ # 从记录名称中确定类别,默认为SERVER
+ category_name = getattr(record, 'category', 'SERVER')
+ category_color = self.CATEGORIES.get(category_name, self.COLORS['WHITE'])
+
+ # 格式化时间戳,类似于Minecraft:[HH:MM:SS]
+ timestamp = datetime.now().strftime('%H:%M:%S')
+
+ # 格式化消息
+ formatted_message = f"{self.COLORS['BRIGHT_BLACK']}[{timestamp}] {category_color}[{category_name}] {level_color}{record.levelname}: {record.getMessage()}{self.COLORS['RESET']}"
+
+ return formatted_message
+
+
+class TCPServer:
+ def __init__(self, host='127.0.0.1', port=9000, buffer_size=4096):
+ """初始化TCP服务器"""
+ self.host = host
+ self.port = port
+ self.buffer_size = buffer_size
+ self.socket = None
+ self.clients = {} # 存储客户端连接 {client_id: (socket, address)}
+ self.running = False
+ self.client_buffers = {} # 每个客户端的消息缓冲区
+
+ # 配置日志
+ self._setup_logging()
+
+ def _setup_logging(self):
+ """设置Minecraft风格的日志系统"""
+ # 创建日志器
+ self.logger = logging.getLogger('TCPServer')
+ self.logger.setLevel(logging.INFO)
+
+ # 清除任何现有的处理器
+ if self.logger.handlers:
+ self.logger.handlers.clear()
+
+ # 创建控制台处理器
+ console_handler = logging.StreamHandler()
+ console_handler.setLevel(logging.INFO)
+
+ # 设置格式化器
+ formatter = MinecraftStyleFormatter()
+ console_handler.setFormatter(formatter)
+
+ # 添加处理器到日志器
+ self.logger.addHandler(console_handler)
+
+ def log(self, level, message, category='SERVER'):
+ """使用指定的分类和级别记录日志"""
+ record = logging.LogRecord(
+ name=self.logger.name,
+ level=getattr(logging, level),
+ pathname='',
+ lineno=0,
+ msg=message,
+ args=(),
+ exc_info=None
+ )
+ record.category = category
+ self.logger.handle(record)
+
+ def start(self):
+ """启动服务器"""
+ try:
+ # 创建TCP套接字
+ self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+ self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
+ self.socket.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1) # 禁用Nagle算法
+
+ # 绑定地址和监听
+ self.socket.bind((self.host, self.port))
+ self.socket.listen(5)
+
+ self.running = True
+ self.log('INFO', f"服务器启动,监听 {self.host}:{self.port}", 'SERVER')
+
+ # 接受客户端连接的主循环
+ self._accept_clients()
+
+ except Exception as e:
+ self.log('ERROR', f"服务器启动错误: {e}", 'SYSTEM')
+ self.stop()
+
+ def _accept_clients(self):
+ """接受客户端连接的循环"""
+ while self.running:
+ try:
+ # 接受新的客户端连接
+ client_socket, address = self.socket.accept()
+ client_id = f"{address[0]}:{address[1]}"
+
+ self.log('INFO', f"新客户端连接: {client_id}", 'NETWORK')
+
+ # 存储客户端信息
+ self.clients[client_id] = (client_socket, address)
+ self.client_buffers[client_id] = ""
+
+ # 创建处理线程
+ client_thread = threading.Thread(
+ target=self._handle_client,
+ args=(client_id,)
+ )
+ client_thread.daemon = True
+ client_thread.start()
+
+ # 通知客户端连接成功
+ self.send_data(client_id, {"type": "connection_status", "status": "connected"})
+
+ except KeyboardInterrupt:
+ self.log('INFO', "收到中断信号,服务器停止中...", 'SYSTEM')
+ break
+ except Exception as e:
+ self.log('ERROR', f"接受连接时出错: {e}", 'NETWORK')
+ time.sleep(1) # 避免CPU过度使用
+
+ def _handle_client(self, client_id):
+ """处理客户端消息的线程"""
+ client_socket, _ = self.clients.get(client_id, (None, None))
+ if not client_socket:
+ return
+
+ # 设置超时,用于定期检查连接状态
+ client_socket.settimeout(30)
+
+ while self.running and client_id in self.clients:
+ try:
+ # 接收数据
+ data = client_socket.recv(self.buffer_size)
+
+ if not data:
+ # 客户端断开连接
+ self.log('INFO', f"客户端 {client_id} 断开连接", 'CLIENT')
+ self._remove_client(client_id)
+ break
+
+ # 处理接收的数据
+ self._process_data(client_id, data)
+
+ except socket.timeout:
+ # 发送保活消息
+ try:
+ self.send_data(client_id, {"type": "ping"})
+ except:
+ self.log('INFO', f"客户端 {client_id} 连接超时", 'CLIENT')
+ self._remove_client(client_id)
+ break
+ except Exception as e:
+ self.log('ERROR', f"处理客户端 {client_id} 数据时出错: {e}", 'CLIENT')
+ self._remove_client(client_id)
+ break
+
+ def _process_data(self, client_id, data):
+ """处理从客户端接收的数据"""
+ # 将接收的字节添加到缓冲区
+ try:
+ decoded_data = data.decode('utf-8')
+ self.client_buffers[client_id] += decoded_data
+
+ # 处理可能包含多条JSON消息的缓冲区
+ self._process_buffer(client_id)
+
+ except UnicodeDecodeError as e:
+ self.log('ERROR', f"解码客户端 {client_id} 数据出错: {e}", 'CLIENT')
+
+ def _process_buffer(self, client_id):
+ """处理客户端消息缓冲区"""
+ buffer = self.client_buffers.get(client_id, "")
+
+ # 按换行符分割消息
+ while '\n' in buffer:
+ message_end = buffer.find('\n')
+ message_text = buffer[:message_end].strip()
+ buffer = buffer[message_end + 1:]
+
+ # 处理非空消息
+ if message_text:
+ try:
+ # 解析JSON消息
+ message = json.loads(message_text)
+ self.log('INFO', f"从客户端 {client_id} 接收JSON: {message}", 'CLIENT')
+
+ # 处理消息 - 实现自定义逻辑
+ self._handle_message(client_id, message)
+
+ except json.JSONDecodeError:
+ # 非JSON格式,作为原始文本处理
+ self.log('INFO', f"从客户端 {client_id} 接收文本: {message_text}", 'CLIENT')
+ self._handle_raw_message(client_id, message_text)
+
+ # 更新缓冲区
+ self.client_buffers[client_id] = buffer
+
+ def _handle_message(self, client_id, message):
+ """处理JSON消息 - 可被子类覆盖以实现自定义逻辑"""
+ # 默认实现:简单回显
+ response = {
+ "type": "response",
+ "original": message,
+ "timestamp": time.time()
+ }
+ self.send_data(client_id, response)
+
+ def _handle_raw_message(self, client_id, message):
+ """处理原始文本消息 - 可被子类覆盖以实现自定义逻辑"""
+ # 默认实现:简单回显
+ response = {
+ "type": "text_response",
+ "content": f"收到: {message}",
+ "timestamp": time.time()
+ }
+ self.send_data(client_id, response)
+
+ def send_data(self, client_id, data):
+ """向指定客户端发送JSON数据"""
+ if client_id not in self.clients:
+ self.log('WARNING', f"客户端 {client_id} 不存在,无法发送数据", 'NETWORK')
+ return False
+
+ client_socket, _ = self.clients[client_id]
+
+ try:
+ # 转换为JSON字符串,添加换行符
+ if isinstance(data, (dict, list)):
+ message = json.dumps(data) + '\n'
+ else:
+ message = str(data) + '\n'
+
+ # 发送数据
+ client_socket.sendall(message.encode('utf-8'))
+ return True
+ except Exception as e:
+ self.log('ERROR', f"向客户端 {client_id} 发送数据时出错: {e}", 'NETWORK')
+ self._remove_client(client_id)
+ return False
+
+ def broadcast(self, data, exclude=None):
+ """向所有客户端广播消息,可选排除特定客户端"""
+ exclude = exclude or []
+ for client_id in list(self.clients.keys()):
+ if client_id not in exclude:
+ self.send_data(client_id, data)
+
+ def _remove_client(self, client_id):
+ """断开并移除客户端连接"""
+ if client_id in self.clients:
+ client_socket, _ = self.clients[client_id]
+ try:
+ client_socket.close()
+ except:
+ pass
+
+ del self.clients[client_id]
+ if client_id in self.client_buffers:
+ del self.client_buffers[client_id]
+
+ self.log('INFO', f"客户端 {client_id} 已移除", 'CLIENT')
+
+ def stop(self):
+ """停止服务器"""
+ self.running = False
+
+ # 关闭所有客户端连接
+ for client_id in list(self.clients.keys()):
+ self._remove_client(client_id)
+
+ # 关闭服务器套接字
+ if self.socket:
+ try:
+ self.socket.close()
+ except:
+ pass
+
+ self.log('INFO', "服务器已停止", 'SERVER')
+
+
+# 使用示例
+if __name__ == "__main__":
+ try:
+ # 创建并启动服务器
+ server = TCPServer()
+
+ # 以阻塞方式启动服务器
+ server_thread = threading.Thread(target=server.start)
+ server_thread.daemon = True
+ server_thread.start()
+
+ # 运行直到按Ctrl+C
+ print("服务器运行中,按Ctrl+C停止...")
+ while True:
+ time.sleep(1)
+
+ except KeyboardInterrupt:
+ print("\n程序被用户中断")
+ if 'server' in locals():
+ server.stop()
+ sys.exit(0)
\ No newline at end of file
diff --git a/Server/__pycache__/QQEmailSend.cpython-313.pyc b/Server/__pycache__/QQEmailSend.cpython-313.pyc
new file mode 100644
index 0000000..0113ea2
Binary files /dev/null and b/Server/__pycache__/QQEmailSend.cpython-313.pyc differ
diff --git a/Server/__pycache__/TCPServer.cpython-313.pyc b/Server/__pycache__/TCPServer.cpython-313.pyc
new file mode 100644
index 0000000..bb004a5
Binary files /dev/null and b/Server/__pycache__/TCPServer.cpython-313.pyc differ
diff --git a/Server/__pycache__/web_admin.cpython-313.pyc b/Server/__pycache__/web_admin.cpython-313.pyc
new file mode 100644
index 0000000..d456750
Binary files /dev/null and b/Server/__pycache__/web_admin.cpython-313.pyc differ
diff --git a/Server/config/crop_data.json b/Server/config/crop_data.json
new file mode 100644
index 0000000..b6fe0a0
--- /dev/null
+++ b/Server/config/crop_data.json
@@ -0,0 +1,28 @@
+{
+ "测试作物": {"花费": 1, "生长时间": 3, "收益": 9999, "品质": "普通", "描述": "测试作物", "耐候性": 10, "等级": 1, "经验": 999},
+ "小麦": {"花费": 120, "生长时间": 120, "收益": 100, "品质": "普通", "描述": "基础作物,品质较低,适合新手种植", "耐候性": 10, "等级": 1, "经验": 10},
+ "稻谷": {"花费": 100, "生长时间": 240, "收益": 120, "品质": "普通", "描述": "适合大规模种植的基础作物", "耐候性": 10, "等级": 1, "经验": 10},
+ "玉米": {"花费": 70, "生长时间": 600, "收益": 90, "品质": "普通", "描述": "营养丰富的优良作物,适合稍有经验的玩家", "耐候性": 15, "等级": 2, "经验": 15},
+ "土豆": {"花费": 75, "生长时间": 360, "收益": 90, "品质": "普通", "描述": "容易种植的耐寒作物", "耐候性": 12, "等级": 1, "经验": 10},
+ "胡萝卜": {"花费": 60, "生长时间": 480, "收益": 80, "品质": "普通", "描述": "适合新手的健康作物", "耐候性": 12, "等级": 1, "经验": 10},
+ "草莓": {"花费": 120, "生长时间": 960, "收益": 150, "品质": "优良", "描述": "营养丰富的果实,收益不错", "耐候性": 14, "等级": 2, "经验": 20},
+ "番茄": {"花费": 100, "生长时间": 720, "收益": 130, "品质": "优良", "描述": "常见作物,适合小规模种植", "耐候性": 12, "等级": 2, "经验": 15},
+ "大豆": {"花费": 90, "生长时间": 840, "收益": 110, "品质": "优良", "描述": "富含蛋白质的基础作物", "耐候性": 11, "等级": 2, "经验": 12},
+ "蓝莓": {"花费": 150, "生长时间": 1200, "收益": 200, "品质": "稀有", "描述": "较为稀有的作物,市场价值较高", "耐候性": 18, "等级": 3, "经验": 25},
+ "洋葱": {"花费": 85, "生长时间": 600, "收益": 105, "品质": "稀有", "描述": "烹饪常用的作物,适合中级种植", "耐候性": 10, "等级": 2, "经验": 10},
+ "南瓜": {"花费": 180, "生长时间": 1440, "收益": 250, "品质": "稀有", "描述": "秋季收获的高收益作物", "耐候性": 20, "等级": 4, "经验": 30},
+ "葡萄": {"花费": 200, "生长时间": 1200, "收益": 300, "品质": "稀有", "描述": "需要特殊管理的高收益作物", "耐候性": 15, "等级": 4, "经验": 35},
+ "柿子": {"花费": 160, "生长时间": 1080, "收益": 240, "品质": "稀有", "描述": "富含营养的秋季作物", "耐候性": 18, "等级": 3, "经验": 28},
+ "花椰菜": {"花费": 130, "生长时间": 960, "收益": 170, "品质": "稀有", "描述": "耐寒的高品质作物,适合经验丰富的玩家", "耐候性": 17, "等级": 3, "经验": 22},
+ "芦笋": {"花费": 200, "生长时间": 1560, "收益": 280, "品质": "稀有", "描述": "市场需求量高的稀有作物", "耐候性": 15, "等级": 4, "经验": 30},
+ "香草": {"花费": 250, "生长时间": 1800, "收益": 400, "品质": "史诗", "描述": "非常稀有且收益极高的作物", "耐候性": 22, "等级": 5, "经验": 40},
+ "西瓜": {"花费": 240, "生长时间": 2400, "收益": 420, "品质": "史诗", "描述": "夏季丰产的高价值作物", "耐候性": 21, "等级": 5, "经验": 45},
+ "甜菜": {"花费": 220, "生长时间": 2160, "收益": 350, "品质": "史诗", "描述": "营养丰富的根茎作物,收益较高", "耐候性": 20, "等级": 5, "经验": 38},
+ "甘蔗": {"花费": 260, "生长时间": 3000, "收益": 450, "品质": "史诗", "描述": "需要充足水源的高价值作物", "耐候性": 18, "等级": 5, "经验": 50},
+ "龙果": {"花费": 400, "生长时间": 4800, "收益": 600, "品质": "传奇", "描述": "极为稀有的热带作物,产量和价值都极高", "耐候性": 25, "等级": 6, "经验": 60},
+ "松露": {"花费": 500, "生长时间": 7200, "收益": 700, "品质": "传奇", "描述": "极其珍贵的地下作物,市场价格极高", "耐候性": 23, "等级": 7, "经验": 80},
+ "人参": {"花费": 450, "生长时间": 6600, "收益": 650, "品质": "传奇", "描述": "需要耐心等待的珍贵药材", "耐候性": 22, "等级": 6, "经验": 75},
+ "富贵竹": {"花费": 450, "生长时间": 6600, "收益": 650, "品质": "传奇", "描述": "需要耐心等待的珍贵药材", "耐候性": 22, "等级": 6, "经验": 75},
+ "芦荟": {"花费": 450, "生长时间": 6600, "收益": 650, "品质": "传奇", "描述": "需要耐心等待的珍贵药材", "耐候性": 22, "等级": 6, "经验": 75},
+ "金橘": {"花费": 420, "生长时间": 4800, "收益": 620, "品质": "传奇", "描述": "少见的耐寒果树,市场需求量极大", "耐候性": 26, "等级": 7, "经验": 70}
+}
\ No newline at end of file
diff --git a/Server/config/crop_data.json.backup b/Server/config/crop_data.json.backup
new file mode 100644
index 0000000..f68165b
--- /dev/null
+++ b/Server/config/crop_data.json.backup
@@ -0,0 +1,32 @@
+{
+
+ "测试作物": {"花费": 1, "生长时间": 3, "收益": 9999, "品质": "普通", "描述": "测试作物", "耐候性": 10, "等级": 1, "经验": 999},
+
+ "小麦": {"花费": 120, "生长时间": 120, "收益": 100, "品质": "普通", "描述": "基础作物,品质较低,适合新手种植", "耐候性": 10, "等级": 1, "经验": 10},
+ "稻谷": {"花费": 100, "生长时间": 240, "收益": 120, "品质": "普通", "描述": "适合大规模种植的基础作物", "耐候性": 10, "等级": 1, "经验": 10},
+ "玉米": {"花费": 70, "生长时间": 600, "收益": 90, "品质": "普通", "描述": "营养丰富的优良作物,适合稍有经验的玩家", "耐候性": 15, "等级": 2, "经验": 15},
+ "土豆": {"花费": 75, "生长时间": 360, "收益": 90, "品质": "普通", "描述": "容易种植的耐寒作物", "耐候性": 12, "等级": 1, "经验": 10},
+ "胡萝卜": {"花费": 60, "生长时间": 480, "收益": 80, "品质": "普通", "描述": "适合新手的健康作物", "耐候性": 12, "等级": 1, "经验": 10},
+
+ "草莓": {"花费": 120, "生长时间": 960, "收益": 150, "品质": "优良", "描述": "营养丰富的果实,收益不错", "耐候性": 14, "等级": 2, "经验": 20},
+ "番茄": {"花费": 100, "生长时间": 720, "收益": 130, "品质": "优良", "描述": "常见作物,适合小规模种植", "耐候性": 12, "等级": 2, "经验": 15},
+ "大豆": {"花费": 90, "生长时间": 840, "收益": 110, "品质": "优良", "描述": "富含蛋白质的基础作物", "耐候性": 11, "等级": 2, "经验": 12},
+
+ "蓝莓": {"花费": 150, "生长时间": 1200, "收益": 200, "品质": "稀有", "描述": "较为稀有的作物,市场价值较高", "耐候性": 18, "等级": 3, "经验": 25},
+ "洋葱": {"花费": 85, "生长时间": 600, "收益": 105, "品质": "稀有", "描述": "烹饪常用的作物,适合中级种植", "耐候性": 10, "等级": 2, "经验": 10},
+ "南瓜": {"花费": 180, "生长时间": 1440, "收益": 250, "品质": "稀有", "描述": "秋季收获的高收益作物", "耐候性": 20, "等级": 4, "经验": 30},
+ "葡萄": {"花费": 200, "生长时间": 1200, "收益": 300, "品质": "稀有", "描述": "需要特殊管理的高收益作物", "耐候性": 15, "等级": 4, "经验": 35},
+ "柿子": {"花费": 160, "生长时间": 1080, "收益": 240, "品质": "稀有", "描述": "富含营养的秋季作物", "耐候性": 18, "等级": 3, "经验": 28},
+ "花椰菜": {"花费": 130, "生长时间": 960, "收益": 170, "品质": "稀有", "描述": "耐寒的高品质作物,适合经验丰富的玩家", "耐候性": 17, "等级": 3, "经验": 22},
+ "芦笋": {"花费": 200, "生长时间": 1560, "收益": 280, "品质": "稀有", "描述": "市场需求量高的稀有作物", "耐候性": 15, "等级": 4, "经验": 30},
+
+ "香草": {"花费": 250, "生长时间": 1800, "收益": 400, "品质": "史诗", "描述": "非常稀有且收益极高的作物", "耐候性": 22, "等级": 5, "经验": 40},
+ "西瓜": {"花费": 240, "生长时间": 2400, "收益": 420, "品质": "史诗", "描述": "夏季丰产的高价值作物", "耐候性": 21, "等级": 5, "经验": 45},
+ "甜菜": {"花费": 220, "生长时间": 2160, "收益": 350, "品质": "史诗", "描述": "营养丰富的根茎作物,收益较高", "耐候性": 20, "等级": 5, "经验": 38},
+ "甘蔗": {"花费": 260, "生长时间": 3000, "收益": 450, "品质": "史诗", "描述": "需要充足水源的高价值作物", "耐候性": 18, "等级": 5, "经验": 50},
+
+ "龙果": {"花费": 400, "生长时间": 4800, "收益": 600, "品质": "传奇", "描述": "极为稀有的热带作物,产量和价值都极高", "耐候性": 25, "等级": 6, "经验": 60},
+ "松露": {"花费": 500, "生长时间": 7200, "收益": 700, "品质": "传奇", "描述": "极其珍贵的地下作物,市场价格极高", "耐候性": 23, "等级": 7, "经验": 80},
+ "人参": {"花费": 450, "生长时间": 6600, "收益": 650, "品质": "传奇", "描述": "需要耐心等待的珍贵药材", "耐候性": 22, "等级": 6, "经验": 75},
+ "金橘": {"花费": 420, "生长时间": 4800, "收益": 620, "品质": "传奇", "描述": "少见的耐寒果树,市场需求量极大", "耐候性": 26, "等级": 7, "经验": 70}
+}
\ No newline at end of file
diff --git a/Server/config/initial_player_data_template.json b/Server/config/initial_player_data_template.json
new file mode 100644
index 0000000..3264e31
--- /dev/null
+++ b/Server/config/initial_player_data_template.json
@@ -0,0 +1,64 @@
+{
+ "experience": 0,
+ "level": 1,
+ "money": 1000,
+ "farm_name": "农场",
+ "user_name": "shumengya",
+ "player_name": "玩家昵称",
+ "user_password": "0123456789",
+ "last_login_time": "2025年12时09分35秒",
+ "total_login_time": "0时0分0秒",
+ "farm_lots": [
+ {"crop_type": "", "grow_time": 0, "is_dead": false, "is_diged": true, "is_planted": false, "max_grow_time": 3},
+ {"crop_type": "", "grow_time": 0, "is_dead": false, "is_diged": true, "is_planted": false, "max_grow_time": 3},
+ {"crop_type": "", "grow_time": 0, "is_dead": false, "is_diged": true, "is_planted": false, "max_grow_time": 3},
+ {"crop_type": "", "grow_time": 0, "is_dead": false, "is_diged": true, "is_planted": false, "max_grow_time": 3},
+ {"crop_type": "", "grow_time": 0, "is_dead": false, "is_diged": true, "is_planted": false, "max_grow_time": 3},
+ {"crop_type": "", "grow_time": 0, "is_dead": false, "is_diged": false, "is_planted": false, "max_grow_time": 5},
+ {"crop_type": "", "grow_time": 0, "is_dead": false, "is_diged": false, "is_planted": false, "max_grow_time": 5},
+ {"crop_type": "", "grow_time": 0, "is_dead": false, "is_diged": false, "is_planted": false, "max_grow_time": 5},
+ {"crop_type": "", "grow_time": 0, "is_dead": false, "is_diged": false, "is_planted": false, "max_grow_time": 5},
+ {"crop_type": "", "grow_time": 0, "is_dead": false, "is_diged": false, "is_planted": false, "max_grow_time": 5},
+ {"crop_type": "", "grow_time": 0, "is_dead": false, "is_diged": false, "is_planted": false, "max_grow_time": 5},
+ {"crop_type": "", "grow_time": 0, "is_dead": false, "is_diged": false, "is_planted": false, "max_grow_time": 5},
+ {"crop_type": "", "grow_time": 0, "is_dead": false, "is_diged": false, "is_planted": false, "max_grow_time": 5},
+ {"crop_type": "", "grow_time": 0, "is_dead": false, "is_diged": false, "is_planted": false, "max_grow_time": 5},
+ {"crop_type": "", "grow_time": 0, "is_dead": false, "is_diged": false, "is_planted": false, "max_grow_time": 5},
+ {"crop_type": "", "grow_time": 0, "is_dead": false, "is_diged": false, "is_planted": false, "max_grow_time": 5},
+ {"crop_type": "", "grow_time": 0, "is_dead": false, "is_diged": false, "is_planted": false, "max_grow_time": 5},
+ {"crop_type": "", "grow_time": 0, "is_dead": false, "is_diged": false, "is_planted": false, "max_grow_time": 5},
+ {"crop_type": "", "grow_time": 0, "is_dead": false, "is_diged": false, "is_planted": false, "max_grow_time": 5},
+ {"crop_type": "", "grow_time": 0, "is_dead": false, "is_diged": false, "is_planted": false, "max_grow_time": 5},
+ {"crop_type": "", "grow_time": 0, "is_dead": false, "is_diged": false, "is_planted": false, "max_grow_time": 5},
+ {"crop_type": "", "grow_time": 0, "is_dead": false, "is_diged": false, "is_planted": false, "max_grow_time": 5},
+ {"crop_type": "", "grow_time": 0, "is_dead": false, "is_diged": false, "is_planted": false, "max_grow_time": 5},
+ {"crop_type": "", "grow_time": 0, "is_dead": false, "is_diged": false, "is_planted": false, "max_grow_time": 5},
+ {"crop_type": "", "grow_time": 0, "is_dead": false, "is_diged": false, "is_planted": false, "max_grow_time": 5},
+ {"crop_type": "", "grow_time": 0, "is_dead": false, "is_diged": false, "is_planted": false, "max_grow_time": 5},
+ {"crop_type": "", "grow_time": 0, "is_dead": false, "is_diged": false, "is_planted": false, "max_grow_time": 5},
+ {"crop_type": "", "grow_time": 0, "is_dead": false, "is_diged": false, "is_planted": false, "max_grow_time": 5},
+ {"crop_type": "", "grow_time": 0, "is_dead": false, "is_diged": false, "is_planted": false, "max_grow_time": 5},
+ {"crop_type": "", "grow_time": 0, "is_dead": false, "is_diged": false, "is_planted": false, "max_grow_time": 5},
+ {"crop_type": "", "grow_time": 0, "is_dead": false, "is_diged": false, "is_planted": false, "max_grow_time": 5},
+ {"crop_type": "", "grow_time": 0, "is_dead": false, "is_diged": false, "is_planted": false, "max_grow_time": 5},
+ {"crop_type": "", "grow_time": 0, "is_dead": false, "is_diged": false, "is_planted": false, "max_grow_time": 5},
+ {"crop_type": "", "grow_time": 0, "is_dead": false, "is_diged": false, "is_planted": false, "max_grow_time": 5},
+ {"crop_type": "", "grow_time": 0, "is_dead": false, "is_diged": false, "is_planted": false, "max_grow_time": 5},
+ {"crop_type": "", "grow_time": 0, "is_dead": false, "is_diged": false, "is_planted": false, "max_grow_time": 5},
+ {"crop_type": "", "grow_time": 0, "is_dead": false, "is_diged": false, "is_planted": false, "max_grow_time": 5},
+ {"crop_type": "", "grow_time": 0, "is_dead": false, "is_diged": false, "is_planted": false, "max_grow_time": 5},
+ {"crop_type": "", "grow_time": 0, "is_dead": false, "is_diged": false, "is_planted": false, "max_grow_time": 5},
+ {"crop_type": "", "grow_time": 0, "is_dead": false, "is_diged": false, "is_planted": false, "max_grow_time": 5},
+ {"crop_type": "", "grow_time": 0, "is_dead": false, "is_diged": false, "is_planted": false, "max_grow_time": 5},
+ {"crop_type": "", "grow_time": 0, "is_dead": false, "is_diged": false, "is_planted": false, "max_grow_time": 5},
+ {"crop_type": "", "grow_time": 0, "is_dead": false, "is_diged": false, "is_planted": false, "max_grow_time": 5},
+ {"crop_type": "", "grow_time": 0, "is_dead": false, "is_diged": false, "is_planted": false, "max_grow_time": 5},
+ {"crop_type": "", "grow_time": 0, "is_dead": false, "is_diged": false, "is_planted": false, "max_grow_time": 5},
+ {"crop_type": "", "grow_time": 0, "is_dead": false, "is_diged": false, "is_planted": false, "max_grow_time": 5},
+ {"crop_type": "", "grow_time": 0, "is_dead": false, "is_diged": false, "is_planted": false, "max_grow_time": 5},
+ {"crop_type": "", "grow_time": 0, "is_dead": false, "is_diged": false, "is_planted": false, "max_grow_time": 5},
+ {"crop_type": "", "grow_time": 0, "is_dead": false, "is_diged": false, "is_planted": false, "max_grow_time": 5},
+ {"crop_type": "", "grow_time": 0, "is_dead": false, "is_diged": false, "is_planted": false, "max_grow_time": 5}
+ ],
+ "player_bag": []
+}
\ No newline at end of file
diff --git a/Server/config/verification_codes.json b/Server/config/verification_codes.json
new file mode 100644
index 0000000..a72097c
--- /dev/null
+++ b/Server/config/verification_codes.json
@@ -0,0 +1,6 @@
+{
+ "1232132": {
+ "code": "5UFH2Z",
+ "expire_at": 1748005553.6155243
+ }
+}
\ No newline at end of file
diff --git a/Server/deployment_guide.md b/Server/deployment_guide.md
new file mode 100644
index 0000000..e1f2676
--- /dev/null
+++ b/Server/deployment_guide.md
@@ -0,0 +1,124 @@
+# 萌芽农场游戏服务器部署指南
+
+## 系统要求
+- Python 3.7 或更高版本
+- 稳定的互联网连接
+- 建议:2GB+ 内存,足够的磁盘空间存储玩家数据
+
+## 安装步骤
+
+### 1. 准备环境
+```bash
+# 在服务器上创建项目文件夹
+mkdir MengYaFarm
+cd MengYaFarm
+
+# 克隆或上传服务器代码到此文件夹
+# (手动上传文件或使用Git)
+```
+
+### 2. 安装依赖
+```bash
+# 创建虚拟环境(推荐)
+python -m venv venv
+# Linux/Mac激活虚拟环境
+source venv/bin/activate
+# Windows激活虚拟环境
+# venv\Scripts\activate
+
+# 安装依赖
+pip install -r requirements.txt
+```
+
+### 3. 配置服务器
+1. 确保已创建所需文件夹:
+```bash
+mkdir -p game_saves config
+```
+
+2. 创建初始玩家数据模板 (如果尚未存在):
+```bash
+# 在config目录中创建initial_player_data_template.json
+```
+
+3. 检查 TCPGameServer.py 中的服务器地址和端口配置:
+```python
+server_host: str = "0.0.0.0" # 使用0.0.0.0允许所有网络接口访问
+server_port: int = 9000 # 确保此端口在防火墙中开放
+```
+
+4. 如需使用QQ邮箱验证功能,请在QQEmailSend.py中更新发件邮箱配置:
+```python
+SENDER_EMAIL = 'your_qq_number@qq.com' # 发件人邮箱
+SENDER_AUTH_CODE = 'your_auth_code' # 授权码
+```
+
+### 4. 启动服务器
+```bash
+# 直接启动
+python Server/TCPGameServer.py
+
+# 或使用nohup在后台运行
+nohup python Server/TCPGameServer.py > server.log 2>&1 &
+```
+
+### 5. 监控与维护
+- 服务器日志会输出到控制台或server.log
+- 玩家数据存储在game_saves文件夹中
+- 定期备份game_saves文件夹以防数据丢失
+
+### 6. 防火墙配置
+确保服务器防火墙允许TCP 9000端口的入站连接:
+
+```bash
+# Ubuntu/Debian
+sudo ufw allow 9000/tcp
+
+# CentOS/RHEL
+sudo firewall-cmd --permanent --add-port=9000/tcp
+sudo firewall-cmd --reload
+```
+
+### 7. 系统服务配置 (可选)
+可以创建systemd服务使服务器自动启动:
+
+```bash
+# 创建服务文件
+sudo nano /etc/systemd/system/mengyafarm.service
+
+# 添加以下内容
+[Unit]
+Description=MengYa Farm Game Server
+After=network.target
+
+[Service]
+Type=simple
+User=your_username
+WorkingDirectory=/path/to/MengYaFarm
+ExecStart=/path/to/MengYaFarm/venv/bin/python /path/to/MengYaFarm/Server/TCPGameServer.py
+Restart=on-failure
+RestartSec=5
+
+[Install]
+WantedBy=multi-user.target
+
+# 启用并启动服务
+sudo systemctl enable mengyafarm.service
+sudo systemctl start mengyafarm.service
+```
+
+## 常见问题
+
+### 服务器无法启动
+- 检查Python版本
+- 确认所有依赖已正确安装
+- 检查端口是否被占用
+
+### 客户端无法连接
+- 确认服务器IP和端口配置正确
+- 检查防火墙设置
+- 验证网络连接
+
+### 发送验证码失败
+- 检查QQ邮箱和授权码设置
+- 确认SMTP服务器可访问
\ No newline at end of file
diff --git a/server/game_saves/1242423.json b/Server/game_saves/2143323382.json
similarity index 76%
rename from server/game_saves/1242423.json
rename to Server/game_saves/2143323382.json
index cc58c0e..fab514a 100644
--- a/server/game_saves/1242423.json
+++ b/Server/game_saves/2143323382.json
@@ -1,5 +1,13 @@
{
"experience": 0,
+ "level": 1,
+ "money": 1000,
+ "farm_name": "柚大青の小农场",
+ "player_name": "柚大青",
+ "user_name": "2143323382",
+ "user_password": "tyh@19900420",
+ "last_login_time": "2025年05月25日16时43分38秒",
+ "total_login_time": "0时0分29秒",
"farm_lots": [
{
"crop_type": "",
@@ -285,7 +293,7 @@
"crop_type": "",
"grow_time": 0,
"is_dead": false,
- "is_diged": true,
+ "is_diged": false,
"is_planted": false,
"max_grow_time": 5
},
@@ -293,7 +301,7 @@
"crop_type": "",
"grow_time": 0,
"is_dead": false,
- "is_diged": true,
+ "is_diged": false,
"is_planted": false,
"max_grow_time": 5
},
@@ -301,7 +309,7 @@
"crop_type": "",
"grow_time": 0,
"is_dead": false,
- "is_diged": true,
+ "is_diged": false,
"is_planted": false,
"max_grow_time": 5
},
@@ -309,7 +317,7 @@
"crop_type": "",
"grow_time": 0,
"is_dead": false,
- "is_diged": true,
+ "is_diged": false,
"is_planted": false,
"max_grow_time": 5
},
@@ -317,14 +325,90 @@
"crop_type": "",
"grow_time": 0,
"is_dead": false,
- "is_diged": true,
+ "is_diged": false,
+ "is_planted": false,
+ "max_grow_time": 5
+ },
+ {
+ "crop_type": "",
+ "grow_time": 0,
+ "is_dead": false,
+ "is_diged": false,
+ "is_planted": false,
+ "max_grow_time": 5
+ },
+ {
+ "crop_type": "",
+ "grow_time": 0,
+ "is_dead": false,
+ "is_diged": false,
+ "is_planted": false,
+ "max_grow_time": 5
+ },
+ {
+ "crop_type": "",
+ "grow_time": 0,
+ "is_dead": false,
+ "is_diged": false,
+ "is_planted": false,
+ "max_grow_time": 5
+ },
+ {
+ "crop_type": "",
+ "grow_time": 0,
+ "is_dead": false,
+ "is_diged": false,
+ "is_planted": false,
+ "max_grow_time": 5
+ },
+ {
+ "crop_type": "",
+ "grow_time": 0,
+ "is_dead": false,
+ "is_diged": false,
+ "is_planted": false,
+ "max_grow_time": 5
+ },
+ {
+ "crop_type": "",
+ "grow_time": 0,
+ "is_dead": false,
+ "is_diged": false,
+ "is_planted": false,
+ "max_grow_time": 5
+ },
+ {
+ "crop_type": "",
+ "grow_time": 0,
+ "is_dead": false,
+ "is_diged": false,
+ "is_planted": false,
+ "max_grow_time": 5
+ },
+ {
+ "crop_type": "",
+ "grow_time": 0,
+ "is_dead": false,
+ "is_diged": false,
+ "is_planted": false,
+ "max_grow_time": 5
+ },
+ {
+ "crop_type": "",
+ "grow_time": 0,
+ "is_dead": false,
+ "is_diged": false,
+ "is_planted": false,
+ "max_grow_time": 5
+ },
+ {
+ "crop_type": "",
+ "grow_time": 0,
+ "is_dead": false,
+ "is_diged": false,
"is_planted": false,
"max_grow_time": 5
}
],
- "farm_name": "1234",
- "level": 0,
- "money": 1000,
- "user_name": "1242423",
- "user_password": "1234"
+ "player_bag": []
}
\ No newline at end of file
diff --git a/Server/game_saves/3205788256.json.backup b/Server/game_saves/3205788256.json.backup
new file mode 100644
index 0000000..f0aa874
--- /dev/null
+++ b/Server/game_saves/3205788256.json.backup
@@ -0,0 +1,370 @@
+{
+ "experience": 508,
+ "farm_lots": [
+ {
+ "crop_type": "",
+ "grow_time": 0,
+ "is_dead": false,
+ "is_diged": true,
+ "is_planted": false,
+ "max_grow_time": 3
+ },
+ {
+ "crop_type": "",
+ "grow_time": 0,
+ "is_dead": false,
+ "is_diged": true,
+ "is_planted": false,
+ "max_grow_time": 3
+ },
+ {
+ "crop_type": "花椰菜",
+ "grow_time": 960,
+ "is_dead": false,
+ "is_diged": true,
+ "is_planted": true,
+ "max_grow_time": 960
+ },
+ {
+ "crop_type": "",
+ "grow_time": 0,
+ "is_dead": false,
+ "is_diged": true,
+ "is_planted": false,
+ "max_grow_time": 3
+ },
+ {
+ "crop_type": "",
+ "grow_time": 0,
+ "is_dead": false,
+ "is_diged": true,
+ "is_planted": false,
+ "max_grow_time": 3
+ },
+ {
+ "crop_type": "",
+ "grow_time": 0,
+ "is_dead": false,
+ "is_diged": true,
+ "is_planted": false,
+ "max_grow_time": 3
+ },
+ {
+ "crop_type": "",
+ "grow_time": 0,
+ "is_dead": false,
+ "is_diged": true,
+ "is_planted": false,
+ "max_grow_time": 3
+ },
+ {
+ "crop_type": "",
+ "grow_time": 0,
+ "is_dead": false,
+ "is_diged": true,
+ "is_planted": false,
+ "max_grow_time": 3
+ },
+ {
+ "crop_type": "",
+ "grow_time": 0,
+ "is_dead": false,
+ "is_diged": true,
+ "is_planted": false,
+ "max_grow_time": 4800
+ },
+ {
+ "crop_type": "",
+ "grow_time": 0,
+ "is_dead": false,
+ "is_diged": true,
+ "is_planted": false,
+ "max_grow_time": 1200
+ },
+ {
+ "crop_type": "",
+ "grow_time": 0,
+ "is_dead": false,
+ "is_diged": false,
+ "is_planted": false,
+ "max_grow_time": 5
+ },
+ {
+ "crop_type": "",
+ "grow_time": 0,
+ "is_dead": false,
+ "is_diged": false,
+ "is_planted": false,
+ "max_grow_time": 5
+ },
+ {
+ "crop_type": "",
+ "grow_time": 0,
+ "is_dead": false,
+ "is_diged": true,
+ "is_planted": false,
+ "max_grow_time": 5
+ },
+ {
+ "crop_type": "",
+ "grow_time": 0,
+ "is_dead": false,
+ "is_diged": true,
+ "is_planted": false,
+ "max_grow_time": 4800
+ },
+ {
+ "crop_type": "",
+ "grow_time": 0,
+ "is_dead": false,
+ "is_diged": true,
+ "is_planted": false,
+ "max_grow_time": 2400
+ },
+ {
+ "crop_type": "",
+ "grow_time": 0,
+ "is_dead": false,
+ "is_diged": true,
+ "is_planted": false,
+ "max_grow_time": 3
+ },
+ {
+ "crop_type": "",
+ "grow_time": 0,
+ "is_dead": false,
+ "is_diged": true,
+ "is_planted": false,
+ "max_grow_time": 3
+ },
+ {
+ "crop_type": "",
+ "grow_time": 0,
+ "is_dead": false,
+ "is_diged": true,
+ "is_planted": false,
+ "max_grow_time": 120
+ },
+ {
+ "crop_type": "",
+ "grow_time": 0,
+ "is_dead": false,
+ "is_diged": true,
+ "is_planted": false,
+ "max_grow_time": 720
+ },
+ {
+ "crop_type": "",
+ "grow_time": 0,
+ "is_dead": false,
+ "is_diged": true,
+ "is_planted": false,
+ "max_grow_time": 2400
+ },
+ {
+ "crop_type": "",
+ "grow_time": 0,
+ "is_dead": false,
+ "is_diged": false,
+ "is_planted": false,
+ "max_grow_time": 5
+ },
+ {
+ "crop_type": "",
+ "grow_time": 0,
+ "is_dead": false,
+ "is_diged": false,
+ "is_planted": false,
+ "max_grow_time": 5
+ },
+ {
+ "crop_type": "",
+ "grow_time": 0,
+ "is_dead": false,
+ "is_diged": true,
+ "is_planted": false,
+ "max_grow_time": 5
+ },
+ {
+ "crop_type": "",
+ "grow_time": 0,
+ "is_dead": false,
+ "is_diged": true,
+ "is_planted": false,
+ "max_grow_time": 5
+ },
+ {
+ "crop_type": "",
+ "grow_time": 0,
+ "is_dead": false,
+ "is_diged": true,
+ "is_planted": false,
+ "max_grow_time": 1200
+ },
+ {
+ "crop_type": "",
+ "grow_time": 0,
+ "is_dead": false,
+ "is_diged": true,
+ "is_planted": false,
+ "max_grow_time": 1800
+ },
+ {
+ "crop_type": "",
+ "grow_time": 0,
+ "is_dead": false,
+ "is_diged": true,
+ "is_planted": false,
+ "max_grow_time": 600
+ },
+ {
+ "crop_type": "",
+ "grow_time": 0,
+ "is_dead": false,
+ "is_diged": true,
+ "is_planted": false,
+ "max_grow_time": 480
+ },
+ {
+ "crop_type": "",
+ "grow_time": 0,
+ "is_dead": false,
+ "is_diged": true,
+ "is_planted": false,
+ "max_grow_time": 960
+ },
+ {
+ "crop_type": "",
+ "grow_time": 0,
+ "is_dead": false,
+ "is_diged": true,
+ "is_planted": false,
+ "max_grow_time": 960
+ },
+ {
+ "crop_type": "",
+ "grow_time": 0,
+ "is_dead": false,
+ "is_diged": false,
+ "is_planted": false,
+ "max_grow_time": 5
+ },
+ {
+ "crop_type": "",
+ "grow_time": 0,
+ "is_dead": false,
+ "is_diged": false,
+ "is_planted": false,
+ "max_grow_time": 5
+ },
+ {
+ "crop_type": "",
+ "grow_time": 0,
+ "is_dead": false,
+ "is_diged": false,
+ "is_planted": false,
+ "max_grow_time": 5
+ },
+ {
+ "crop_type": "",
+ "grow_time": 0,
+ "is_dead": false,
+ "is_diged": true,
+ "is_planted": false,
+ "max_grow_time": 5
+ },
+ {
+ "crop_type": "",
+ "grow_time": 0,
+ "is_dead": false,
+ "is_diged": true,
+ "is_planted": false,
+ "max_grow_time": 5
+ },
+ {
+ "crop_type": "",
+ "grow_time": 0,
+ "is_dead": false,
+ "is_diged": true,
+ "is_planted": false,
+ "max_grow_time": 2400
+ },
+ {
+ "crop_type": "",
+ "grow_time": 0,
+ "is_dead": false,
+ "is_diged": true,
+ "is_planted": false,
+ "max_grow_time": 3
+ },
+ {
+ "crop_type": "",
+ "grow_time": 0,
+ "is_dead": false,
+ "is_diged": true,
+ "is_planted": false,
+ "max_grow_time": 3
+ },
+ {
+ "crop_type": "",
+ "grow_time": 0,
+ "is_dead": false,
+ "is_diged": true,
+ "is_planted": false,
+ "max_grow_time": 960
+ },
+ {
+ "crop_type": "",
+ "grow_time": 0,
+ "is_dead": false,
+ "is_diged": true,
+ "is_planted": false,
+ "max_grow_time": 960
+ }
+ ],
+ "player_bag": [
+ {
+ "count": 18,
+ "name": "测试作物",
+ "quality": "普通"
+ },
+ {
+ "count": 253,
+ "name": "金橘",
+ "quality": "传奇"
+ },
+ {
+ "name": "胡萝卜",
+ "quality": "普通",
+ "count": 17
+ },
+ {
+ "name": "花椰菜",
+ "quality": "稀有",
+ "count": 11
+ },
+ {
+ "name": "芦笋",
+ "quality": "稀有",
+ "count": 8
+ },
+ {
+ "name": "草莓",
+ "quality": "优良",
+ "count": 4
+ },
+ {
+ "name": "香草",
+ "quality": "史诗",
+ "count": 3
+ }
+ ],
+ "farm_name": "树萌芽の大农场",
+ "player_name": "树萌芽",
+ "level": 36,
+ "money": 40013,
+ "last_login_time": "2025年05月24日11时51分35秒",
+ "total_login_time": "100时33分38秒",
+ "user_name": "3205788256",
+ "user_password": "tyh@19900420"
+}
\ No newline at end of file
diff --git a/Server/requirements.txt b/Server/requirements.txt
new file mode 100644
index 0000000..9a8909c
--- /dev/null
+++ b/Server/requirements.txt
@@ -0,0 +1,4 @@
+# Game Server Dependencies
+colorama>=0.4.6 # For colored terminal output
+# Email Requirements
+# Standard library dependencies are not listed (socket, threading, json, etc.)
\ No newline at end of file
diff --git a/shaders/CropProgress.gdshader b/Shader/CropProgress.gdshader
similarity index 100%
rename from shaders/CropProgress.gdshader
rename to Shader/CropProgress.gdshader
diff --git a/Shader/CropProgress.gdshader.uid b/Shader/CropProgress.gdshader.uid
new file mode 100644
index 0000000..02bb6c5
--- /dev/null
+++ b/Shader/CropProgress.gdshader.uid
@@ -0,0 +1 @@
+uid://cmrhmjs8fohm
diff --git a/Temp/login.json b/Temp/login.json
new file mode 100644
index 0000000..0f1e2ca
--- /dev/null
+++ b/Temp/login.json
@@ -0,0 +1,4 @@
+{
+ "user_name":"",
+ "password":""
+}
\ No newline at end of file
diff --git a/Test/HTTPTextureRectDemo.gd b/Test/HTTPTextureRectDemo.gd
new file mode 100644
index 0000000..c4cb8ed
--- /dev/null
+++ b/Test/HTTPTextureRectDemo.gd
@@ -0,0 +1,46 @@
+extends Control
+
+@onready var http_texture_rect = $VBoxContainer/ImageContainer/HTTPTextureRect
+@onready var url_input = $VBoxContainer/HBoxContainer/URLInput
+@onready var load_url_button = $VBoxContainer/HBoxContainer/LoadURLButton
+@onready var qq_input = $VBoxContainer/HBoxContainer2/QQInput
+@onready var load_qq_button = $VBoxContainer/HBoxContainer2/LoadQQButton
+@onready var status_label = $VBoxContainer/StatusLabel
+
+func _ready():
+ # 设置默认URL和QQ号
+ url_input.text = "https://picsum.photos/200"
+ qq_input.text = "3205788256"
+
+ # 连接按钮信号
+ load_url_button.pressed.connect(_on_load_url_button_pressed)
+ load_qq_button.pressed.connect(_on_load_qq_button_pressed)
+
+ # 连接HTTP纹理矩形的信号
+ http_texture_rect.loading_started.connect(_on_loading_started)
+ http_texture_rect.loading_finished.connect(_on_loading_finished)
+
+func _on_load_url_button_pressed():
+ var url = url_input.text.strip_edges()
+ if url.is_empty():
+ status_label.text = "状态: URL不能为空"
+ return
+
+ http_texture_rect.load_from_url(url)
+
+func _on_load_qq_button_pressed():
+ var qq_number = qq_input.text.strip_edges()
+ if qq_number.is_empty() or not qq_number.is_valid_int():
+ status_label.text = "状态: 无效的QQ号"
+ return
+
+ http_texture_rect.load_qq_avatar(qq_number)
+
+func _on_loading_started():
+ status_label.text = "状态: 正在加载..."
+
+func _on_loading_finished(success: bool):
+ if success:
+ status_label.text = "状态: 加载成功"
+ else:
+ status_label.text = "状态: 加载失败"
diff --git a/Test/HTTPTextureRectDemo.gd.uid b/Test/HTTPTextureRectDemo.gd.uid
new file mode 100644
index 0000000..1009d47
--- /dev/null
+++ b/Test/HTTPTextureRectDemo.gd.uid
@@ -0,0 +1 @@
+uid://cgylg6qxwg1f0
diff --git a/Test/HTTPTextureRectDemo.tscn b/Test/HTTPTextureRectDemo.tscn
new file mode 100644
index 0000000..218c778
--- /dev/null
+++ b/Test/HTTPTextureRectDemo.tscn
@@ -0,0 +1,76 @@
+[gd_scene load_steps=3 format=3 uid="uid://dyh0q82ytbk3v"]
+
+[ext_resource type="Script" uid="uid://cgylg6qxwg1f0" path="res://Test/HTTPTextureRectDemo.gd" id="1_vgcbi"]
+[ext_resource type="Script" uid="uid://0d2j5m6j2ema" path="res://Components/HTTPTextureRect.gd" id="2_pujh8"]
+
+[node name="HTTPTextureRectDemo" type="Control"]
+layout_mode = 3
+anchors_preset = 15
+anchor_right = 1.0
+anchor_bottom = 1.0
+grow_horizontal = 2
+grow_vertical = 2
+script = ExtResource("1_vgcbi")
+
+[node name="VBoxContainer" type="VBoxContainer" parent="."]
+layout_mode = 1
+anchors_preset = 15
+anchor_right = 1.0
+anchor_bottom = 1.0
+grow_horizontal = 2
+grow_vertical = 2
+alignment = 1
+
+[node name="Label" type="Label" parent="VBoxContainer"]
+layout_mode = 2
+text = "HTTP图像加载演示"
+horizontal_alignment = 1
+
+[node name="ImageContainer" type="CenterContainer" parent="VBoxContainer"]
+layout_mode = 2
+size_flags_vertical = 3
+
+[node name="HTTPTextureRect" type="TextureRect" parent="VBoxContainer/ImageContainer"]
+custom_minimum_size = Vector2(200, 200)
+layout_mode = 2
+stretch_mode = 5
+script = ExtResource("2_pujh8")
+
+[node name="HBoxContainer" type="HBoxContainer" parent="VBoxContainer"]
+layout_mode = 2
+alignment = 1
+
+[node name="URLLabel" type="Label" parent="VBoxContainer/HBoxContainer"]
+layout_mode = 2
+text = "URL:"
+
+[node name="URLInput" type="LineEdit" parent="VBoxContainer/HBoxContainer"]
+custom_minimum_size = Vector2(300, 0)
+layout_mode = 2
+placeholder_text = "输入HTTP图像URL"
+
+[node name="LoadURLButton" type="Button" parent="VBoxContainer/HBoxContainer"]
+layout_mode = 2
+text = "加载图像"
+
+[node name="HBoxContainer2" type="HBoxContainer" parent="VBoxContainer"]
+layout_mode = 2
+alignment = 1
+
+[node name="QQLabel" type="Label" parent="VBoxContainer/HBoxContainer2"]
+layout_mode = 2
+text = "QQ号:"
+
+[node name="QQInput" type="LineEdit" parent="VBoxContainer/HBoxContainer2"]
+custom_minimum_size = Vector2(200, 0)
+layout_mode = 2
+placeholder_text = "输入QQ号"
+
+[node name="LoadQQButton" type="Button" parent="VBoxContainer/HBoxContainer2"]
+layout_mode = 2
+text = "加载QQ头像"
+
+[node name="StatusLabel" type="Label" parent="VBoxContainer"]
+layout_mode = 2
+text = "状态: 等待加载"
+horizontal_alignment = 1
diff --git a/name.md b/Test/name.md
similarity index 100%
rename from name.md
rename to Test/name.md
diff --git a/android/build/AndroidManifest.xml b/android/build/AndroidManifest.xml
new file mode 100644
index 0000000..27c19fb
--- /dev/null
+++ b/android/build/AndroidManifest.xml
@@ -0,0 +1,31 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/android/build/res/xml/network_security_config.xml b/android/build/res/xml/network_security_config.xml
new file mode 100644
index 0000000..61afc28
--- /dev/null
+++ b/android/build/res/xml/network_security_config.xml
@@ -0,0 +1,15 @@
+
+
+
+ 192.168.1.110
+ 127.0.0.1
+ localhost
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/assets/GUI/农场名称.png b/assets/GUI/农场名称.png
new file mode 100644
index 0000000..7808bff
Binary files /dev/null and b/assets/GUI/农场名称.png differ
diff --git a/assets/GUI/农场名称.png.import b/assets/GUI/农场名称.png.import
new file mode 100644
index 0000000..b04104a
--- /dev/null
+++ b/assets/GUI/农场名称.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://clvhlo0mc3e7v"
+path="res://.godot/imported/农场名称.png-1101845a74d5743a7bffe958ff6ddc5d.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/GUI/农场名称.png"
+dest_files=["res://.godot/imported/农场名称.png-1101845a74d5743a7bffe958ff6ddc5d.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+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/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/assets/GUI/小提示.png b/assets/GUI/小提示.png
new file mode 100644
index 0000000..169931a
Binary files /dev/null and b/assets/GUI/小提示.png differ
diff --git a/assets/GUI/小提示.png.import b/assets/GUI/小提示.png.import
new file mode 100644
index 0000000..aa8ce98
--- /dev/null
+++ b/assets/GUI/小提示.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://ckqy5yq2ltax6"
+path="res://.godot/imported/小提示.png-af968d997d0bd20225a871f0c885a204.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/GUI/小提示.png"
+dest_files=["res://.godot/imported/小提示.png-af968d997d0bd20225a871f0c885a204.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+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/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/assets/GUI/服务器连接状态.png b/assets/GUI/服务器连接状态.png
new file mode 100644
index 0000000..1a7e409
Binary files /dev/null and b/assets/GUI/服务器连接状态.png differ
diff --git a/assets/GUI/服务器连接状态.png.import b/assets/GUI/服务器连接状态.png.import
new file mode 100644
index 0000000..b43581e
--- /dev/null
+++ b/assets/GUI/服务器连接状态.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://by5qcip8tel1f"
+path="res://.godot/imported/服务器连接状态.png-a55f4e8174e2bbf848a6ffd7e554646c.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/GUI/服务器连接状态.png"
+dest_files=["res://.godot/imported/服务器连接状态.png-a55f4e8174e2bbf848a6ffd7e554646c.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+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/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/assets/GUI/玩家昵称.png b/assets/GUI/玩家昵称.png
new file mode 100644
index 0000000..b65a919
Binary files /dev/null and b/assets/GUI/玩家昵称.png differ
diff --git a/assets/GUI/玩家昵称.png.import b/assets/GUI/玩家昵称.png.import
new file mode 100644
index 0000000..4df74da
--- /dev/null
+++ b/assets/GUI/玩家昵称.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://b4wi8yusmbbu8"
+path="res://.godot/imported/玩家昵称.png-1608f19521048d10cd2802563f027b42.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/GUI/玩家昵称.png"
+dest_files=["res://.godot/imported/玩家昵称.png-1608f19521048d10cd2802563f027b42.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+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/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/assets/GUI/等级.png b/assets/GUI/等级.png
new file mode 100644
index 0000000..9bedac6
Binary files /dev/null and b/assets/GUI/等级.png differ
diff --git a/assets/GUI/等级.png.import b/assets/GUI/等级.png.import
new file mode 100644
index 0000000..5e0e5bf
--- /dev/null
+++ b/assets/GUI/等级.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://c87kujyuxnx2s"
+path="res://.godot/imported/等级.png-571abcf9eb5b920577c180e41ac1eb10.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/GUI/等级.png"
+dest_files=["res://.godot/imported/等级.png-571abcf9eb5b920577c180e41ac1eb10.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+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/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/assets/GUI/经验球.png b/assets/GUI/经验球.png
new file mode 100644
index 0000000..7e668f7
Binary files /dev/null and b/assets/GUI/经验球.png differ
diff --git a/assets/GUI/经验球.png.import b/assets/GUI/经验球.png.import
new file mode 100644
index 0000000..8eae7ff
--- /dev/null
+++ b/assets/GUI/经验球.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://cwloibftcmp76"
+path="res://.godot/imported/经验球.png-e7ec652ceb5e77fccd6dbb0e0fbd7dcd.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/GUI/经验球.png"
+dest_files=["res://.godot/imported/经验球.png-e7ec652ceb5e77fccd6dbb0e0fbd7dcd.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+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/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/assets/GUI/钱币.png b/assets/GUI/钱币.png
new file mode 100644
index 0000000..1722985
Binary files /dev/null and b/assets/GUI/钱币.png differ
diff --git a/assets/GUI/钱币.png.import b/assets/GUI/钱币.png.import
new file mode 100644
index 0000000..1c6de8e
--- /dev/null
+++ b/assets/GUI/钱币.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://c6i00d35fnl12"
+path="res://.godot/imported/钱币.png-f6b277b749721715d601deace45b6e54.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/GUI/钱币.png"
+dest_files=["res://.godot/imported/钱币.png-f6b277b749721715d601deace45b6e54.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+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/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/assets/Test/g.jpg b/assets/Test/g.jpg
new file mode 100644
index 0000000..4b19045
Binary files /dev/null and b/assets/Test/g.jpg differ
diff --git a/assets/Test/g.jpg.import b/assets/Test/g.jpg.import
new file mode 100644
index 0000000..dbe4a56
--- /dev/null
+++ b/assets/Test/g.jpg.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://y4gfkorl1g4f"
+path="res://.godot/imported/g.jpg-9129d5433d811daa5a9462e7b8751277.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/Test/g.jpg"
+dest_files=["res://.godot/imported/g.jpg-9129d5433d811daa5a9462e7b8751277.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+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/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/assets/Test/g.png b/assets/Test/g.png
new file mode 100644
index 0000000..391d5f9
Binary files /dev/null and b/assets/Test/g.png differ
diff --git a/assets/Test/g.png.import b/assets/Test/g.png.import
new file mode 100644
index 0000000..9d36094
--- /dev/null
+++ b/assets/Test/g.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://c3vng0nal1wr8"
+path="res://.godot/imported/g.png-3604f64f9277adc00d21f2056f418ce3.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/Test/g.png"
+dest_files=["res://.godot/imported/g.png-3604f64f9277adc00d21f2056f418ce3.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+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/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/assets/tu.jpg b/assets/tu1.jpg
similarity index 100%
rename from assets/tu.jpg
rename to assets/tu1.jpg
diff --git a/assets/tu1.jpg.import b/assets/tu1.jpg.import
new file mode 100644
index 0000000..1e0d663
--- /dev/null
+++ b/assets/tu1.jpg.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://duoqp854aoeeg"
+path="res://.godot/imported/tu1.jpg-c72e43aa0cb817520503d62990aab61d.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/tu1.jpg"
+dest_files=["res://.godot/imported/tu1.jpg-c72e43aa0cb817520503d62990aab61d.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+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/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/assets/tu2.png b/assets/tu2.png
new file mode 100644
index 0000000..840b780
Binary files /dev/null and b/assets/tu2.png differ
diff --git a/assets/tu2.png.import b/assets/tu2.png.import
new file mode 100644
index 0000000..0be4ef7
--- /dev/null
+++ b/assets/tu2.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://d046caoogul6g"
+path="res://.godot/imported/tu2.png-5c1f2dd0cefd9388c2780247e294469e.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/tu2.png"
+dest_files=["res://.godot/imported/tu2.png-5c1f2dd0cefd9388c2780247e294469e.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+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/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/assets/tu3.png b/assets/tu3.png
new file mode 100644
index 0000000..c9f9156
Binary files /dev/null and b/assets/tu3.png differ
diff --git a/assets/tu3.png.import b/assets/tu3.png.import
new file mode 100644
index 0000000..d31aafd
--- /dev/null
+++ b/assets/tu3.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://c4l0qn0p4yav8"
+path="res://.godot/imported/tu3.png-53f50a01a12d698dc896d7552428cb9a.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/tu3.png"
+dest_files=["res://.godot/imported/tu3.png-53f50a01a12d698dc896d7552428cb9a.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+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/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/assets/作物/人参/0.png b/assets/作物/人参/0.png
new file mode 100644
index 0000000..26124c4
Binary files /dev/null and b/assets/作物/人参/0.png differ
diff --git a/assets/作物/人参/0.png.import b/assets/作物/人参/0.png.import
new file mode 100644
index 0000000..575f0a2
--- /dev/null
+++ b/assets/作物/人参/0.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://c461olyam2wi"
+path="res://.godot/imported/0.png-f9b471f54a505f90386a524550e73d6f.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/作物/人参/0.png"
+dest_files=["res://.godot/imported/0.png-f9b471f54a505f90386a524550e73d6f.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+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/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/assets/作物/人参/1.png b/assets/作物/人参/1.png
new file mode 100644
index 0000000..fce39b8
Binary files /dev/null and b/assets/作物/人参/1.png differ
diff --git a/assets/作物/人参/1.png.import b/assets/作物/人参/1.png.import
new file mode 100644
index 0000000..3cd3102
--- /dev/null
+++ b/assets/作物/人参/1.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://dgvbvhbp3ex3y"
+path="res://.godot/imported/1.png-04bacd437a08646b40fe56ae5ab69ec5.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/作物/人参/1.png"
+dest_files=["res://.godot/imported/1.png-04bacd437a08646b40fe56ae5ab69ec5.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+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/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/assets/作物/人参/2.png b/assets/作物/人参/2.png
new file mode 100644
index 0000000..7c555d6
Binary files /dev/null and b/assets/作物/人参/2.png differ
diff --git a/assets/作物/人参/2.png.import b/assets/作物/人参/2.png.import
new file mode 100644
index 0000000..bb1c5f8
--- /dev/null
+++ b/assets/作物/人参/2.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://bbl4ltdtg2qik"
+path="res://.godot/imported/2.png-d4d2dd76b180838bcbe3877a8a1ab889.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/作物/人参/2.png"
+dest_files=["res://.godot/imported/2.png-d4d2dd76b180838bcbe3877a8a1ab889.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+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/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/assets/作物/南瓜/0.png b/assets/作物/南瓜/0.png
new file mode 100644
index 0000000..7b453e4
Binary files /dev/null and b/assets/作物/南瓜/0.png differ
diff --git a/assets/作物/南瓜/0.png.import b/assets/作物/南瓜/0.png.import
new file mode 100644
index 0000000..4816621
--- /dev/null
+++ b/assets/作物/南瓜/0.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://desmvugebvk8t"
+path="res://.godot/imported/0.png-8e55385de1b1b62059f050bb8ea68ed5.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/作物/南瓜/0.png"
+dest_files=["res://.godot/imported/0.png-8e55385de1b1b62059f050bb8ea68ed5.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+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/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/assets/作物/南瓜/1.png b/assets/作物/南瓜/1.png
new file mode 100644
index 0000000..05847c2
Binary files /dev/null and b/assets/作物/南瓜/1.png differ
diff --git a/assets/作物/南瓜/1.png.import b/assets/作物/南瓜/1.png.import
new file mode 100644
index 0000000..85e6dba
--- /dev/null
+++ b/assets/作物/南瓜/1.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://c517mqa1e2rxx"
+path="res://.godot/imported/1.png-7a01077c8ecafac4ae20656d56e20ffe.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/作物/南瓜/1.png"
+dest_files=["res://.godot/imported/1.png-7a01077c8ecafac4ae20656d56e20ffe.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+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/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/assets/作物/南瓜/2.png b/assets/作物/南瓜/2.png
new file mode 100644
index 0000000..0043de7
Binary files /dev/null and b/assets/作物/南瓜/2.png differ
diff --git a/assets/作物/南瓜/2.png.import b/assets/作物/南瓜/2.png.import
new file mode 100644
index 0000000..c94082d
--- /dev/null
+++ b/assets/作物/南瓜/2.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://uu7qg2lbsn7j"
+path="res://.godot/imported/2.png-c787170238d74e6778dad182464e397d.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/作物/南瓜/2.png"
+dest_files=["res://.godot/imported/2.png-c787170238d74e6778dad182464e397d.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+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/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/assets/作物/南瓜/3.png b/assets/作物/南瓜/3.png
new file mode 100644
index 0000000..24bd540
Binary files /dev/null and b/assets/作物/南瓜/3.png differ
diff --git a/assets/作物/南瓜/3.png.import b/assets/作物/南瓜/3.png.import
new file mode 100644
index 0000000..ab1d2e4
--- /dev/null
+++ b/assets/作物/南瓜/3.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://b63b4giyj7744"
+path="res://.godot/imported/3.png-4d2c8278cc86a5936da0375fffb82b98.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/作物/南瓜/3.png"
+dest_files=["res://.godot/imported/3.png-4d2c8278cc86a5936da0375fffb82b98.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+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/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/assets/作物/南瓜/4.png b/assets/作物/南瓜/4.png
new file mode 100644
index 0000000..977d4da
Binary files /dev/null and b/assets/作物/南瓜/4.png differ
diff --git a/assets/作物/南瓜/4.png.import b/assets/作物/南瓜/4.png.import
new file mode 100644
index 0000000..ac816cf
--- /dev/null
+++ b/assets/作物/南瓜/4.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://b3spmtgjfca3v"
+path="res://.godot/imported/4.png-046eacbe6c6f135740311e69bd45add2.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/作物/南瓜/4.png"
+dest_files=["res://.godot/imported/4.png-046eacbe6c6f135740311e69bd45add2.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+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/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/assets/作物/南瓜/5.png b/assets/作物/南瓜/5.png
new file mode 100644
index 0000000..ee8a307
Binary files /dev/null and b/assets/作物/南瓜/5.png differ
diff --git a/assets/作物/南瓜/5.png.import b/assets/作物/南瓜/5.png.import
new file mode 100644
index 0000000..d030ded
--- /dev/null
+++ b/assets/作物/南瓜/5.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://bn765xfusuncp"
+path="res://.godot/imported/5.png-ab96c7c6bf55d4f99e046c6517630f8b.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/作物/南瓜/5.png"
+dest_files=["res://.godot/imported/5.png-ab96c7c6bf55d4f99e046c6517630f8b.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+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/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/assets/作物/南瓜/6.png b/assets/作物/南瓜/6.png
new file mode 100644
index 0000000..1757ee5
Binary files /dev/null and b/assets/作物/南瓜/6.png differ
diff --git a/assets/作物/南瓜/6.png.import b/assets/作物/南瓜/6.png.import
new file mode 100644
index 0000000..3a9ecb9
--- /dev/null
+++ b/assets/作物/南瓜/6.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://l18q56u3q4tj"
+path="res://.godot/imported/6.png-0b475c643db46b9db1d445fe4df0abf1.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/作物/南瓜/6.png"
+dest_files=["res://.godot/imported/6.png-0b475c643db46b9db1d445fe4df0abf1.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+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/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/assets/作物/土豆/0.png b/assets/作物/土豆/0.png
new file mode 100644
index 0000000..885f567
Binary files /dev/null and b/assets/作物/土豆/0.png differ
diff --git a/assets/作物/土豆/0.png.import b/assets/作物/土豆/0.png.import
new file mode 100644
index 0000000..a008355
--- /dev/null
+++ b/assets/作物/土豆/0.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://d0nes14soyvc8"
+path="res://.godot/imported/0.png-a4b8f3cc539e989a7c84098f47a7f71b.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/作物/土豆/0.png"
+dest_files=["res://.godot/imported/0.png-a4b8f3cc539e989a7c84098f47a7f71b.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+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/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/assets/作物/土豆/1.png b/assets/作物/土豆/1.png
new file mode 100644
index 0000000..567d1cc
Binary files /dev/null and b/assets/作物/土豆/1.png differ
diff --git a/assets/作物/土豆/1.png.import b/assets/作物/土豆/1.png.import
new file mode 100644
index 0000000..0b2eb6a
--- /dev/null
+++ b/assets/作物/土豆/1.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://jbm6pc813lg6"
+path="res://.godot/imported/1.png-92385bb34c5493275c11aa146c34f092.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/作物/土豆/1.png"
+dest_files=["res://.godot/imported/1.png-92385bb34c5493275c11aa146c34f092.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+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/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/assets/作物/土豆/2.png b/assets/作物/土豆/2.png
new file mode 100644
index 0000000..1625486
Binary files /dev/null and b/assets/作物/土豆/2.png differ
diff --git a/assets/作物/土豆/2.png.import b/assets/作物/土豆/2.png.import
new file mode 100644
index 0000000..a4d7fef
--- /dev/null
+++ b/assets/作物/土豆/2.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://e2qlfv277txk"
+path="res://.godot/imported/2.png-46e3b23d3a7b1f6af3c3efdd41898eef.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/作物/土豆/2.png"
+dest_files=["res://.godot/imported/2.png-46e3b23d3a7b1f6af3c3efdd41898eef.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+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/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/assets/作物/土豆/3.png b/assets/作物/土豆/3.png
new file mode 100644
index 0000000..7881f20
Binary files /dev/null and b/assets/作物/土豆/3.png differ
diff --git a/assets/作物/土豆/3.png.import b/assets/作物/土豆/3.png.import
new file mode 100644
index 0000000..393657b
--- /dev/null
+++ b/assets/作物/土豆/3.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://cefnaf01skn1v"
+path="res://.godot/imported/3.png-0d45ce6e437eb227fdb76a221c8119ae.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/作物/土豆/3.png"
+dest_files=["res://.godot/imported/3.png-0d45ce6e437eb227fdb76a221c8119ae.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+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/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/assets/作物/土豆/4.png b/assets/作物/土豆/4.png
new file mode 100644
index 0000000..4c15910
Binary files /dev/null and b/assets/作物/土豆/4.png differ
diff --git a/assets/作物/土豆/4.png.import b/assets/作物/土豆/4.png.import
new file mode 100644
index 0000000..9528d05
--- /dev/null
+++ b/assets/作物/土豆/4.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://dfqqeais1e0hl"
+path="res://.godot/imported/4.png-039ea98816a21347599d6c6c8098f9d0.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/作物/土豆/4.png"
+dest_files=["res://.godot/imported/4.png-039ea98816a21347599d6c6c8098f9d0.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+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/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/assets/作物/大豆/0.png b/assets/作物/大豆/0.png
new file mode 100644
index 0000000..64d30dd
Binary files /dev/null and b/assets/作物/大豆/0.png differ
diff --git a/assets/作物/大豆/0.png.import b/assets/作物/大豆/0.png.import
new file mode 100644
index 0000000..d483652
--- /dev/null
+++ b/assets/作物/大豆/0.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://7aje85pdipi"
+path="res://.godot/imported/0.png-36baec312b6e724c9039802a43ae1c7b.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/作物/大豆/0.png"
+dest_files=["res://.godot/imported/0.png-36baec312b6e724c9039802a43ae1c7b.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+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/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/assets/作物/大豆/1.png b/assets/作物/大豆/1.png
new file mode 100644
index 0000000..5646cef
Binary files /dev/null and b/assets/作物/大豆/1.png differ
diff --git a/assets/作物/大豆/1.png.import b/assets/作物/大豆/1.png.import
new file mode 100644
index 0000000..afa5171
--- /dev/null
+++ b/assets/作物/大豆/1.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://cfbxa2n322pa5"
+path="res://.godot/imported/1.png-49cf2ad5356dcb7c6ba0ac6c8d868699.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/作物/大豆/1.png"
+dest_files=["res://.godot/imported/1.png-49cf2ad5356dcb7c6ba0ac6c8d868699.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+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/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/assets/作物/大豆/2.png b/assets/作物/大豆/2.png
new file mode 100644
index 0000000..f669377
Binary files /dev/null and b/assets/作物/大豆/2.png differ
diff --git a/assets/作物/大豆/2.png.import b/assets/作物/大豆/2.png.import
new file mode 100644
index 0000000..1e0715f
--- /dev/null
+++ b/assets/作物/大豆/2.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://db37kli4ar0nq"
+path="res://.godot/imported/2.png-10cc11dee3ee978bfa9fd59cb8ef9cc7.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/作物/大豆/2.png"
+dest_files=["res://.godot/imported/2.png-10cc11dee3ee978bfa9fd59cb8ef9cc7.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+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/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/assets/作物/大豆/3.png b/assets/作物/大豆/3.png
new file mode 100644
index 0000000..0036a6f
Binary files /dev/null and b/assets/作物/大豆/3.png differ
diff --git a/assets/作物/大豆/3.png.import b/assets/作物/大豆/3.png.import
new file mode 100644
index 0000000..461e6e6
--- /dev/null
+++ b/assets/作物/大豆/3.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://epkjx5obqgrm"
+path="res://.godot/imported/3.png-d401a7ac75820003830a36637e95bc32.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/作物/大豆/3.png"
+dest_files=["res://.godot/imported/3.png-d401a7ac75820003830a36637e95bc32.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+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/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/assets/作物/大豆/4.png b/assets/作物/大豆/4.png
new file mode 100644
index 0000000..01e07f8
Binary files /dev/null and b/assets/作物/大豆/4.png differ
diff --git a/assets/作物/大豆/4.png.import b/assets/作物/大豆/4.png.import
new file mode 100644
index 0000000..74bff1b
--- /dev/null
+++ b/assets/作物/大豆/4.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://thshoto1l280"
+path="res://.godot/imported/4.png-aaa66345cdf1a7496ba65c1cfeba266f.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/作物/大豆/4.png"
+dest_files=["res://.godot/imported/4.png-aaa66345cdf1a7496ba65c1cfeba266f.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+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/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/assets/作物/小麦/0.png b/assets/作物/小麦/0.png
new file mode 100644
index 0000000..f044a47
Binary files /dev/null and b/assets/作物/小麦/0.png differ
diff --git a/assets/作物/小麦/0.png.import b/assets/作物/小麦/0.png.import
new file mode 100644
index 0000000..0171da9
--- /dev/null
+++ b/assets/作物/小麦/0.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://dp72gv5qhapwh"
+path="res://.godot/imported/0.png-2d2590663fae9927d0b175cf83a2c785.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/作物/小麦/0.png"
+dest_files=["res://.godot/imported/0.png-2d2590663fae9927d0b175cf83a2c785.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+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/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/assets/作物/小麦/1.png b/assets/作物/小麦/1.png
new file mode 100644
index 0000000..f044a47
Binary files /dev/null and b/assets/作物/小麦/1.png differ
diff --git a/assets/作物/小麦/1.png.import b/assets/作物/小麦/1.png.import
new file mode 100644
index 0000000..2e858f2
--- /dev/null
+++ b/assets/作物/小麦/1.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://bwrekiagqxbfj"
+path="res://.godot/imported/1.png-e55314fa79010f274c863f7fe31ac103.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/作物/小麦/1.png"
+dest_files=["res://.godot/imported/1.png-e55314fa79010f274c863f7fe31ac103.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+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/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/assets/作物/小麦/2.png b/assets/作物/小麦/2.png
new file mode 100644
index 0000000..0e6cd75
Binary files /dev/null and b/assets/作物/小麦/2.png differ
diff --git a/assets/作物/小麦/2.png.import b/assets/作物/小麦/2.png.import
new file mode 100644
index 0000000..f82402a
--- /dev/null
+++ b/assets/作物/小麦/2.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://dki15p22wv55e"
+path="res://.godot/imported/2.png-0cc2659ba8a739a50969aff9a360c523.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/作物/小麦/2.png"
+dest_files=["res://.godot/imported/2.png-0cc2659ba8a739a50969aff9a360c523.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+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/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/assets/作物/小麦/3.png b/assets/作物/小麦/3.png
new file mode 100644
index 0000000..5ddf083
Binary files /dev/null and b/assets/作物/小麦/3.png differ
diff --git a/assets/作物/小麦/3.png.import b/assets/作物/小麦/3.png.import
new file mode 100644
index 0000000..0a5b90c
--- /dev/null
+++ b/assets/作物/小麦/3.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://b42vuqmadb7rk"
+path="res://.godot/imported/3.png-8963398665c35bd98bf07e697cdf8ba2.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/作物/小麦/3.png"
+dest_files=["res://.godot/imported/3.png-8963398665c35bd98bf07e697cdf8ba2.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+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/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/assets/作物/小麦/4.png b/assets/作物/小麦/4.png
new file mode 100644
index 0000000..a11c8e5
Binary files /dev/null and b/assets/作物/小麦/4.png differ
diff --git a/assets/作物/小麦/4.png.import b/assets/作物/小麦/4.png.import
new file mode 100644
index 0000000..95740bc
--- /dev/null
+++ b/assets/作物/小麦/4.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://jhn2jmc36g1t"
+path="res://.godot/imported/4.png-f16c75249dc9b772dc9383d5f9abdd94.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/作物/小麦/4.png"
+dest_files=["res://.godot/imported/4.png-f16c75249dc9b772dc9383d5f9abdd94.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+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/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/assets/作物/小麦/5.png b/assets/作物/小麦/5.png
new file mode 100644
index 0000000..1c9b940
Binary files /dev/null and b/assets/作物/小麦/5.png differ
diff --git a/assets/作物/小麦/5.png.import b/assets/作物/小麦/5.png.import
new file mode 100644
index 0000000..01f2cd8
--- /dev/null
+++ b/assets/作物/小麦/5.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://dcjlys86af0f4"
+path="res://.godot/imported/5.png-92f8d5f1a8a7f6310a098ae5b17d62a5.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/作物/小麦/5.png"
+dest_files=["res://.godot/imported/5.png-92f8d5f1a8a7f6310a098ae5b17d62a5.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+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/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/assets/作物/小麦/6.png b/assets/作物/小麦/6.png
new file mode 100644
index 0000000..3ccf375
Binary files /dev/null and b/assets/作物/小麦/6.png differ
diff --git a/assets/作物/小麦/6.png.import b/assets/作物/小麦/6.png.import
new file mode 100644
index 0000000..877e194
--- /dev/null
+++ b/assets/作物/小麦/6.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://bmsqn6gpgf8f"
+path="res://.godot/imported/6.png-21260edca0af002457a3d9821a525cfb.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/作物/小麦/6.png"
+dest_files=["res://.godot/imported/6.png-21260edca0af002457a3d9821a525cfb.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+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/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/assets/作物/小麦/7.png b/assets/作物/小麦/7.png
new file mode 100644
index 0000000..a54448c
Binary files /dev/null and b/assets/作物/小麦/7.png differ
diff --git a/assets/作物/小麦/7.png.import b/assets/作物/小麦/7.png.import
new file mode 100644
index 0000000..99d068e
--- /dev/null
+++ b/assets/作物/小麦/7.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://ffc0tm6tiael"
+path="res://.godot/imported/7.png-92156afa090da6d9caa778b80138e5c1.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/作物/小麦/7.png"
+dest_files=["res://.godot/imported/7.png-92156afa090da6d9caa778b80138e5c1.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+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/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/assets/作物/小麦/8.png b/assets/作物/小麦/8.png
new file mode 100644
index 0000000..3ffe9ff
Binary files /dev/null and b/assets/作物/小麦/8.png differ
diff --git a/assets/作物/小麦/8.png.import b/assets/作物/小麦/8.png.import
new file mode 100644
index 0000000..bd4f2e0
--- /dev/null
+++ b/assets/作物/小麦/8.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://dgh0yjpehos7a"
+path="res://.godot/imported/8.png-1288b5cc2305acbd042e24d254e316e2.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/作物/小麦/8.png"
+dest_files=["res://.godot/imported/8.png-1288b5cc2305acbd042e24d254e316e2.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+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/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/assets/作物/松露/0.png b/assets/作物/松露/0.png
new file mode 100644
index 0000000..5477b1e
Binary files /dev/null and b/assets/作物/松露/0.png differ
diff --git a/assets/作物/松露/0.png.import b/assets/作物/松露/0.png.import
new file mode 100644
index 0000000..b2389f6
--- /dev/null
+++ b/assets/作物/松露/0.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://2iqortyxjwn7"
+path="res://.godot/imported/0.png-d68c88d4dfb4d8ec045b4c2bccc14f10.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/作物/松露/0.png"
+dest_files=["res://.godot/imported/0.png-d68c88d4dfb4d8ec045b4c2bccc14f10.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+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/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/assets/作物/松露/1.png b/assets/作物/松露/1.png
new file mode 100644
index 0000000..abce413
Binary files /dev/null and b/assets/作物/松露/1.png differ
diff --git a/assets/作物/松露/1.png.import b/assets/作物/松露/1.png.import
new file mode 100644
index 0000000..4ab5799
--- /dev/null
+++ b/assets/作物/松露/1.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://b6ri45r31yogd"
+path="res://.godot/imported/1.png-34e90d925bf822f5c34acba2cfdcd230.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/作物/松露/1.png"
+dest_files=["res://.godot/imported/1.png-34e90d925bf822f5c34acba2cfdcd230.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+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/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/assets/作物/松露/2.png b/assets/作物/松露/2.png
new file mode 100644
index 0000000..4f8305f
Binary files /dev/null and b/assets/作物/松露/2.png differ
diff --git a/assets/作物/松露/2.png.import b/assets/作物/松露/2.png.import
new file mode 100644
index 0000000..541ee35
--- /dev/null
+++ b/assets/作物/松露/2.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://ss2p3e3tacgq"
+path="res://.godot/imported/2.png-e26cf449a096c167c7cfa4c27748c993.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/作物/松露/2.png"
+dest_files=["res://.godot/imported/2.png-e26cf449a096c167c7cfa4c27748c993.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+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/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/assets/作物/松露/3.png b/assets/作物/松露/3.png
new file mode 100644
index 0000000..b890dd0
Binary files /dev/null and b/assets/作物/松露/3.png differ
diff --git a/assets/作物/松露/3.png.import b/assets/作物/松露/3.png.import
new file mode 100644
index 0000000..7f7970f
--- /dev/null
+++ b/assets/作物/松露/3.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://dfsij7kyddx7s"
+path="res://.godot/imported/3.png-3f3cd5a4970ad5d3f01e2be87dbcb772.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/作物/松露/3.png"
+dest_files=["res://.godot/imported/3.png-3f3cd5a4970ad5d3f01e2be87dbcb772.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+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/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/assets/作物/柿子/0.png b/assets/作物/柿子/0.png
new file mode 100644
index 0000000..0a0effb
Binary files /dev/null and b/assets/作物/柿子/0.png differ
diff --git a/assets/作物/柿子/0.png.import b/assets/作物/柿子/0.png.import
new file mode 100644
index 0000000..54831e5
--- /dev/null
+++ b/assets/作物/柿子/0.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://1bdju8hro7fe"
+path="res://.godot/imported/0.png-84436ca49602485c6d553b6170037a78.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/作物/柿子/0.png"
+dest_files=["res://.godot/imported/0.png-84436ca49602485c6d553b6170037a78.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+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/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/assets/作物/柿子/1.png b/assets/作物/柿子/1.png
new file mode 100644
index 0000000..f101991
Binary files /dev/null and b/assets/作物/柿子/1.png differ
diff --git a/assets/作物/柿子/1.png.import b/assets/作物/柿子/1.png.import
new file mode 100644
index 0000000..12a7a4f
--- /dev/null
+++ b/assets/作物/柿子/1.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://cd4iqc5qfmnem"
+path="res://.godot/imported/1.png-2b0494cf251d060478396a4298914ac2.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/作物/柿子/1.png"
+dest_files=["res://.godot/imported/1.png-2b0494cf251d060478396a4298914ac2.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+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/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/assets/作物/柿子/2.png b/assets/作物/柿子/2.png
new file mode 100644
index 0000000..1d127be
Binary files /dev/null and b/assets/作物/柿子/2.png differ
diff --git a/assets/作物/柿子/2.png.import b/assets/作物/柿子/2.png.import
new file mode 100644
index 0000000..2302c7c
--- /dev/null
+++ b/assets/作物/柿子/2.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://dam5eceq280t1"
+path="res://.godot/imported/2.png-1afb16d186fedac6061c7e0dd6e641da.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/作物/柿子/2.png"
+dest_files=["res://.godot/imported/2.png-1afb16d186fedac6061c7e0dd6e641da.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+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/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/assets/作物/柿子/3.png b/assets/作物/柿子/3.png
new file mode 100644
index 0000000..dc4c3b8
Binary files /dev/null and b/assets/作物/柿子/3.png differ
diff --git a/assets/作物/柿子/3.png.import b/assets/作物/柿子/3.png.import
new file mode 100644
index 0000000..459635f
--- /dev/null
+++ b/assets/作物/柿子/3.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://ceuhlgka5j0xj"
+path="res://.godot/imported/3.png-cc19acf0e9bdc68d29cd7fa598cf8b16.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/作物/柿子/3.png"
+dest_files=["res://.godot/imported/3.png-cc19acf0e9bdc68d29cd7fa598cf8b16.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+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/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/assets/作物/柿子/4.png b/assets/作物/柿子/4.png
new file mode 100644
index 0000000..d372584
Binary files /dev/null and b/assets/作物/柿子/4.png differ
diff --git a/assets/作物/柿子/4.png.import b/assets/作物/柿子/4.png.import
new file mode 100644
index 0000000..dbc6380
--- /dev/null
+++ b/assets/作物/柿子/4.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://cfux7p8n6ikv0"
+path="res://.godot/imported/4.png-7b9798902dbe195ec31db41cf8bfc362.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/作物/柿子/4.png"
+dest_files=["res://.godot/imported/4.png-7b9798902dbe195ec31db41cf8bfc362.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+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/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/assets/作物/柿子/5.png b/assets/作物/柿子/5.png
new file mode 100644
index 0000000..409f4c2
Binary files /dev/null and b/assets/作物/柿子/5.png differ
diff --git a/assets/作物/柿子/5.png.import b/assets/作物/柿子/5.png.import
new file mode 100644
index 0000000..ea0aeea
--- /dev/null
+++ b/assets/作物/柿子/5.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://qw18flvhbb83"
+path="res://.godot/imported/5.png-2c0aed5ef1e26fbb11fc3977c52d1a5c.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/作物/柿子/5.png"
+dest_files=["res://.godot/imported/5.png-2c0aed5ef1e26fbb11fc3977c52d1a5c.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+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/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/assets/作物/柿子/6.png b/assets/作物/柿子/6.png
new file mode 100644
index 0000000..df7f96c
Binary files /dev/null and b/assets/作物/柿子/6.png differ
diff --git a/assets/作物/柿子/6.png.import b/assets/作物/柿子/6.png.import
new file mode 100644
index 0000000..753c5ab
--- /dev/null
+++ b/assets/作物/柿子/6.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://bf6c86rl1c156"
+path="res://.godot/imported/6.png-ef286d075cee59679deb9933db98d984.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/作物/柿子/6.png"
+dest_files=["res://.godot/imported/6.png-ef286d075cee59679deb9933db98d984.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+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/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/assets/作物/柿子/7.png b/assets/作物/柿子/7.png
new file mode 100644
index 0000000..bbd571f
Binary files /dev/null and b/assets/作物/柿子/7.png differ
diff --git a/assets/作物/柿子/7.png.import b/assets/作物/柿子/7.png.import
new file mode 100644
index 0000000..f17b882
--- /dev/null
+++ b/assets/作物/柿子/7.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://dysf87k2r5iib"
+path="res://.godot/imported/7.png-aa0e60cdf1fc01cadd0dd54404ec9e15.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/作物/柿子/7.png"
+dest_files=["res://.godot/imported/7.png-aa0e60cdf1fc01cadd0dd54404ec9e15.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+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/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/assets/作物/柿子/8.png b/assets/作物/柿子/8.png
new file mode 100644
index 0000000..257b1d7
Binary files /dev/null and b/assets/作物/柿子/8.png differ
diff --git a/assets/作物/柿子/8.png.import b/assets/作物/柿子/8.png.import
new file mode 100644
index 0000000..1ac6d01
--- /dev/null
+++ b/assets/作物/柿子/8.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://ckxxdhn1stetn"
+path="res://.godot/imported/8.png-f58de77ea4aaf73748f24ebf1820d1a4.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/作物/柿子/8.png"
+dest_files=["res://.godot/imported/8.png-f58de77ea4aaf73748f24ebf1820d1a4.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+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/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/assets/作物/洋葱/0.png b/assets/作物/洋葱/0.png
new file mode 100644
index 0000000..f09ccba
Binary files /dev/null and b/assets/作物/洋葱/0.png differ
diff --git a/assets/作物/洋葱/0.png.import b/assets/作物/洋葱/0.png.import
new file mode 100644
index 0000000..9495902
--- /dev/null
+++ b/assets/作物/洋葱/0.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://bjrsp10mfpya7"
+path="res://.godot/imported/0.png-8b7db9a749e0c10afe9747df1814031e.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/作物/洋葱/0.png"
+dest_files=["res://.godot/imported/0.png-8b7db9a749e0c10afe9747df1814031e.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+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/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/assets/作物/洋葱/1.png b/assets/作物/洋葱/1.png
new file mode 100644
index 0000000..3b13aa0
Binary files /dev/null and b/assets/作物/洋葱/1.png differ
diff --git a/assets/作物/洋葱/1.png.import b/assets/作物/洋葱/1.png.import
new file mode 100644
index 0000000..844da63
--- /dev/null
+++ b/assets/作物/洋葱/1.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://doljf0iyrpx7r"
+path="res://.godot/imported/1.png-0d183cebd2abe340bfd3d75d6f5433fd.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/作物/洋葱/1.png"
+dest_files=["res://.godot/imported/1.png-0d183cebd2abe340bfd3d75d6f5433fd.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+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/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/assets/作物/洋葱/2.png b/assets/作物/洋葱/2.png
new file mode 100644
index 0000000..9ab7971
Binary files /dev/null and b/assets/作物/洋葱/2.png differ
diff --git a/assets/作物/洋葱/2.png.import b/assets/作物/洋葱/2.png.import
new file mode 100644
index 0000000..02527e5
--- /dev/null
+++ b/assets/作物/洋葱/2.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://c1vcy1aos0eg3"
+path="res://.godot/imported/2.png-ab6f4019acf379085e70f9cf969f588b.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/作物/洋葱/2.png"
+dest_files=["res://.godot/imported/2.png-ab6f4019acf379085e70f9cf969f588b.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+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/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/assets/作物/洋葱/3.png b/assets/作物/洋葱/3.png
new file mode 100644
index 0000000..27d7de8
Binary files /dev/null and b/assets/作物/洋葱/3.png differ
diff --git a/assets/作物/洋葱/3.png.import b/assets/作物/洋葱/3.png.import
new file mode 100644
index 0000000..cd724e4
--- /dev/null
+++ b/assets/作物/洋葱/3.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://bm13yjgrkk3hr"
+path="res://.godot/imported/3.png-1d06212dc06b8c72d13eb2b3474aa99f.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/作物/洋葱/3.png"
+dest_files=["res://.godot/imported/3.png-1d06212dc06b8c72d13eb2b3474aa99f.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+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/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/assets/作物/洋葱/4.png b/assets/作物/洋葱/4.png
new file mode 100644
index 0000000..985e17a
Binary files /dev/null and b/assets/作物/洋葱/4.png differ
diff --git a/assets/作物/洋葱/4.png.import b/assets/作物/洋葱/4.png.import
new file mode 100644
index 0000000..018a471
--- /dev/null
+++ b/assets/作物/洋葱/4.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://g3g1m0cc2iy4"
+path="res://.godot/imported/4.png-d0687375008cf9a46accad932a728a34.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/作物/洋葱/4.png"
+dest_files=["res://.godot/imported/4.png-d0687375008cf9a46accad932a728a34.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+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/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/assets/作物/玉米/0.png b/assets/作物/玉米/0.png
new file mode 100644
index 0000000..885f567
Binary files /dev/null and b/assets/作物/玉米/0.png differ
diff --git a/assets/作物/玉米/0.png.import b/assets/作物/玉米/0.png.import
new file mode 100644
index 0000000..912269e
--- /dev/null
+++ b/assets/作物/玉米/0.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://coeuul4lc7pmt"
+path="res://.godot/imported/0.png-9a3af25b09a90714743ad379da89420c.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/作物/玉米/0.png"
+dest_files=["res://.godot/imported/0.png-9a3af25b09a90714743ad379da89420c.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+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/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/assets/作物/玉米/1.png b/assets/作物/玉米/1.png
new file mode 100644
index 0000000..adfe7c6
Binary files /dev/null and b/assets/作物/玉米/1.png differ
diff --git a/assets/作物/玉米/1.png.import b/assets/作物/玉米/1.png.import
new file mode 100644
index 0000000..92e6c0c
--- /dev/null
+++ b/assets/作物/玉米/1.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://dp3luxblo0lr8"
+path="res://.godot/imported/1.png-6e25658f36a7b5b5ef19cc2ef4437dbe.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/作物/玉米/1.png"
+dest_files=["res://.godot/imported/1.png-6e25658f36a7b5b5ef19cc2ef4437dbe.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+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/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/assets/作物/甘蔗/0.png b/assets/作物/甘蔗/0.png
new file mode 100644
index 0000000..060ea07
Binary files /dev/null and b/assets/作物/甘蔗/0.png differ
diff --git a/assets/作物/甘蔗/0.png.import b/assets/作物/甘蔗/0.png.import
new file mode 100644
index 0000000..08ce79c
--- /dev/null
+++ b/assets/作物/甘蔗/0.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://6bx18e7gbm15"
+path="res://.godot/imported/0.png-0e0de218f61dd9b268b974ef91851059.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/作物/甘蔗/0.png"
+dest_files=["res://.godot/imported/0.png-0e0de218f61dd9b268b974ef91851059.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+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/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/assets/作物/甘蔗/1.png b/assets/作物/甘蔗/1.png
new file mode 100644
index 0000000..9017986
Binary files /dev/null and b/assets/作物/甘蔗/1.png differ
diff --git a/assets/作物/甘蔗/1.png.import b/assets/作物/甘蔗/1.png.import
new file mode 100644
index 0000000..bb32ce0
--- /dev/null
+++ b/assets/作物/甘蔗/1.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://b5r3ggi30a5k7"
+path="res://.godot/imported/1.png-4b9f49051a5c72ba8b6a7a7e5f177c08.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/作物/甘蔗/1.png"
+dest_files=["res://.godot/imported/1.png-4b9f49051a5c72ba8b6a7a7e5f177c08.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+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/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/assets/作物/甘蔗/2.png b/assets/作物/甘蔗/2.png
new file mode 100644
index 0000000..8770089
Binary files /dev/null and b/assets/作物/甘蔗/2.png differ
diff --git a/assets/作物/甘蔗/2.png.import b/assets/作物/甘蔗/2.png.import
new file mode 100644
index 0000000..b6c851b
--- /dev/null
+++ b/assets/作物/甘蔗/2.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://coq50lwgq0dct"
+path="res://.godot/imported/2.png-8c2974882b596990203b501040d949b1.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/作物/甘蔗/2.png"
+dest_files=["res://.godot/imported/2.png-8c2974882b596990203b501040d949b1.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+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/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/assets/作物/甘蔗/3.png b/assets/作物/甘蔗/3.png
new file mode 100644
index 0000000..70b78d5
Binary files /dev/null and b/assets/作物/甘蔗/3.png differ
diff --git a/assets/作物/甘蔗/3.png.import b/assets/作物/甘蔗/3.png.import
new file mode 100644
index 0000000..3925e36
--- /dev/null
+++ b/assets/作物/甘蔗/3.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://bbrtxayf6n7lc"
+path="res://.godot/imported/3.png-5794eeb8692338caac30611645ec5dd6.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/作物/甘蔗/3.png"
+dest_files=["res://.godot/imported/3.png-5794eeb8692338caac30611645ec5dd6.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+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/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/assets/作物/甘蔗/4.png b/assets/作物/甘蔗/4.png
new file mode 100644
index 0000000..7299ded
Binary files /dev/null and b/assets/作物/甘蔗/4.png differ
diff --git a/assets/作物/甘蔗/4.png.import b/assets/作物/甘蔗/4.png.import
new file mode 100644
index 0000000..cdbf7ec
--- /dev/null
+++ b/assets/作物/甘蔗/4.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://dg4d41ejpbks7"
+path="res://.godot/imported/4.png-0511717296dc1f6e1b72ca49b616621d.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/作物/甘蔗/4.png"
+dest_files=["res://.godot/imported/4.png-0511717296dc1f6e1b72ca49b616621d.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+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/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/assets/作物/甘蔗/5.png b/assets/作物/甘蔗/5.png
new file mode 100644
index 0000000..2cbbd08
Binary files /dev/null and b/assets/作物/甘蔗/5.png differ
diff --git a/assets/作物/甘蔗/5.png.import b/assets/作物/甘蔗/5.png.import
new file mode 100644
index 0000000..0e9daf8
--- /dev/null
+++ b/assets/作物/甘蔗/5.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://cu77eb1n85776"
+path="res://.godot/imported/5.png-e26199746f61239a03e13da812bb2c8e.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/作物/甘蔗/5.png"
+dest_files=["res://.godot/imported/5.png-e26199746f61239a03e13da812bb2c8e.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+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/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/assets/作物/甘蔗/6.png b/assets/作物/甘蔗/6.png
new file mode 100644
index 0000000..7ed965e
Binary files /dev/null and b/assets/作物/甘蔗/6.png differ
diff --git a/assets/作物/甘蔗/6.png.import b/assets/作物/甘蔗/6.png.import
new file mode 100644
index 0000000..5bd3484
--- /dev/null
+++ b/assets/作物/甘蔗/6.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://10irlex2sfek"
+path="res://.godot/imported/6.png-bf0cdbe50e797059963b29c0704cba3f.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/作物/甘蔗/6.png"
+dest_files=["res://.godot/imported/6.png-bf0cdbe50e797059963b29c0704cba3f.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+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/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/assets/作物/甘蔗/7.png b/assets/作物/甘蔗/7.png
new file mode 100644
index 0000000..efdff20
Binary files /dev/null and b/assets/作物/甘蔗/7.png differ
diff --git a/assets/作物/甘蔗/7.png.import b/assets/作物/甘蔗/7.png.import
new file mode 100644
index 0000000..92557f7
--- /dev/null
+++ b/assets/作物/甘蔗/7.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://c2mioarbqsnx5"
+path="res://.godot/imported/7.png-5d3ac31c1b5194ec7410d7c38f31a60c.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/作物/甘蔗/7.png"
+dest_files=["res://.godot/imported/7.png-5d3ac31c1b5194ec7410d7c38f31a60c.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+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/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/assets/作物/甜菜/0.png b/assets/作物/甜菜/0.png
new file mode 100644
index 0000000..aa495cd
Binary files /dev/null and b/assets/作物/甜菜/0.png differ
diff --git a/assets/作物/甜菜/0.png.import b/assets/作物/甜菜/0.png.import
new file mode 100644
index 0000000..c7f81c1
--- /dev/null
+++ b/assets/作物/甜菜/0.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://b8dn1eg6wlxq"
+path="res://.godot/imported/0.png-bc6293036861a1ef035c6430f2b381bd.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/作物/甜菜/0.png"
+dest_files=["res://.godot/imported/0.png-bc6293036861a1ef035c6430f2b381bd.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+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/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/assets/作物/甜菜/1.png b/assets/作物/甜菜/1.png
new file mode 100644
index 0000000..6d3b01a
Binary files /dev/null and b/assets/作物/甜菜/1.png differ
diff --git a/assets/作物/甜菜/1.png.import b/assets/作物/甜菜/1.png.import
new file mode 100644
index 0000000..e9c023e
--- /dev/null
+++ b/assets/作物/甜菜/1.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://pwfirs3wpjdu"
+path="res://.godot/imported/1.png-bd4048dd0175b0e381680f07a11255dc.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/作物/甜菜/1.png"
+dest_files=["res://.godot/imported/1.png-bd4048dd0175b0e381680f07a11255dc.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+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/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/assets/作物/甜菜/2.png b/assets/作物/甜菜/2.png
new file mode 100644
index 0000000..458dda2
Binary files /dev/null and b/assets/作物/甜菜/2.png differ
diff --git a/assets/作物/甜菜/2.png.import b/assets/作物/甜菜/2.png.import
new file mode 100644
index 0000000..6efb469
--- /dev/null
+++ b/assets/作物/甜菜/2.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://bb1wmc7wo8u2c"
+path="res://.godot/imported/2.png-eb31389ef90db794330ec505ae9b3fe7.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/作物/甜菜/2.png"
+dest_files=["res://.godot/imported/2.png-eb31389ef90db794330ec505ae9b3fe7.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+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/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/assets/作物/甜菜/3.png b/assets/作物/甜菜/3.png
new file mode 100644
index 0000000..d24b066
Binary files /dev/null and b/assets/作物/甜菜/3.png differ
diff --git a/assets/作物/甜菜/3.png.import b/assets/作物/甜菜/3.png.import
new file mode 100644
index 0000000..2532066
--- /dev/null
+++ b/assets/作物/甜菜/3.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://dl88mc1dwo2w7"
+path="res://.godot/imported/3.png-32c7fa9963aeb4c32f889ba20bb30a85.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/作物/甜菜/3.png"
+dest_files=["res://.godot/imported/3.png-32c7fa9963aeb4c32f889ba20bb30a85.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+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/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/assets/作物/甜菜/4.png b/assets/作物/甜菜/4.png
new file mode 100644
index 0000000..f600f40
Binary files /dev/null and b/assets/作物/甜菜/4.png differ
diff --git a/assets/作物/甜菜/4.png.import b/assets/作物/甜菜/4.png.import
new file mode 100644
index 0000000..1c956f7
--- /dev/null
+++ b/assets/作物/甜菜/4.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://cdks311a03s7i"
+path="res://.godot/imported/4.png-f476a1076d52d95aa28facb7255a8765.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/作物/甜菜/4.png"
+dest_files=["res://.godot/imported/4.png-f476a1076d52d95aa28facb7255a8765.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+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/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/assets/作物/番茄/20250525114400.png b/assets/作物/番茄/20250525114400.png
new file mode 100644
index 0000000..7845d06
Binary files /dev/null and b/assets/作物/番茄/20250525114400.png differ
diff --git a/assets/作物/番茄/20250525114400.png.import b/assets/作物/番茄/20250525114400.png.import
new file mode 100644
index 0000000..c11e52d
--- /dev/null
+++ b/assets/作物/番茄/20250525114400.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://dx34eq1n7ykh"
+path="res://.godot/imported/20250525114400.png-c26cf40eac4186991444d56e44d968b3.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/作物/番茄/20250525114400.png"
+dest_files=["res://.godot/imported/20250525114400.png-c26cf40eac4186991444d56e44d968b3.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+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/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/assets/作物/番茄/20250525114414.png b/assets/作物/番茄/20250525114414.png
new file mode 100644
index 0000000..54de7ee
Binary files /dev/null and b/assets/作物/番茄/20250525114414.png differ
diff --git a/assets/作物/番茄/20250525114414.png.import b/assets/作物/番茄/20250525114414.png.import
new file mode 100644
index 0000000..2a4cae7
--- /dev/null
+++ b/assets/作物/番茄/20250525114414.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://dc71c6i16herl"
+path="res://.godot/imported/20250525114414.png-621e24338a3a7e12d06733dbc61151ac.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/作物/番茄/20250525114414.png"
+dest_files=["res://.godot/imported/20250525114414.png-621e24338a3a7e12d06733dbc61151ac.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+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/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/assets/作物/番茄/20250525114429.png b/assets/作物/番茄/20250525114429.png
new file mode 100644
index 0000000..b562b87
Binary files /dev/null and b/assets/作物/番茄/20250525114429.png differ
diff --git a/assets/作物/番茄/20250525114429.png.import b/assets/作物/番茄/20250525114429.png.import
new file mode 100644
index 0000000..6b4612e
--- /dev/null
+++ b/assets/作物/番茄/20250525114429.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://cvqdm1uaqdg0d"
+path="res://.godot/imported/20250525114429.png-40fb5ec5343fde69519086c3bc98af15.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/作物/番茄/20250525114429.png"
+dest_files=["res://.godot/imported/20250525114429.png-40fb5ec5343fde69519086c3bc98af15.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+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/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/assets/作物/番茄/20250525114503.png b/assets/作物/番茄/20250525114503.png
new file mode 100644
index 0000000..5dd064f
Binary files /dev/null and b/assets/作物/番茄/20250525114503.png differ
diff --git a/assets/作物/番茄/20250525114503.png.import b/assets/作物/番茄/20250525114503.png.import
new file mode 100644
index 0000000..2241a89
--- /dev/null
+++ b/assets/作物/番茄/20250525114503.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://d1t5dw1wicw5c"
+path="res://.godot/imported/20250525114503.png-71d534aab30af97ed83f772abb36c52b.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/作物/番茄/20250525114503.png"
+dest_files=["res://.godot/imported/20250525114503.png-71d534aab30af97ed83f772abb36c52b.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+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/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/assets/作物/番茄/20250525114524.png b/assets/作物/番茄/20250525114524.png
new file mode 100644
index 0000000..69c9896
Binary files /dev/null and b/assets/作物/番茄/20250525114524.png differ
diff --git a/assets/作物/番茄/20250525114524.png.import b/assets/作物/番茄/20250525114524.png.import
new file mode 100644
index 0000000..aa608bf
--- /dev/null
+++ b/assets/作物/番茄/20250525114524.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://b760if560n2l7"
+path="res://.godot/imported/20250525114524.png-dc843122ac11aba0d2d250a4d9fb6a1e.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/作物/番茄/20250525114524.png"
+dest_files=["res://.godot/imported/20250525114524.png-dc843122ac11aba0d2d250a4d9fb6a1e.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+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/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/assets/作物/番茄/20250525114542.png b/assets/作物/番茄/20250525114542.png
new file mode 100644
index 0000000..95a3484
Binary files /dev/null and b/assets/作物/番茄/20250525114542.png differ
diff --git a/assets/作物/番茄/20250525114542.png.import b/assets/作物/番茄/20250525114542.png.import
new file mode 100644
index 0000000..36dec73
--- /dev/null
+++ b/assets/作物/番茄/20250525114542.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://ceo8frcqrkkcc"
+path="res://.godot/imported/20250525114542.png-42663e8f2f8ad4f25e0f999aa6c17461.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/作物/番茄/20250525114542.png"
+dest_files=["res://.godot/imported/20250525114542.png-42663e8f2f8ad4f25e0f999aa6c17461.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+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/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/assets/作物/稻谷/0.png b/assets/作物/稻谷/0.png
new file mode 100644
index 0000000..f848ed5
Binary files /dev/null and b/assets/作物/稻谷/0.png differ
diff --git a/assets/作物/稻谷/0.png.import b/assets/作物/稻谷/0.png.import
new file mode 100644
index 0000000..f8b8c23
--- /dev/null
+++ b/assets/作物/稻谷/0.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://66p7ser7xdcd"
+path="res://.godot/imported/0.png-1b2f8001664d9dcbfb2970a7f025a9ee.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/作物/稻谷/0.png"
+dest_files=["res://.godot/imported/0.png-1b2f8001664d9dcbfb2970a7f025a9ee.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+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/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/assets/作物/稻谷/1.png b/assets/作物/稻谷/1.png
new file mode 100644
index 0000000..e071e0a
Binary files /dev/null and b/assets/作物/稻谷/1.png differ
diff --git a/assets/作物/稻谷/1.png.import b/assets/作物/稻谷/1.png.import
new file mode 100644
index 0000000..4199338
--- /dev/null
+++ b/assets/作物/稻谷/1.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://cgog0xpol5m4h"
+path="res://.godot/imported/1.png-7a0e13a09532dcfa4c50c80d4050b246.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/作物/稻谷/1.png"
+dest_files=["res://.godot/imported/1.png-7a0e13a09532dcfa4c50c80d4050b246.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+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/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/assets/作物/稻谷/2.png b/assets/作物/稻谷/2.png
new file mode 100644
index 0000000..a0d2bd1
Binary files /dev/null and b/assets/作物/稻谷/2.png differ
diff --git a/assets/作物/稻谷/2.png.import b/assets/作物/稻谷/2.png.import
new file mode 100644
index 0000000..89c6ef6
--- /dev/null
+++ b/assets/作物/稻谷/2.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://oxkkkvhxbj2n"
+path="res://.godot/imported/2.png-959c37c42618f16fcf7666a0e06e84ea.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/作物/稻谷/2.png"
+dest_files=["res://.godot/imported/2.png-959c37c42618f16fcf7666a0e06e84ea.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+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/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/assets/作物/稻谷/3.png b/assets/作物/稻谷/3.png
new file mode 100644
index 0000000..ae69676
Binary files /dev/null and b/assets/作物/稻谷/3.png differ
diff --git a/assets/作物/稻谷/3.png.import b/assets/作物/稻谷/3.png.import
new file mode 100644
index 0000000..88f079b
--- /dev/null
+++ b/assets/作物/稻谷/3.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://c3jdu5qaa40jt"
+path="res://.godot/imported/3.png-59ac583e303b2c9e9e57b13ddf018c49.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/作物/稻谷/3.png"
+dest_files=["res://.godot/imported/3.png-59ac583e303b2c9e9e57b13ddf018c49.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+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/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/assets/作物/稻谷/4.png b/assets/作物/稻谷/4.png
new file mode 100644
index 0000000..e937042
Binary files /dev/null and b/assets/作物/稻谷/4.png differ
diff --git a/assets/作物/稻谷/4.png.import b/assets/作物/稻谷/4.png.import
new file mode 100644
index 0000000..e83c923
--- /dev/null
+++ b/assets/作物/稻谷/4.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://capktt7hcf2mi"
+path="res://.godot/imported/4.png-5421616d7f728725d823a896dac80d94.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/作物/稻谷/4.png"
+dest_files=["res://.godot/imported/4.png-5421616d7f728725d823a896dac80d94.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+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/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/assets/作物/稻谷/5.png b/assets/作物/稻谷/5.png
new file mode 100644
index 0000000..2508722
Binary files /dev/null and b/assets/作物/稻谷/5.png differ
diff --git a/assets/作物/稻谷/5.png.import b/assets/作物/稻谷/5.png.import
new file mode 100644
index 0000000..b7c2a7f
--- /dev/null
+++ b/assets/作物/稻谷/5.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://c7ik3rwhgf1yd"
+path="res://.godot/imported/5.png-e1e6446f59a662e6db5435dcdc772323.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/作物/稻谷/5.png"
+dest_files=["res://.godot/imported/5.png-e1e6446f59a662e6db5435dcdc772323.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+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/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/assets/作物/稻谷/6.png b/assets/作物/稻谷/6.png
new file mode 100644
index 0000000..633c539
Binary files /dev/null and b/assets/作物/稻谷/6.png differ
diff --git a/assets/作物/稻谷/6.png.import b/assets/作物/稻谷/6.png.import
new file mode 100644
index 0000000..52c7435
--- /dev/null
+++ b/assets/作物/稻谷/6.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://dp2w866iw6ycr"
+path="res://.godot/imported/6.png-547e2e83ceaa5d9cf8d0c8f05d0cec88.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/作物/稻谷/6.png"
+dest_files=["res://.godot/imported/6.png-547e2e83ceaa5d9cf8d0c8f05d0cec88.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+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/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/assets/作物/稻谷/7.png b/assets/作物/稻谷/7.png
new file mode 100644
index 0000000..8249136
Binary files /dev/null and b/assets/作物/稻谷/7.png differ
diff --git a/assets/作物/稻谷/7.png.import b/assets/作物/稻谷/7.png.import
new file mode 100644
index 0000000..c6d0a7c
--- /dev/null
+++ b/assets/作物/稻谷/7.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://n02macuippph"
+path="res://.godot/imported/7.png-efec93404250aff681b9decb01dc795e.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/作物/稻谷/7.png"
+dest_files=["res://.godot/imported/7.png-efec93404250aff681b9decb01dc795e.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+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/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/assets/作物/稻谷/8.png b/assets/作物/稻谷/8.png
new file mode 100644
index 0000000..fc0e5fb
Binary files /dev/null and b/assets/作物/稻谷/8.png differ
diff --git a/assets/作物/稻谷/8.png.import b/assets/作物/稻谷/8.png.import
new file mode 100644
index 0000000..2b3c1b8
--- /dev/null
+++ b/assets/作物/稻谷/8.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://bwfgnkgs4fpew"
+path="res://.godot/imported/8.png-8f2b101766d3d46d2a62c6c1a7603c86.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/作物/稻谷/8.png"
+dest_files=["res://.godot/imported/8.png-8f2b101766d3d46d2a62c6c1a7603c86.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+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/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/assets/作物/稻谷/9.png b/assets/作物/稻谷/9.png
new file mode 100644
index 0000000..9bbd8f6
Binary files /dev/null and b/assets/作物/稻谷/9.png differ
diff --git a/assets/作物/稻谷/9.png.import b/assets/作物/稻谷/9.png.import
new file mode 100644
index 0000000..47a1ef0
--- /dev/null
+++ b/assets/作物/稻谷/9.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://c8f8f37tt7cw4"
+path="res://.godot/imported/9.png-97b58d776bd44c79abbe7e0bc190a82c.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/作物/稻谷/9.png"
+dest_files=["res://.godot/imported/9.png-97b58d776bd44c79abbe7e0bc190a82c.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+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/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/assets/作物/胡萝卜/0.png b/assets/作物/胡萝卜/0.png
new file mode 100644
index 0000000..885f567
Binary files /dev/null and b/assets/作物/胡萝卜/0.png differ
diff --git a/assets/作物/胡萝卜/0.png.import b/assets/作物/胡萝卜/0.png.import
new file mode 100644
index 0000000..8e630dc
--- /dev/null
+++ b/assets/作物/胡萝卜/0.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://cwtatsted80ya"
+path="res://.godot/imported/0.png-15d10317ac4e01788e5120a917929023.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/作物/胡萝卜/0.png"
+dest_files=["res://.godot/imported/0.png-15d10317ac4e01788e5120a917929023.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+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/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/assets/作物/胡萝卜/1.png b/assets/作物/胡萝卜/1.png
new file mode 100644
index 0000000..06844ea
Binary files /dev/null and b/assets/作物/胡萝卜/1.png differ
diff --git a/assets/作物/胡萝卜/1.png.import b/assets/作物/胡萝卜/1.png.import
new file mode 100644
index 0000000..aac4f2d
--- /dev/null
+++ b/assets/作物/胡萝卜/1.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://c5lji85cnnnhe"
+path="res://.godot/imported/1.png-7ae9b48d0b2f4da52e361357613f32bf.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/作物/胡萝卜/1.png"
+dest_files=["res://.godot/imported/1.png-7ae9b48d0b2f4da52e361357613f32bf.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+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/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/assets/作物/胡萝卜/2.png b/assets/作物/胡萝卜/2.png
new file mode 100644
index 0000000..511895c
Binary files /dev/null and b/assets/作物/胡萝卜/2.png differ
diff --git a/assets/作物/胡萝卜/2.png.import b/assets/作物/胡萝卜/2.png.import
new file mode 100644
index 0000000..17ded2b
--- /dev/null
+++ b/assets/作物/胡萝卜/2.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://cwtyfnm8ofrjf"
+path="res://.godot/imported/2.png-5cb9a02f78b8a36caec8bf3075ff0980.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/作物/胡萝卜/2.png"
+dest_files=["res://.godot/imported/2.png-5cb9a02f78b8a36caec8bf3075ff0980.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+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/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/assets/作物/胡萝卜/3.png b/assets/作物/胡萝卜/3.png
new file mode 100644
index 0000000..0762bac
Binary files /dev/null and b/assets/作物/胡萝卜/3.png differ
diff --git a/assets/作物/胡萝卜/3.png.import b/assets/作物/胡萝卜/3.png.import
new file mode 100644
index 0000000..328a355
--- /dev/null
+++ b/assets/作物/胡萝卜/3.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://dfw07evekk3lt"
+path="res://.godot/imported/3.png-ceac6ad869d69f99afced2211cc1d508.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/作物/胡萝卜/3.png"
+dest_files=["res://.godot/imported/3.png-ceac6ad869d69f99afced2211cc1d508.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+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/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/assets/作物/胡萝卜/4.png b/assets/作物/胡萝卜/4.png
new file mode 100644
index 0000000..51fce6f
Binary files /dev/null and b/assets/作物/胡萝卜/4.png differ
diff --git a/assets/作物/胡萝卜/4.png.import b/assets/作物/胡萝卜/4.png.import
new file mode 100644
index 0000000..f862185
--- /dev/null
+++ b/assets/作物/胡萝卜/4.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://di3hgl70j1g2m"
+path="res://.godot/imported/4.png-e890562aad789bb5433254cf14f29e38.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/作物/胡萝卜/4.png"
+dest_files=["res://.godot/imported/4.png-e890562aad789bb5433254cf14f29e38.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+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/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/assets/作物/芦笋/0.png b/assets/作物/芦笋/0.png
new file mode 100644
index 0000000..e850978
Binary files /dev/null and b/assets/作物/芦笋/0.png differ
diff --git a/assets/作物/芦笋/0.png.import b/assets/作物/芦笋/0.png.import
new file mode 100644
index 0000000..e87a570
--- /dev/null
+++ b/assets/作物/芦笋/0.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://cjoqss5jnu61p"
+path="res://.godot/imported/0.png-5615c2a6fe10314461869f13a202b936.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/作物/芦笋/0.png"
+dest_files=["res://.godot/imported/0.png-5615c2a6fe10314461869f13a202b936.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+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/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/assets/作物/芦笋/1.png b/assets/作物/芦笋/1.png
new file mode 100644
index 0000000..52c0d9b
Binary files /dev/null and b/assets/作物/芦笋/1.png differ
diff --git a/assets/作物/芦笋/1.png.import b/assets/作物/芦笋/1.png.import
new file mode 100644
index 0000000..6e5fc0d
--- /dev/null
+++ b/assets/作物/芦笋/1.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://bi1u4hhkqydpa"
+path="res://.godot/imported/1.png-dae2c4770eda5ce71d07d4f3347a2bae.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/作物/芦笋/1.png"
+dest_files=["res://.godot/imported/1.png-dae2c4770eda5ce71d07d4f3347a2bae.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+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/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/assets/作物/芦笋/2.png b/assets/作物/芦笋/2.png
new file mode 100644
index 0000000..a5a54a9
Binary files /dev/null and b/assets/作物/芦笋/2.png differ
diff --git a/assets/作物/芦笋/2.png.import b/assets/作物/芦笋/2.png.import
new file mode 100644
index 0000000..9bec670
--- /dev/null
+++ b/assets/作物/芦笋/2.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://bchlpda7rp2xs"
+path="res://.godot/imported/2.png-388d324f592088464b8d1775da2b0db8.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/作物/芦笋/2.png"
+dest_files=["res://.godot/imported/2.png-388d324f592088464b8d1775da2b0db8.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+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/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/assets/作物/芦笋/3.png b/assets/作物/芦笋/3.png
new file mode 100644
index 0000000..8f3f157
Binary files /dev/null and b/assets/作物/芦笋/3.png differ
diff --git a/assets/作物/芦笋/3.png.import b/assets/作物/芦笋/3.png.import
new file mode 100644
index 0000000..8f2d0b1
--- /dev/null
+++ b/assets/作物/芦笋/3.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://demijtyido3rd"
+path="res://.godot/imported/3.png-871e774516b90443a9261cc885b0e538.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/作物/芦笋/3.png"
+dest_files=["res://.godot/imported/3.png-871e774516b90443a9261cc885b0e538.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+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/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/assets/作物/芦笋/4.png b/assets/作物/芦笋/4.png
new file mode 100644
index 0000000..42691a8
Binary files /dev/null and b/assets/作物/芦笋/4.png differ
diff --git a/assets/作物/芦笋/4.png.import b/assets/作物/芦笋/4.png.import
new file mode 100644
index 0000000..c864ee3
--- /dev/null
+++ b/assets/作物/芦笋/4.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://c6ebegpa0ct7d"
+path="res://.godot/imported/4.png-898d107b2eb8e7a276c9ade5f0bd6388.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/作物/芦笋/4.png"
+dest_files=["res://.godot/imported/4.png-898d107b2eb8e7a276c9ade5f0bd6388.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+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/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/assets/作物/花椰菜/0.png b/assets/作物/花椰菜/0.png
new file mode 100644
index 0000000..2046fa6
Binary files /dev/null and b/assets/作物/花椰菜/0.png differ
diff --git a/assets/作物/花椰菜/0.png.import b/assets/作物/花椰菜/0.png.import
new file mode 100644
index 0000000..e48f6b3
--- /dev/null
+++ b/assets/作物/花椰菜/0.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://bgdeojr0uah7t"
+path="res://.godot/imported/0.png-d627ab6b814d458796c247adfecf5800.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/作物/花椰菜/0.png"
+dest_files=["res://.godot/imported/0.png-d627ab6b814d458796c247adfecf5800.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+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/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/assets/作物/花椰菜/1.png b/assets/作物/花椰菜/1.png
new file mode 100644
index 0000000..7fc77d1
Binary files /dev/null and b/assets/作物/花椰菜/1.png differ
diff --git a/assets/作物/花椰菜/1.png.import b/assets/作物/花椰菜/1.png.import
new file mode 100644
index 0000000..a418d1e
--- /dev/null
+++ b/assets/作物/花椰菜/1.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://blc8u5jnma88x"
+path="res://.godot/imported/1.png-c54d18742a1d7df338b573cc6e3b1674.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/作物/花椰菜/1.png"
+dest_files=["res://.godot/imported/1.png-c54d18742a1d7df338b573cc6e3b1674.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+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/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/assets/作物/花椰菜/2.png b/assets/作物/花椰菜/2.png
new file mode 100644
index 0000000..c2c61ef
Binary files /dev/null and b/assets/作物/花椰菜/2.png differ
diff --git a/assets/作物/花椰菜/2.png.import b/assets/作物/花椰菜/2.png.import
new file mode 100644
index 0000000..fc4a907
--- /dev/null
+++ b/assets/作物/花椰菜/2.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://bx0jqnkg1s3r0"
+path="res://.godot/imported/2.png-759e0ecf2d36b46de52e3caab26362c0.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/作物/花椰菜/2.png"
+dest_files=["res://.godot/imported/2.png-759e0ecf2d36b46de52e3caab26362c0.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+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/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/assets/作物/花椰菜/3.png b/assets/作物/花椰菜/3.png
new file mode 100644
index 0000000..feec6f1
Binary files /dev/null and b/assets/作物/花椰菜/3.png differ
diff --git a/assets/作物/花椰菜/3.png.import b/assets/作物/花椰菜/3.png.import
new file mode 100644
index 0000000..c80153c
--- /dev/null
+++ b/assets/作物/花椰菜/3.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://bi2klgvolm8ux"
+path="res://.godot/imported/3.png-ba96fd7325e59ca7a392ec773caa9636.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/作物/花椰菜/3.png"
+dest_files=["res://.godot/imported/3.png-ba96fd7325e59ca7a392ec773caa9636.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+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/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/assets/作物/花椰菜/4.png b/assets/作物/花椰菜/4.png
new file mode 100644
index 0000000..157ecc6
Binary files /dev/null and b/assets/作物/花椰菜/4.png differ
diff --git a/assets/作物/花椰菜/4.png.import b/assets/作物/花椰菜/4.png.import
new file mode 100644
index 0000000..0c5ab22
--- /dev/null
+++ b/assets/作物/花椰菜/4.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://b520cloaq6lcj"
+path="res://.godot/imported/4.png-1c62abc3876fb6263fafad89fd80a608.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/作物/花椰菜/4.png"
+dest_files=["res://.godot/imported/4.png-1c62abc3876fb6263fafad89fd80a608.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+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/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/assets/作物/花椰菜/5.png b/assets/作物/花椰菜/5.png
new file mode 100644
index 0000000..ce37524
Binary files /dev/null and b/assets/作物/花椰菜/5.png differ
diff --git a/assets/作物/花椰菜/5.png.import b/assets/作物/花椰菜/5.png.import
new file mode 100644
index 0000000..3ef74a8
--- /dev/null
+++ b/assets/作物/花椰菜/5.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://chg3oop410nss"
+path="res://.godot/imported/5.png-6e7f29a08c311b13ebc4d8cac5227385.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/作物/花椰菜/5.png"
+dest_files=["res://.godot/imported/5.png-6e7f29a08c311b13ebc4d8cac5227385.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+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/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/assets/作物/花椰菜/6.png b/assets/作物/花椰菜/6.png
new file mode 100644
index 0000000..83e8cd7
Binary files /dev/null and b/assets/作物/花椰菜/6.png differ
diff --git a/assets/作物/花椰菜/6.png.import b/assets/作物/花椰菜/6.png.import
new file mode 100644
index 0000000..b79956a
--- /dev/null
+++ b/assets/作物/花椰菜/6.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://dnqut65pkh8ko"
+path="res://.godot/imported/6.png-fd5bc05ca124ef4992d4b5519fc4ad36.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/作物/花椰菜/6.png"
+dest_files=["res://.godot/imported/6.png-fd5bc05ca124ef4992d4b5519fc4ad36.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+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/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/assets/作物/草莓/0.png b/assets/作物/草莓/0.png
new file mode 100644
index 0000000..a7a2e0f
Binary files /dev/null and b/assets/作物/草莓/0.png differ
diff --git a/assets/作物/草莓/0.png.import b/assets/作物/草莓/0.png.import
new file mode 100644
index 0000000..7a4f925
--- /dev/null
+++ b/assets/作物/草莓/0.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://bi1w6k0qc4lir"
+path="res://.godot/imported/0.png-5afe2de5333c741ad5e4876db6ee9703.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/作物/草莓/0.png"
+dest_files=["res://.godot/imported/0.png-5afe2de5333c741ad5e4876db6ee9703.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+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/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/assets/作物/草莓/1.png b/assets/作物/草莓/1.png
new file mode 100644
index 0000000..1437078
Binary files /dev/null and b/assets/作物/草莓/1.png differ
diff --git a/assets/作物/草莓/1.png.import b/assets/作物/草莓/1.png.import
new file mode 100644
index 0000000..4661369
--- /dev/null
+++ b/assets/作物/草莓/1.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://dx4l6iuw3apn8"
+path="res://.godot/imported/1.png-09f372c8440e85781aa9d04417c51814.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/作物/草莓/1.png"
+dest_files=["res://.godot/imported/1.png-09f372c8440e85781aa9d04417c51814.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+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/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/assets/作物/草莓/2.png b/assets/作物/草莓/2.png
new file mode 100644
index 0000000..3344b25
Binary files /dev/null and b/assets/作物/草莓/2.png differ
diff --git a/assets/作物/草莓/2.png.import b/assets/作物/草莓/2.png.import
new file mode 100644
index 0000000..bf82cb2
--- /dev/null
+++ b/assets/作物/草莓/2.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://b4g8s23fa4st8"
+path="res://.godot/imported/2.png-26f7dd0262ff3fcab00250f1bdf5dc47.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/作物/草莓/2.png"
+dest_files=["res://.godot/imported/2.png-26f7dd0262ff3fcab00250f1bdf5dc47.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+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/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/assets/作物/草莓/3.png b/assets/作物/草莓/3.png
new file mode 100644
index 0000000..5890fe3
Binary files /dev/null and b/assets/作物/草莓/3.png differ
diff --git a/assets/作物/草莓/3.png.import b/assets/作物/草莓/3.png.import
new file mode 100644
index 0000000..4f6e8b0
--- /dev/null
+++ b/assets/作物/草莓/3.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://du1brm1rpdnxb"
+path="res://.godot/imported/3.png-91b3b2044adcd9acba1494f34b8eff56.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/作物/草莓/3.png"
+dest_files=["res://.godot/imported/3.png-91b3b2044adcd9acba1494f34b8eff56.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+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/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/assets/作物/葡萄/0.png b/assets/作物/葡萄/0.png
new file mode 100644
index 0000000..cf1d311
Binary files /dev/null and b/assets/作物/葡萄/0.png differ
diff --git a/assets/作物/葡萄/0.png.import b/assets/作物/葡萄/0.png.import
new file mode 100644
index 0000000..a49c41b
--- /dev/null
+++ b/assets/作物/葡萄/0.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://tye0qcwa4ecs"
+path="res://.godot/imported/0.png-38730186a9acbf62b0a56667577bcb30.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/作物/葡萄/0.png"
+dest_files=["res://.godot/imported/0.png-38730186a9acbf62b0a56667577bcb30.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+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/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/assets/作物/葡萄/1.png b/assets/作物/葡萄/1.png
new file mode 100644
index 0000000..9bf73ca
Binary files /dev/null and b/assets/作物/葡萄/1.png differ
diff --git a/assets/作物/葡萄/1.png.import b/assets/作物/葡萄/1.png.import
new file mode 100644
index 0000000..db3bec5
--- /dev/null
+++ b/assets/作物/葡萄/1.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://de5tr8hmg136m"
+path="res://.godot/imported/1.png-655c9fe3e05ead5ec53106f1822002b8.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/作物/葡萄/1.png"
+dest_files=["res://.godot/imported/1.png-655c9fe3e05ead5ec53106f1822002b8.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+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/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/assets/作物/葡萄/2.png b/assets/作物/葡萄/2.png
new file mode 100644
index 0000000..b5332df
Binary files /dev/null and b/assets/作物/葡萄/2.png differ
diff --git a/assets/作物/葡萄/2.png.import b/assets/作物/葡萄/2.png.import
new file mode 100644
index 0000000..adb8aa9
--- /dev/null
+++ b/assets/作物/葡萄/2.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://s5ofclxt3t7g"
+path="res://.godot/imported/2.png-b43d1e95017818e43a530249ff774a91.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/作物/葡萄/2.png"
+dest_files=["res://.godot/imported/2.png-b43d1e95017818e43a530249ff774a91.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+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/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/assets/作物/葡萄/3.png b/assets/作物/葡萄/3.png
new file mode 100644
index 0000000..b5af02c
Binary files /dev/null and b/assets/作物/葡萄/3.png differ
diff --git a/assets/作物/葡萄/3.png.import b/assets/作物/葡萄/3.png.import
new file mode 100644
index 0000000..2f716ef
--- /dev/null
+++ b/assets/作物/葡萄/3.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://cc7qohdq6uiol"
+path="res://.godot/imported/3.png-e50d3599ae06ca8c6c9686ab5e1f8b68.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/作物/葡萄/3.png"
+dest_files=["res://.godot/imported/3.png-e50d3599ae06ca8c6c9686ab5e1f8b68.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+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/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/assets/作物/葡萄/4.png b/assets/作物/葡萄/4.png
new file mode 100644
index 0000000..9774f8d
Binary files /dev/null and b/assets/作物/葡萄/4.png differ
diff --git a/assets/作物/葡萄/4.png.import b/assets/作物/葡萄/4.png.import
new file mode 100644
index 0000000..6df0a48
--- /dev/null
+++ b/assets/作物/葡萄/4.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://cysjiaou40akq"
+path="res://.godot/imported/4.png-d7662341c15f3b9700f8d73316f94905.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/作物/葡萄/4.png"
+dest_files=["res://.godot/imported/4.png-d7662341c15f3b9700f8d73316f94905.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+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/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/assets/作物/葡萄/5.png b/assets/作物/葡萄/5.png
new file mode 100644
index 0000000..ca1dc7d
Binary files /dev/null and b/assets/作物/葡萄/5.png differ
diff --git a/assets/作物/葡萄/5.png.import b/assets/作物/葡萄/5.png.import
new file mode 100644
index 0000000..0b9362e
--- /dev/null
+++ b/assets/作物/葡萄/5.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://dn503tm5u57pp"
+path="res://.godot/imported/5.png-7eccf40a6e89dcd868fb9f2a34c31512.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/作物/葡萄/5.png"
+dest_files=["res://.godot/imported/5.png-7eccf40a6e89dcd868fb9f2a34c31512.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+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/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/assets/作物/蓝莓/0.png b/assets/作物/蓝莓/0.png
new file mode 100644
index 0000000..5562545
Binary files /dev/null and b/assets/作物/蓝莓/0.png differ
diff --git a/assets/作物/蓝莓/0.png.import b/assets/作物/蓝莓/0.png.import
new file mode 100644
index 0000000..4776418
--- /dev/null
+++ b/assets/作物/蓝莓/0.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://fi2jjd2sycwv"
+path="res://.godot/imported/0.png-00199a921e333eacc64c001481c52cb2.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/作物/蓝莓/0.png"
+dest_files=["res://.godot/imported/0.png-00199a921e333eacc64c001481c52cb2.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+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/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/assets/作物/蓝莓/1.png b/assets/作物/蓝莓/1.png
new file mode 100644
index 0000000..0ec2da1
Binary files /dev/null and b/assets/作物/蓝莓/1.png differ
diff --git a/assets/作物/蓝莓/1.png.import b/assets/作物/蓝莓/1.png.import
new file mode 100644
index 0000000..52872f9
--- /dev/null
+++ b/assets/作物/蓝莓/1.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://4x4rekc6shlm"
+path="res://.godot/imported/1.png-bad68e98a372ff8c2f3033f8985d63a2.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/作物/蓝莓/1.png"
+dest_files=["res://.godot/imported/1.png-bad68e98a372ff8c2f3033f8985d63a2.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+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/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/assets/作物/蓝莓/2.png b/assets/作物/蓝莓/2.png
new file mode 100644
index 0000000..9a47bbc
Binary files /dev/null and b/assets/作物/蓝莓/2.png differ
diff --git a/assets/作物/蓝莓/2.png.import b/assets/作物/蓝莓/2.png.import
new file mode 100644
index 0000000..bf98356
--- /dev/null
+++ b/assets/作物/蓝莓/2.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://4kj8hhwuq4g6"
+path="res://.godot/imported/2.png-a8a07ee1bdbd240051705a8fbf7f927e.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/作物/蓝莓/2.png"
+dest_files=["res://.godot/imported/2.png-a8a07ee1bdbd240051705a8fbf7f927e.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+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/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/assets/作物/蓝莓/3.png b/assets/作物/蓝莓/3.png
new file mode 100644
index 0000000..d271538
Binary files /dev/null and b/assets/作物/蓝莓/3.png differ
diff --git a/assets/作物/蓝莓/3.png.import b/assets/作物/蓝莓/3.png.import
new file mode 100644
index 0000000..12b34b9
--- /dev/null
+++ b/assets/作物/蓝莓/3.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://cfv438f3lay0i"
+path="res://.godot/imported/3.png-e3c10c36e2d319fdb12a349615175cdb.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/作物/蓝莓/3.png"
+dest_files=["res://.godot/imported/3.png-e3c10c36e2d319fdb12a349615175cdb.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+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/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/assets/作物/蓝莓/4.png b/assets/作物/蓝莓/4.png
new file mode 100644
index 0000000..a976108
Binary files /dev/null and b/assets/作物/蓝莓/4.png differ
diff --git a/assets/作物/蓝莓/4.png.import b/assets/作物/蓝莓/4.png.import
new file mode 100644
index 0000000..b9a310e
--- /dev/null
+++ b/assets/作物/蓝莓/4.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://bb3ko7pooawr5"
+path="res://.godot/imported/4.png-cb72430978916fa2987828bc567a8b2d.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/作物/蓝莓/4.png"
+dest_files=["res://.godot/imported/4.png-cb72430978916fa2987828bc567a8b2d.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+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/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/assets/作物/蓝莓/5.png b/assets/作物/蓝莓/5.png
new file mode 100644
index 0000000..eb8b825
Binary files /dev/null and b/assets/作物/蓝莓/5.png differ
diff --git a/assets/作物/蓝莓/5.png.import b/assets/作物/蓝莓/5.png.import
new file mode 100644
index 0000000..a6caef3
--- /dev/null
+++ b/assets/作物/蓝莓/5.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://cxsbdvcajc01o"
+path="res://.godot/imported/5.png-dc4880ca5ff3752c9b2d9cb37bc0d241.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/作物/蓝莓/5.png"
+dest_files=["res://.godot/imported/5.png-dc4880ca5ff3752c9b2d9cb37bc0d241.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+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/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/assets/作物/西瓜/0.png b/assets/作物/西瓜/0.png
new file mode 100644
index 0000000..c3d9841
Binary files /dev/null and b/assets/作物/西瓜/0.png differ
diff --git a/assets/作物/西瓜/0.png.import b/assets/作物/西瓜/0.png.import
new file mode 100644
index 0000000..aad9ff4
--- /dev/null
+++ b/assets/作物/西瓜/0.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://cq3x62ki0huuw"
+path="res://.godot/imported/0.png-3742b6d7e1c4e282a30c5ea019f93c88.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/作物/西瓜/0.png"
+dest_files=["res://.godot/imported/0.png-3742b6d7e1c4e282a30c5ea019f93c88.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+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/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/assets/作物/西瓜/1.png b/assets/作物/西瓜/1.png
new file mode 100644
index 0000000..c720dbf
Binary files /dev/null and b/assets/作物/西瓜/1.png differ
diff --git a/assets/作物/西瓜/1.png.import b/assets/作物/西瓜/1.png.import
new file mode 100644
index 0000000..b8108ba
--- /dev/null
+++ b/assets/作物/西瓜/1.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://mlvo3ihvcswi"
+path="res://.godot/imported/1.png-a9ba38f5057b76e8bea037174fa8c089.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/作物/西瓜/1.png"
+dest_files=["res://.godot/imported/1.png-a9ba38f5057b76e8bea037174fa8c089.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+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/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/assets/作物/西瓜/2.png b/assets/作物/西瓜/2.png
new file mode 100644
index 0000000..77ca232
Binary files /dev/null and b/assets/作物/西瓜/2.png differ
diff --git a/assets/作物/西瓜/2.png.import b/assets/作物/西瓜/2.png.import
new file mode 100644
index 0000000..601dd51
--- /dev/null
+++ b/assets/作物/西瓜/2.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://bh3ndc6nifed8"
+path="res://.godot/imported/2.png-51f8d40f2cf1663d86403055a4390496.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/作物/西瓜/2.png"
+dest_files=["res://.godot/imported/2.png-51f8d40f2cf1663d86403055a4390496.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+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/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/assets/作物/西瓜/3.png b/assets/作物/西瓜/3.png
new file mode 100644
index 0000000..dfd20d5
Binary files /dev/null and b/assets/作物/西瓜/3.png differ
diff --git a/assets/作物/西瓜/3.png.import b/assets/作物/西瓜/3.png.import
new file mode 100644
index 0000000..1f3d738
--- /dev/null
+++ b/assets/作物/西瓜/3.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://4x8r4t2muf4t"
+path="res://.godot/imported/3.png-f288b9ffdd3d24ac69694912648a2c2f.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/作物/西瓜/3.png"
+dest_files=["res://.godot/imported/3.png-f288b9ffdd3d24ac69694912648a2c2f.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+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/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/assets/作物/西瓜/4.png b/assets/作物/西瓜/4.png
new file mode 100644
index 0000000..305aadc
Binary files /dev/null and b/assets/作物/西瓜/4.png differ
diff --git a/assets/作物/西瓜/4.png.import b/assets/作物/西瓜/4.png.import
new file mode 100644
index 0000000..979edd9
--- /dev/null
+++ b/assets/作物/西瓜/4.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://bbd6aykbpapjj"
+path="res://.godot/imported/4.png-dcfa99924c6cac1ff1ada3a6de88145d.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/作物/西瓜/4.png"
+dest_files=["res://.godot/imported/4.png-dcfa99924c6cac1ff1ada3a6de88145d.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+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/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/assets/作物/西瓜/5.png b/assets/作物/西瓜/5.png
new file mode 100644
index 0000000..a0c69a3
Binary files /dev/null and b/assets/作物/西瓜/5.png differ
diff --git a/assets/作物/西瓜/5.png.import b/assets/作物/西瓜/5.png.import
new file mode 100644
index 0000000..b1c3fbf
--- /dev/null
+++ b/assets/作物/西瓜/5.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://c0nmhw6qika6j"
+path="res://.godot/imported/5.png-5cc59cd8253d19264258fead63db9327.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/作物/西瓜/5.png"
+dest_files=["res://.godot/imported/5.png-5cc59cd8253d19264258fead63db9327.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+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/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/assets/作物/西瓜/6.png b/assets/作物/西瓜/6.png
new file mode 100644
index 0000000..8a9959f
Binary files /dev/null and b/assets/作物/西瓜/6.png differ
diff --git a/assets/作物/西瓜/6.png.import b/assets/作物/西瓜/6.png.import
new file mode 100644
index 0000000..ef8e645
--- /dev/null
+++ b/assets/作物/西瓜/6.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://cx75gv3q67bec"
+path="res://.godot/imported/6.png-41015a6769e425862043e6f80e81c9e5.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/作物/西瓜/6.png"
+dest_files=["res://.godot/imported/6.png-41015a6769e425862043e6f80e81c9e5.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+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/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/assets/作物/金橘/0.png b/assets/作物/金橘/0.png
new file mode 100644
index 0000000..19e7cf2
Binary files /dev/null and b/assets/作物/金橘/0.png differ
diff --git a/assets/作物/金橘/0.png.import b/assets/作物/金橘/0.png.import
new file mode 100644
index 0000000..a7193a1
--- /dev/null
+++ b/assets/作物/金橘/0.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://ic81572bfqll"
+path="res://.godot/imported/0.png-51b1c395d40ea9426a8fbf538ebe7f21.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/作物/金橘/0.png"
+dest_files=["res://.godot/imported/0.png-51b1c395d40ea9426a8fbf538ebe7f21.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+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/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/assets/作物/金橘/1.png b/assets/作物/金橘/1.png
new file mode 100644
index 0000000..5d85d23
Binary files /dev/null and b/assets/作物/金橘/1.png differ
diff --git a/assets/作物/金橘/1.png.import b/assets/作物/金橘/1.png.import
new file mode 100644
index 0000000..e3c8b63
--- /dev/null
+++ b/assets/作物/金橘/1.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://364oeghmr7bj"
+path="res://.godot/imported/1.png-62365bc565e43705d7ee7927b38bcdaa.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/作物/金橘/1.png"
+dest_files=["res://.godot/imported/1.png-62365bc565e43705d7ee7927b38bcdaa.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+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/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/assets/作物/金橘/2.png b/assets/作物/金橘/2.png
new file mode 100644
index 0000000..404f68b
Binary files /dev/null and b/assets/作物/金橘/2.png differ
diff --git a/assets/作物/金橘/2.png.import b/assets/作物/金橘/2.png.import
new file mode 100644
index 0000000..1309df6
--- /dev/null
+++ b/assets/作物/金橘/2.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://cxqwlavni0cps"
+path="res://.godot/imported/2.png-21760195e337a8529263cf401c6e024c.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/作物/金橘/2.png"
+dest_files=["res://.godot/imported/2.png-21760195e337a8529263cf401c6e024c.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+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/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/assets/作物/金橘/3.png b/assets/作物/金橘/3.png
new file mode 100644
index 0000000..7517e01
Binary files /dev/null and b/assets/作物/金橘/3.png differ
diff --git a/assets/作物/金橘/3.png.import b/assets/作物/金橘/3.png.import
new file mode 100644
index 0000000..4042f84
--- /dev/null
+++ b/assets/作物/金橘/3.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://mcpapc353utr"
+path="res://.godot/imported/3.png-a67daf809f4170978f3d586df40cd5bf.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/作物/金橘/3.png"
+dest_files=["res://.godot/imported/3.png-a67daf809f4170978f3d586df40cd5bf.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+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/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/assets/作物/金橘/4.png b/assets/作物/金橘/4.png
new file mode 100644
index 0000000..f499ccf
Binary files /dev/null and b/assets/作物/金橘/4.png differ
diff --git a/assets/作物/金橘/4.png.import b/assets/作物/金橘/4.png.import
new file mode 100644
index 0000000..bb996cd
--- /dev/null
+++ b/assets/作物/金橘/4.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://doob3ym5xqkue"
+path="res://.godot/imported/4.png-40351c27fe8a85ece550012b86fa70f4.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/作物/金橘/4.png"
+dest_files=["res://.godot/imported/4.png-40351c27fe8a85ece550012b86fa70f4.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+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/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/assets/作物/金橘/5.png b/assets/作物/金橘/5.png
new file mode 100644
index 0000000..b07f07f
Binary files /dev/null and b/assets/作物/金橘/5.png differ
diff --git a/assets/作物/金橘/5.png.import b/assets/作物/金橘/5.png.import
new file mode 100644
index 0000000..264d9b7
--- /dev/null
+++ b/assets/作物/金橘/5.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://djvap68it2ys0"
+path="res://.godot/imported/5.png-5f6c326133b55709b7cca11e09db34c4.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/作物/金橘/5.png"
+dest_files=["res://.godot/imported/5.png-5f6c326133b55709b7cca11e09db34c4.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+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/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/assets/作物/金橘/6.png b/assets/作物/金橘/6.png
new file mode 100644
index 0000000..068d9d5
Binary files /dev/null and b/assets/作物/金橘/6.png differ
diff --git a/assets/作物/金橘/6.png.import b/assets/作物/金橘/6.png.import
new file mode 100644
index 0000000..4be1f41
--- /dev/null
+++ b/assets/作物/金橘/6.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://3gu8kspy5mmj"
+path="res://.godot/imported/6.png-b7e1fe80fdac44a7b537e2edb47b99a6.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/作物/金橘/6.png"
+dest_files=["res://.godot/imported/6.png-b7e1fe80fdac44a7b537e2edb47b99a6.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+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/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/assets/作物/金橘/7.png b/assets/作物/金橘/7.png
new file mode 100644
index 0000000..7d87552
Binary files /dev/null and b/assets/作物/金橘/7.png differ
diff --git a/assets/作物/金橘/7.png.import b/assets/作物/金橘/7.png.import
new file mode 100644
index 0000000..5953140
--- /dev/null
+++ b/assets/作物/金橘/7.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://lsu3uttdfurr"
+path="res://.godot/imported/7.png-a66b5472aa7d41090bb820c9ce0e8afa.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/作物/金橘/7.png"
+dest_files=["res://.godot/imported/7.png-a66b5472aa7d41090bb820c9ce0e8afa.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+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/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/assets/作物/香草/0.png b/assets/作物/香草/0.png
new file mode 100644
index 0000000..506da7b
Binary files /dev/null and b/assets/作物/香草/0.png differ
diff --git a/assets/作物/香草/0.png.import b/assets/作物/香草/0.png.import
new file mode 100644
index 0000000..12e0cb3
--- /dev/null
+++ b/assets/作物/香草/0.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://cbao0fd55vvdu"
+path="res://.godot/imported/0.png-53fc08d01da54e71f15d397b3187fa45.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/作物/香草/0.png"
+dest_files=["res://.godot/imported/0.png-53fc08d01da54e71f15d397b3187fa45.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+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/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/assets/作物/香草/1.png b/assets/作物/香草/1.png
new file mode 100644
index 0000000..70bcfad
Binary files /dev/null and b/assets/作物/香草/1.png differ
diff --git a/assets/作物/香草/1.png.import b/assets/作物/香草/1.png.import
new file mode 100644
index 0000000..2a8c5db
--- /dev/null
+++ b/assets/作物/香草/1.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://vo1byg1amdof"
+path="res://.godot/imported/1.png-9abe5cb0ded8cd29a371e93253c025c4.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/作物/香草/1.png"
+dest_files=["res://.godot/imported/1.png-9abe5cb0ded8cd29a371e93253c025c4.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+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/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/assets/作物/香草/2.png b/assets/作物/香草/2.png
new file mode 100644
index 0000000..8d675d1
Binary files /dev/null and b/assets/作物/香草/2.png differ
diff --git a/assets/作物/香草/2.png.import b/assets/作物/香草/2.png.import
new file mode 100644
index 0000000..deccfb6
--- /dev/null
+++ b/assets/作物/香草/2.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://btchfqldgiddl"
+path="res://.godot/imported/2.png-30b94c1d6bd5b241c19733ec9cb2eee1.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/作物/香草/2.png"
+dest_files=["res://.godot/imported/2.png-30b94c1d6bd5b241c19733ec9cb2eee1.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+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/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/assets/作物/香草/3.png b/assets/作物/香草/3.png
new file mode 100644
index 0000000..7f69a59
Binary files /dev/null and b/assets/作物/香草/3.png differ
diff --git a/assets/作物/香草/3.png.import b/assets/作物/香草/3.png.import
new file mode 100644
index 0000000..7f8bf0c
--- /dev/null
+++ b/assets/作物/香草/3.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://dc7wj1je5s28q"
+path="res://.godot/imported/3.png-7388f44d69260f607c01063724ce4886.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/作物/香草/3.png"
+dest_files=["res://.godot/imported/3.png-7388f44d69260f607c01063724ce4886.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+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/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/assets/作物/默认/0.png b/assets/作物/默认/0.png
new file mode 100644
index 0000000..c3897cb
Binary files /dev/null and b/assets/作物/默认/0.png differ
diff --git a/assets/作物/默认/0.png.import b/assets/作物/默认/0.png.import
new file mode 100644
index 0000000..f8a569b
--- /dev/null
+++ b/assets/作物/默认/0.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://kdhowrc6av4g"
+path="res://.godot/imported/0.png-15c614c8b6ef776bad388aaf408f4023.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/作物/默认/0.png"
+dest_files=["res://.godot/imported/0.png-15c614c8b6ef776bad388aaf408f4023.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+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/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/assets/作物/龙果/0.png b/assets/作物/龙果/0.png
new file mode 100644
index 0000000..24c6d24
Binary files /dev/null and b/assets/作物/龙果/0.png differ
diff --git a/assets/作物/龙果/0.png.import b/assets/作物/龙果/0.png.import
new file mode 100644
index 0000000..b9e275a
--- /dev/null
+++ b/assets/作物/龙果/0.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://bs4pkkmc80l6h"
+path="res://.godot/imported/0.png-3163a16c96b63c242e45e140a3d41e00.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/作物/龙果/0.png"
+dest_files=["res://.godot/imported/0.png-3163a16c96b63c242e45e140a3d41e00.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+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/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/assets/作物/龙果/1.png b/assets/作物/龙果/1.png
new file mode 100644
index 0000000..7bf33b0
Binary files /dev/null and b/assets/作物/龙果/1.png differ
diff --git a/assets/作物/龙果/1.png.import b/assets/作物/龙果/1.png.import
new file mode 100644
index 0000000..dd6487a
--- /dev/null
+++ b/assets/作物/龙果/1.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://ca0fmindl85gm"
+path="res://.godot/imported/1.png-27694ec978f8e9d2b3be4f54065ffb05.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/作物/龙果/1.png"
+dest_files=["res://.godot/imported/1.png-27694ec978f8e9d2b3be4f54065ffb05.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+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/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/assets/作物/龙果/2.png b/assets/作物/龙果/2.png
new file mode 100644
index 0000000..8d17b53
Binary files /dev/null and b/assets/作物/龙果/2.png differ
diff --git a/assets/作物/龙果/2.png.import b/assets/作物/龙果/2.png.import
new file mode 100644
index 0000000..b722b00
--- /dev/null
+++ b/assets/作物/龙果/2.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://dtsh7d8ag1st"
+path="res://.godot/imported/2.png-2a8d64f80c46b34d0c38a6bc63417504.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/作物/龙果/2.png"
+dest_files=["res://.godot/imported/2.png-2a8d64f80c46b34d0c38a6bc63417504.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+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/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/assets/作物/龙果/3.png b/assets/作物/龙果/3.png
new file mode 100644
index 0000000..039a6d4
Binary files /dev/null and b/assets/作物/龙果/3.png differ
diff --git a/assets/作物/龙果/3.png.import b/assets/作物/龙果/3.png.import
new file mode 100644
index 0000000..732d3aa
--- /dev/null
+++ b/assets/作物/龙果/3.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://djbfevj2liy45"
+path="res://.godot/imported/3.png-100d0d7320e9c0831dc087a2e9c902a4.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/作物/龙果/3.png"
+dest_files=["res://.godot/imported/3.png-100d0d7320e9c0831dc087a2e9c902a4.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+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/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/assets/作物/龙果/4.png b/assets/作物/龙果/4.png
new file mode 100644
index 0000000..1628aa7
Binary files /dev/null and b/assets/作物/龙果/4.png differ
diff --git a/assets/作物/龙果/4.png.import b/assets/作物/龙果/4.png.import
new file mode 100644
index 0000000..e75a01c
--- /dev/null
+++ b/assets/作物/龙果/4.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://b7somcbgl4fod"
+path="res://.godot/imported/4.png-aaaff20fa154ccd324c5ec0f9990f60e.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/作物/龙果/4.png"
+dest_files=["res://.godot/imported/4.png-aaaff20fa154ccd324c5ec0f9990f60e.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+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/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/components/ToastShow.tscn b/components/ToastShow.tscn
index 8a99774..bbec46e 100644
--- a/components/ToastShow.tscn
+++ b/components/ToastShow.tscn
@@ -1,6 +1,6 @@
[gd_scene load_steps=2 format=3 uid="uid://ffw2vjwnwvew"]
-[ext_resource type="Script" path="res://components/ToastShow.gd" id="1_0rpwy"]
+[ext_resource type="Script" uid="uid://caly13tf4ni1d" path="res://Components/ToastShow.gd" id="1_0rpwy"]
[node name="ToastShow" type="PanelContainer"]
offset_left = 469.0
diff --git a/crop_item.tscn b/crop_item.tscn
deleted file mode 100644
index 5ac38eb..0000000
--- a/crop_item.tscn
+++ /dev/null
@@ -1,36 +0,0 @@
-[gd_scene load_steps=3 format=3 uid="uid://bkivlkirrx6u8"]
-
-[ext_resource type="Texture2D" uid="uid://bo5oinxbn65rw" path="res://assets/tu.jpg" id="1_stl1w"]
-[ext_resource type="Script" path="res://SMY_ProgressBar.gd" id="2_1n4xp"]
-
-[node name="CropItem" type="Button"]
-custom_minimum_size = Vector2(100, 100)
-offset_right = 40.0
-offset_bottom = 40.0
-
-[node name="background" type="Sprite2D" parent="."]
-position = Vector2(50.15, 49.975)
-scale = Vector2(0.147923, 0.156084)
-texture = ExtResource("1_stl1w")
-
-[node name="ProgressBar" type="ProgressBar" parent="."]
-layout_mode = 2
-offset_top = 86.0
-offset_right = 495.0
-offset_bottom = 159.0
-scale = Vector2(0.2, 0.2)
-theme_override_font_sizes/font_size = 50
-script = ExtResource("2_1n4xp")
-
-[node name="crop_sprite" type="AnimatedSprite2D" parent="."]
-
-[node name="Label" type="Label" parent="."]
-layout_mode = 2
-offset_right = 250.0
-offset_bottom = 55.0
-scale = Vector2(0.4, 0.4)
-size_flags_horizontal = 3
-theme_override_font_sizes/font_size = 40
-text = "[普通-超萝卜]"
-horizontal_alignment = 1
-vertical_alignment = 1
diff --git a/game_camera.gd b/game_camera.gd
new file mode 100644
index 0000000..43d490c
--- /dev/null
+++ b/game_camera.gd
@@ -0,0 +1,133 @@
+extends Camera2D
+
+# 相机移动速度
+@export var move_speed: float = 400.0 # 每秒移动的像素数
+@export var zoom_speed: float = 0.02 # 缩放速度
+@export var min_zoom: float = 0.7 # 最小缩放值
+@export var max_zoom: float = 1.2 # 最大缩放值
+
+# 移动端触摸设置
+@export var touch_sensitivity: float = 1.0 # 触摸灵敏度
+@export var enable_touch_zoom: bool = true # 是否启用双指缩放
+
+# 移动边界(可选)
+@export var bounds_enabled: bool = false
+@export var bounds_min: Vector2 = Vector2(-1000, -1000)
+@export var bounds_max: Vector2 = Vector2(1000, 1000)
+
+var current_zoom_level: float = 1.0
+
+# 触摸相关变量
+var is_dragging: bool = false
+var last_touch_position: Vector2
+var touch_points: Dictionary = {} # 存储多点触摸信息
+var initial_zoom_distance: float = 0.0
+
+func _ready():
+ # 初始化相机
+ zoom = Vector2(current_zoom_level, current_zoom_level)
+
+
+
+func _process(delta):
+ # 处理相机移动
+ var input_dir = Vector2.ZERO
+
+ # WASD 键移动
+ if Input.is_action_pressed("ui_up") or Input.is_key_pressed(KEY_W):
+ input_dir.y -= 1
+ if Input.is_action_pressed("ui_down") or Input.is_key_pressed(KEY_S):
+ input_dir.y += 1
+ if Input.is_action_pressed("ui_left") or Input.is_key_pressed(KEY_A):
+ input_dir.x -= 1
+ if Input.is_action_pressed("ui_right") or Input.is_key_pressed(KEY_D):
+ input_dir.x += 1
+
+ # 归一化移动向量,确保对角线移动不会更快
+ if input_dir.length() > 0:
+ input_dir = input_dir.normalized()
+
+ # 相机移动
+ position += input_dir * move_speed * delta / current_zoom_level
+
+ # 如果启用了边界限制,确保相机在边界内
+ if bounds_enabled:
+ position.x = clamp(position.x, bounds_min.x, bounds_max.x)
+ position.y = clamp(position.y, bounds_min.y, bounds_max.y)
+
+ # 处理相机缩放KEY_EQUAL
+ if Input.is_key_pressed(KEY_EQUAL) or Input.is_key_pressed(KEY_KP_ADD): # + 键放大
+ zoom_camera(-zoom_speed)
+ if Input.is_key_pressed(KEY_MINUS) or Input.is_key_pressed(KEY_KP_SUBTRACT): # - 键缩小
+ zoom_camera(zoom_speed)
+
+# 处理输入事件(包括触摸和鼠标)
+func _input(event):
+ # 鼠标滚轮缩放
+ if event is InputEventMouseButton:
+ if event.button_index == MOUSE_BUTTON_WHEEL_DOWN:
+ zoom_camera(-zoom_speed)
+ elif event.button_index == MOUSE_BUTTON_WHEEL_UP:
+ zoom_camera(zoom_speed)
+
+ # 触摸开始
+ elif event is InputEventScreenTouch:
+ if event.pressed:
+ # 记录触摸点
+ touch_points[event.index] = event.position
+
+ if len(touch_points) == 1:
+ # 单指触摸,开始拖动
+ is_dragging = true
+ last_touch_position = event.position
+ elif len(touch_points) == 2 and enable_touch_zoom:
+ # 双指触摸,准备缩放
+ is_dragging = false
+ var touches = touch_points.values()
+ initial_zoom_distance = touches[0].distance_to(touches[1])
+ else:
+ # 触摸结束
+ if touch_points.has(event.index):
+ touch_points.erase(event.index)
+
+ if len(touch_points) == 0:
+ is_dragging = false
+ elif len(touch_points) == 1:
+ # 从双指回到单指,重新开始拖动
+ is_dragging = true
+ last_touch_position = touch_points.values()[0]
+
+ # 触摸拖动
+ elif event is InputEventScreenDrag:
+ if touch_points.has(event.index):
+ touch_points[event.index] = event.position
+
+ if len(touch_points) == 1 and is_dragging:
+ # 单指拖动,移动相机
+ var drag_delta = last_touch_position - event.position
+ # 根据当前缩放级别调整移动距离
+ position += drag_delta * touch_sensitivity / current_zoom_level
+
+ # 应用边界限制
+ if bounds_enabled:
+ position.x = clamp(position.x, bounds_min.x, bounds_max.x)
+ position.y = clamp(position.y, bounds_min.y, bounds_max.y)
+
+ last_touch_position = event.position
+
+ elif len(touch_points) == 2 and enable_touch_zoom:
+ # 双指缩放
+ var touches = touch_points.values()
+ var current_distance = touches[0].distance_to(touches[1])
+
+ if initial_zoom_distance > 0:
+ var zoom_factor = current_distance / initial_zoom_distance
+ var zoom_change = (zoom_factor - 1.0) * zoom_speed * 10
+ zoom_camera(zoom_change)
+
+ initial_zoom_distance = current_distance
+
+# 缩放相机
+func zoom_camera(zoom_amount):
+ current_zoom_level = clamp(current_zoom_level + zoom_amount, min_zoom, max_zoom)
+ zoom = Vector2(current_zoom_level, current_zoom_level)
diff --git a/game_camera.gd.uid b/game_camera.gd.uid
new file mode 100644
index 0000000..bb9ca5b
--- /dev/null
+++ b/game_camera.gd.uid
@@ -0,0 +1 @@
+uid://c7bxje0wvvgo4
diff --git a/project.godot b/project.godot
index eaa3a84..73e21b1 100644
--- a/project.godot
+++ b/project.godot
@@ -13,21 +13,27 @@ config_version=5
config/name="萌芽农场"
config/description="一款支持多人联机的农场游戏"
run/main_scene="res://MainGame.tscn"
-config/features=PackedStringArray("4.3", "Mobile")
+config/features=PackedStringArray("4.4", "Mobile")
config/icon="res://assets/logo2.png"
[autoload]
-Toast="*res://components/toast.gd"
+GlobalFunctions="*res://GlobalScript/GlobalFunctions.gd"
+Toast="*res://GlobalScript/Toast.gd"
+GlobalVariables="*res://GlobalScript/GlobalVariables.gd"
[display]
-window/size/resizable=false
+window/size/viewport_width=1400
+window/size/viewport_height=720
window/stretch/mode="viewport"
-window/stretch/aspect="ignore"
window/per_pixel_transparency/allowed=true
window/vsync/vsync_mode=0
+[dotnet]
+
+project/assembly_name="萌芽农场"
+
[input]
ui_save={
@@ -44,3 +50,4 @@ ui_load={
[rendering]
renderer/rendering_method="mobile"
+textures/vram_compression/import_etc2_astc=true
diff --git a/server/game_saves/3205788256.json b/server/game_saves/3205788256.json
index 6bbeb28..0a8e8e4 100644
--- a/server/game_saves/3205788256.json
+++ b/server/game_saves/3205788256.json
@@ -1,5 +1,5 @@
{
- "experience": 2407,
+ "experience": 6,
"farm_lots": [
{
"crop_type": "",
@@ -17,273 +17,57 @@
"is_planted": false,
"max_grow_time": 3
},
+ {
+ "crop_type": "",
+ "grow_time": 0,
+ "is_dead": false,
+ "is_diged": true,
+ "is_planted": false,
+ "max_grow_time": 960
+ },
+ {
+ "crop_type": "金橘",
+ "grow_time": 647,
+ "is_dead": false,
+ "is_diged": true,
+ "is_planted": true,
+ "max_grow_time": 4800
+ },
+ {
+ "crop_type": "松露",
+ "grow_time": 659,
+ "is_dead": false,
+ "is_diged": true,
+ "is_planted": true,
+ "max_grow_time": 7200
+ },
+ {
+ "crop_type": "人参",
+ "grow_time": 6600,
+ "is_dead": false,
+ "is_diged": true,
+ "is_planted": true,
+ "max_grow_time": 6600
+ },
{
"crop_type": "草莓",
- "grow_time": 33,
+ "grow_time": 960,
"is_dead": false,
"is_diged": true,
"is_planted": true,
"max_grow_time": 960
},
{
- "crop_type": "测试作物",
- "grow_time": 3,
+ "crop_type": "芦笋",
+ "grow_time": 1560,
"is_dead": false,
"is_diged": true,
"is_planted": true,
- "max_grow_time": 3
- },
- {
- "crop_type": "小麦",
- "grow_time": 3,
- "is_dead": false,
- "is_diged": true,
- "is_planted": true,
- "max_grow_time": 120
- },
- {
- "crop_type": "",
- "grow_time": 0,
- "is_dead": false,
- "is_diged": false,
- "is_planted": false,
- "max_grow_time": 5
- },
- {
- "crop_type": "",
- "grow_time": 0,
- "is_dead": false,
- "is_diged": false,
- "is_planted": false,
- "max_grow_time": 5
- },
- {
- "crop_type": "",
- "grow_time": 0,
- "is_dead": false,
- "is_diged": false,
- "is_planted": false,
- "max_grow_time": 5
- },
- {
- "crop_type": "",
- "grow_time": 0,
- "is_dead": false,
- "is_diged": false,
- "is_planted": false,
- "max_grow_time": 5
- },
- {
- "crop_type": "",
- "grow_time": 0,
- "is_dead": false,
- "is_diged": false,
- "is_planted": false,
- "max_grow_time": 5
- },
- {
- "crop_type": "",
- "grow_time": 0,
- "is_dead": false,
- "is_diged": false,
- "is_planted": false,
- "max_grow_time": 5
- },
- {
- "crop_type": "",
- "grow_time": 0,
- "is_dead": false,
- "is_diged": false,
- "is_planted": false,
- "max_grow_time": 5
- },
- {
- "crop_type": "",
- "grow_time": 0,
- "is_dead": false,
- "is_diged": false,
- "is_planted": false,
- "max_grow_time": 5
- },
- {
- "crop_type": "",
- "grow_time": 0,
- "is_dead": false,
- "is_diged": false,
- "is_planted": false,
- "max_grow_time": 5
- },
- {
- "crop_type": "",
- "grow_time": 0,
- "is_dead": false,
- "is_diged": false,
- "is_planted": false,
- "max_grow_time": 5
- },
- {
- "crop_type": "",
- "grow_time": 0,
- "is_dead": false,
- "is_diged": false,
- "is_planted": false,
- "max_grow_time": 5
- },
- {
- "crop_type": "",
- "grow_time": 0,
- "is_dead": false,
- "is_diged": false,
- "is_planted": false,
- "max_grow_time": 5
- },
- {
- "crop_type": "",
- "grow_time": 0,
- "is_dead": false,
- "is_diged": false,
- "is_planted": false,
- "max_grow_time": 5
- },
- {
- "crop_type": "",
- "grow_time": 0,
- "is_dead": false,
- "is_diged": false,
- "is_planted": false,
- "max_grow_time": 5
- },
- {
- "crop_type": "",
- "grow_time": 0,
- "is_dead": false,
- "is_diged": false,
- "is_planted": false,
- "max_grow_time": 5
- },
- {
- "crop_type": "",
- "grow_time": 0,
- "is_dead": false,
- "is_diged": false,
- "is_planted": false,
- "max_grow_time": 5
- },
- {
- "crop_type": "",
- "grow_time": 0,
- "is_dead": false,
- "is_diged": false,
- "is_planted": false,
- "max_grow_time": 5
- },
- {
- "crop_type": "",
- "grow_time": 0,
- "is_dead": false,
- "is_diged": false,
- "is_planted": false,
- "max_grow_time": 5
- },
- {
- "crop_type": "",
- "grow_time": 0,
- "is_dead": false,
- "is_diged": false,
- "is_planted": false,
- "max_grow_time": 5
- },
- {
- "crop_type": "",
- "grow_time": 0,
- "is_dead": false,
- "is_diged": false,
- "is_planted": false,
- "max_grow_time": 5
- },
- {
- "crop_type": "",
- "grow_time": 0,
- "is_dead": false,
- "is_diged": false,
- "is_planted": false,
- "max_grow_time": 5
- },
- {
- "crop_type": "",
- "grow_time": 0,
- "is_dead": false,
- "is_diged": false,
- "is_planted": false,
- "max_grow_time": 5
- },
- {
- "crop_type": "",
- "grow_time": 0,
- "is_dead": false,
- "is_diged": false,
- "is_planted": false,
- "max_grow_time": 5
- },
- {
- "crop_type": "",
- "grow_time": 0,
- "is_dead": false,
- "is_diged": false,
- "is_planted": false,
- "max_grow_time": 5
- },
- {
- "crop_type": "",
- "grow_time": 0,
- "is_dead": false,
- "is_diged": false,
- "is_planted": false,
- "max_grow_time": 5
- },
- {
- "crop_type": "",
- "grow_time": 0,
- "is_dead": false,
- "is_diged": false,
- "is_planted": false,
- "max_grow_time": 5
- },
- {
- "crop_type": "",
- "grow_time": 0,
- "is_dead": false,
- "is_diged": false,
- "is_planted": false,
- "max_grow_time": 5
- },
- {
- "crop_type": "",
- "grow_time": 0,
- "is_dead": false,
- "is_diged": false,
- "is_planted": false,
- "max_grow_time": 5
- },
- {
- "crop_type": "",
- "grow_time": 0,
- "is_dead": false,
- "is_diged": false,
- "is_planted": false,
- "max_grow_time": 5
- },
- {
- "crop_type": "",
- "grow_time": 0,
- "is_dead": false,
- "is_diged": false,
- "is_planted": false,
- "max_grow_time": 5
+ "max_grow_time": 1560
},
{
"crop_type": "花椰菜",
- "grow_time": 132,
+ "grow_time": 960,
"is_dead": false,
"is_diged": true,
"is_planted": true,
@@ -291,7 +75,7 @@
},
{
"crop_type": "花椰菜",
- "grow_time": 129,
+ "grow_time": 960,
"is_dead": false,
"is_diged": true,
"is_planted": true,
@@ -301,7 +85,7 @@
"crop_type": "",
"grow_time": 0,
"is_dead": false,
- "is_diged": true,
+ "is_diged": false,
"is_planted": false,
"max_grow_time": 5
},
@@ -319,12 +103,278 @@
"is_dead": false,
"is_diged": true,
"is_planted": false,
+ "max_grow_time": 4800
+ },
+ {
+ "crop_type": "",
+ "grow_time": 0,
+ "is_dead": false,
+ "is_diged": true,
+ "is_planted": false,
+ "max_grow_time": 1800
+ },
+ {
+ "crop_type": "芦笋",
+ "grow_time": 661,
+ "is_dead": false,
+ "is_diged": true,
+ "is_planted": true,
+ "max_grow_time": 1560
+ },
+ {
+ "crop_type": "人参",
+ "grow_time": 6600,
+ "is_dead": false,
+ "is_diged": true,
+ "is_planted": true,
+ "max_grow_time": 6600
+ },
+ {
+ "crop_type": "胡萝卜",
+ "grow_time": 480,
+ "is_dead": false,
+ "is_diged": true,
+ "is_planted": true,
+ "max_grow_time": 480
+ },
+ {
+ "crop_type": "胡萝卜",
+ "grow_time": 480,
+ "is_dead": false,
+ "is_diged": true,
+ "is_planted": true,
+ "max_grow_time": 480
+ },
+ {
+ "crop_type": "花椰菜",
+ "grow_time": 960,
+ "is_dead": false,
+ "is_diged": true,
+ "is_planted": true,
+ "max_grow_time": 960
+ },
+ {
+ "crop_type": "龙果",
+ "grow_time": 4800,
+ "is_dead": false,
+ "is_diged": true,
+ "is_planted": true,
+ "max_grow_time": 4800
+ },
+ {
+ "crop_type": "",
+ "grow_time": 0,
+ "is_dead": false,
+ "is_diged": false,
+ "is_planted": false,
"max_grow_time": 5
+ },
+ {
+ "crop_type": "",
+ "grow_time": 0,
+ "is_dead": false,
+ "is_diged": false,
+ "is_planted": false,
+ "max_grow_time": 5
+ },
+ {
+ "crop_type": "",
+ "grow_time": 0,
+ "is_dead": false,
+ "is_diged": true,
+ "is_planted": false,
+ "max_grow_time": 960
+ },
+ {
+ "crop_type": "",
+ "grow_time": 0,
+ "is_dead": false,
+ "is_diged": true,
+ "is_planted": false,
+ "max_grow_time": 1560
+ },
+ {
+ "crop_type": "稻谷",
+ "grow_time": 240,
+ "is_dead": false,
+ "is_diged": true,
+ "is_planted": true,
+ "max_grow_time": 240
+ },
+ {
+ "crop_type": "富贵竹",
+ "grow_time": 5952,
+ "is_dead": false,
+ "is_diged": true,
+ "is_planted": true,
+ "max_grow_time": 6600
+ },
+ {
+ "crop_type": "金橘",
+ "grow_time": 4800,
+ "is_dead": false,
+ "is_diged": true,
+ "is_planted": true,
+ "max_grow_time": 4800
+ },
+ {
+ "crop_type": "胡萝卜",
+ "grow_time": 480,
+ "is_dead": false,
+ "is_diged": true,
+ "is_planted": true,
+ "max_grow_time": 480
+ },
+ {
+ "crop_type": "草莓",
+ "grow_time": 960,
+ "is_dead": false,
+ "is_diged": true,
+ "is_planted": true,
+ "max_grow_time": 960
+ },
+ {
+ "crop_type": "人参",
+ "grow_time": 6600,
+ "is_dead": false,
+ "is_diged": true,
+ "is_planted": true,
+ "max_grow_time": 6600
+ },
+ {
+ "crop_type": "",
+ "grow_time": 0,
+ "is_dead": false,
+ "is_diged": false,
+ "is_planted": false,
+ "max_grow_time": 5
+ },
+ {
+ "crop_type": "",
+ "grow_time": 0,
+ "is_dead": false,
+ "is_diged": false,
+ "is_planted": false,
+ "max_grow_time": 5
+ },
+ {
+ "crop_type": "",
+ "grow_time": 0,
+ "is_dead": false,
+ "is_diged": false,
+ "is_planted": false,
+ "max_grow_time": 5
+ },
+ {
+ "crop_type": "",
+ "grow_time": 0,
+ "is_dead": false,
+ "is_diged": true,
+ "is_planted": false,
+ "max_grow_time": 5
+ },
+ {
+ "crop_type": "胡萝卜",
+ "grow_time": 480,
+ "is_dead": false,
+ "is_diged": true,
+ "is_planted": true,
+ "max_grow_time": 480
+ },
+ {
+ "crop_type": "富贵竹",
+ "grow_time": 5968,
+ "is_dead": false,
+ "is_diged": true,
+ "is_planted": true,
+ "max_grow_time": 6600
+ },
+ {
+ "crop_type": "芦笋",
+ "grow_time": 1560,
+ "is_dead": false,
+ "is_diged": true,
+ "is_planted": true,
+ "max_grow_time": 1560
+ },
+ {
+ "crop_type": "花椰菜",
+ "grow_time": 960,
+ "is_dead": false,
+ "is_diged": true,
+ "is_planted": true,
+ "max_grow_time": 960
+ },
+ {
+ "crop_type": "花椰菜",
+ "grow_time": 960,
+ "is_dead": false,
+ "is_diged": true,
+ "is_planted": true,
+ "max_grow_time": 960
+ },
+ {
+ "crop_type": "花椰菜",
+ "grow_time": 960,
+ "is_dead": false,
+ "is_diged": true,
+ "is_planted": true,
+ "max_grow_time": 960
}
],
- "farm_name": "",
- "level": 4,
- "money": 30596,
+ "player_bag": [
+ {
+ "count": 16,
+ "name": "测试作物",
+ "quality": "普通"
+ },
+ {
+ "count": 260,
+ "name": "金橘",
+ "quality": "传奇"
+ },
+ {
+ "name": "胡萝卜",
+ "quality": "普通",
+ "count": 11
+ },
+ {
+ "name": "花椰菜",
+ "quality": "稀有",
+ "count": 1
+ },
+ {
+ "name": "芦笋",
+ "quality": "稀有",
+ "count": 1
+ },
+ {
+ "name": "人参",
+ "quality": "传奇",
+ "count": 8
+ },
+ {
+ "name": "松露",
+ "quality": "传奇",
+ "count": 7
+ },
+ {
+ "name": "富贵竹",
+ "quality": "传奇",
+ "count": 9
+ },
+ {
+ "name": "芦荟",
+ "quality": "传奇",
+ "count": 6
+ }
+ ],
+ "farm_name": "树萌芽の大农场",
+ "player_name": "树萌芽",
+ "level": 37,
+ "money": 18663,
+ "last_login_time": "2025年05月25日18时37分14秒",
+ "total_login_time": "102时27分46秒",
"user_name": "3205788256",
"user_password": "tyh@19900420"
}
\ No newline at end of file
diff --git a/server/package-lock.json b/server/package-lock.json
deleted file mode 100644
index 01a9926..0000000
--- a/server/package-lock.json
+++ /dev/null
@@ -1,923 +0,0 @@
-{
- "name": "Servers",
- "lockfileVersion": 3,
- "requires": true,
- "packages": {
- "": {
- "dependencies": {
- "chalk": "^4.1.2",
- "cors": "^2.8.5",
- "express": "^4.21.2"
- }
- },
- "node_modules/accepts": {
- "version": "1.3.8",
- "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz",
- "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==",
- "license": "MIT",
- "dependencies": {
- "mime-types": "~2.1.34",
- "negotiator": "0.6.3"
- },
- "engines": {
- "node": ">= 0.6"
- }
- },
- "node_modules/ansi-styles": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
- "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
- "license": "MIT",
- "dependencies": {
- "color-convert": "^2.0.1"
- },
- "engines": {
- "node": ">=8"
- },
- "funding": {
- "url": "https://github.com/chalk/ansi-styles?sponsor=1"
- }
- },
- "node_modules/array-flatten": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
- "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==",
- "license": "MIT"
- },
- "node_modules/body-parser": {
- "version": "1.20.3",
- "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz",
- "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==",
- "license": "MIT",
- "dependencies": {
- "bytes": "3.1.2",
- "content-type": "~1.0.5",
- "debug": "2.6.9",
- "depd": "2.0.0",
- "destroy": "1.2.0",
- "http-errors": "2.0.0",
- "iconv-lite": "0.4.24",
- "on-finished": "2.4.1",
- "qs": "6.13.0",
- "raw-body": "2.5.2",
- "type-is": "~1.6.18",
- "unpipe": "1.0.0"
- },
- "engines": {
- "node": ">= 0.8",
- "npm": "1.2.8000 || >= 1.4.16"
- }
- },
- "node_modules/bytes": {
- "version": "3.1.2",
- "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
- "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==",
- "license": "MIT",
- "engines": {
- "node": ">= 0.8"
- }
- },
- "node_modules/call-bind-apply-helpers": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz",
- "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==",
- "license": "MIT",
- "dependencies": {
- "es-errors": "^1.3.0",
- "function-bind": "^1.1.2"
- },
- "engines": {
- "node": ">= 0.4"
- }
- },
- "node_modules/call-bound": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz",
- "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==",
- "license": "MIT",
- "dependencies": {
- "call-bind-apply-helpers": "^1.0.2",
- "get-intrinsic": "^1.3.0"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/chalk": {
- "version": "4.1.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
- "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
- "license": "MIT",
- "dependencies": {
- "ansi-styles": "^4.1.0",
- "supports-color": "^7.1.0"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/chalk/chalk?sponsor=1"
- }
- },
- "node_modules/color-convert": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
- "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
- "license": "MIT",
- "dependencies": {
- "color-name": "~1.1.4"
- },
- "engines": {
- "node": ">=7.0.0"
- }
- },
- "node_modules/color-name": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
- "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
- "license": "MIT"
- },
- "node_modules/content-disposition": {
- "version": "0.5.4",
- "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz",
- "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==",
- "license": "MIT",
- "dependencies": {
- "safe-buffer": "5.2.1"
- },
- "engines": {
- "node": ">= 0.6"
- }
- },
- "node_modules/content-type": {
- "version": "1.0.5",
- "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz",
- "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==",
- "license": "MIT",
- "engines": {
- "node": ">= 0.6"
- }
- },
- "node_modules/cookie": {
- "version": "0.7.1",
- "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz",
- "integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==",
- "license": "MIT",
- "engines": {
- "node": ">= 0.6"
- }
- },
- "node_modules/cookie-signature": {
- "version": "1.0.6",
- "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
- "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==",
- "license": "MIT"
- },
- "node_modules/cors": {
- "version": "2.8.5",
- "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz",
- "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==",
- "license": "MIT",
- "dependencies": {
- "object-assign": "^4",
- "vary": "^1"
- },
- "engines": {
- "node": ">= 0.10"
- }
- },
- "node_modules/debug": {
- "version": "2.6.9",
- "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
- "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
- "license": "MIT",
- "dependencies": {
- "ms": "2.0.0"
- }
- },
- "node_modules/depd": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
- "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==",
- "license": "MIT",
- "engines": {
- "node": ">= 0.8"
- }
- },
- "node_modules/destroy": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz",
- "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==",
- "license": "MIT",
- "engines": {
- "node": ">= 0.8",
- "npm": "1.2.8000 || >= 1.4.16"
- }
- },
- "node_modules/dunder-proto": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
- "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==",
- "license": "MIT",
- "dependencies": {
- "call-bind-apply-helpers": "^1.0.1",
- "es-errors": "^1.3.0",
- "gopd": "^1.2.0"
- },
- "engines": {
- "node": ">= 0.4"
- }
- },
- "node_modules/ee-first": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
- "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==",
- "license": "MIT"
- },
- "node_modules/encodeurl": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz",
- "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==",
- "license": "MIT",
- "engines": {
- "node": ">= 0.8"
- }
- },
- "node_modules/es-define-property": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
- "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==",
- "license": "MIT",
- "engines": {
- "node": ">= 0.4"
- }
- },
- "node_modules/es-errors": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
- "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
- "license": "MIT",
- "engines": {
- "node": ">= 0.4"
- }
- },
- "node_modules/es-object-atoms": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz",
- "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==",
- "license": "MIT",
- "dependencies": {
- "es-errors": "^1.3.0"
- },
- "engines": {
- "node": ">= 0.4"
- }
- },
- "node_modules/escape-html": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
- "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==",
- "license": "MIT"
- },
- "node_modules/etag": {
- "version": "1.8.1",
- "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
- "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==",
- "license": "MIT",
- "engines": {
- "node": ">= 0.6"
- }
- },
- "node_modules/express": {
- "version": "4.21.2",
- "resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz",
- "integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==",
- "license": "MIT",
- "dependencies": {
- "accepts": "~1.3.8",
- "array-flatten": "1.1.1",
- "body-parser": "1.20.3",
- "content-disposition": "0.5.4",
- "content-type": "~1.0.4",
- "cookie": "0.7.1",
- "cookie-signature": "1.0.6",
- "debug": "2.6.9",
- "depd": "2.0.0",
- "encodeurl": "~2.0.0",
- "escape-html": "~1.0.3",
- "etag": "~1.8.1",
- "finalhandler": "1.3.1",
- "fresh": "0.5.2",
- "http-errors": "2.0.0",
- "merge-descriptors": "1.0.3",
- "methods": "~1.1.2",
- "on-finished": "2.4.1",
- "parseurl": "~1.3.3",
- "path-to-regexp": "0.1.12",
- "proxy-addr": "~2.0.7",
- "qs": "6.13.0",
- "range-parser": "~1.2.1",
- "safe-buffer": "5.2.1",
- "send": "0.19.0",
- "serve-static": "1.16.2",
- "setprototypeof": "1.2.0",
- "statuses": "2.0.1",
- "type-is": "~1.6.18",
- "utils-merge": "1.0.1",
- "vary": "~1.1.2"
- },
- "engines": {
- "node": ">= 0.10.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/express"
- }
- },
- "node_modules/finalhandler": {
- "version": "1.3.1",
- "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz",
- "integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==",
- "license": "MIT",
- "dependencies": {
- "debug": "2.6.9",
- "encodeurl": "~2.0.0",
- "escape-html": "~1.0.3",
- "on-finished": "2.4.1",
- "parseurl": "~1.3.3",
- "statuses": "2.0.1",
- "unpipe": "~1.0.0"
- },
- "engines": {
- "node": ">= 0.8"
- }
- },
- "node_modules/forwarded": {
- "version": "0.2.0",
- "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
- "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==",
- "license": "MIT",
- "engines": {
- "node": ">= 0.6"
- }
- },
- "node_modules/fresh": {
- "version": "0.5.2",
- "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
- "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==",
- "license": "MIT",
- "engines": {
- "node": ">= 0.6"
- }
- },
- "node_modules/function-bind": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
- "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
- "license": "MIT",
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/get-intrinsic": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
- "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==",
- "license": "MIT",
- "dependencies": {
- "call-bind-apply-helpers": "^1.0.2",
- "es-define-property": "^1.0.1",
- "es-errors": "^1.3.0",
- "es-object-atoms": "^1.1.1",
- "function-bind": "^1.1.2",
- "get-proto": "^1.0.1",
- "gopd": "^1.2.0",
- "has-symbols": "^1.1.0",
- "hasown": "^2.0.2",
- "math-intrinsics": "^1.1.0"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/get-proto": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz",
- "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==",
- "license": "MIT",
- "dependencies": {
- "dunder-proto": "^1.0.1",
- "es-object-atoms": "^1.0.0"
- },
- "engines": {
- "node": ">= 0.4"
- }
- },
- "node_modules/gopd": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
- "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==",
- "license": "MIT",
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/has-flag": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
- "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
- "license": "MIT",
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/has-symbols": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz",
- "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==",
- "license": "MIT",
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/hasown": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
- "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
- "license": "MIT",
- "dependencies": {
- "function-bind": "^1.1.2"
- },
- "engines": {
- "node": ">= 0.4"
- }
- },
- "node_modules/http-errors": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz",
- "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==",
- "license": "MIT",
- "dependencies": {
- "depd": "2.0.0",
- "inherits": "2.0.4",
- "setprototypeof": "1.2.0",
- "statuses": "2.0.1",
- "toidentifier": "1.0.1"
- },
- "engines": {
- "node": ">= 0.8"
- }
- },
- "node_modules/iconv-lite": {
- "version": "0.4.24",
- "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
- "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
- "license": "MIT",
- "dependencies": {
- "safer-buffer": ">= 2.1.2 < 3"
- },
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/inherits": {
- "version": "2.0.4",
- "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
- "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
- "license": "ISC"
- },
- "node_modules/ipaddr.js": {
- "version": "1.9.1",
- "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
- "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==",
- "license": "MIT",
- "engines": {
- "node": ">= 0.10"
- }
- },
- "node_modules/math-intrinsics": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
- "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==",
- "license": "MIT",
- "engines": {
- "node": ">= 0.4"
- }
- },
- "node_modules/media-typer": {
- "version": "0.3.0",
- "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
- "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==",
- "license": "MIT",
- "engines": {
- "node": ">= 0.6"
- }
- },
- "node_modules/merge-descriptors": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz",
- "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==",
- "license": "MIT",
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/methods": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz",
- "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==",
- "license": "MIT",
- "engines": {
- "node": ">= 0.6"
- }
- },
- "node_modules/mime": {
- "version": "1.6.0",
- "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
- "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==",
- "license": "MIT",
- "bin": {
- "mime": "cli.js"
- },
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/mime-db": {
- "version": "1.52.0",
- "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
- "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
- "license": "MIT",
- "engines": {
- "node": ">= 0.6"
- }
- },
- "node_modules/mime-types": {
- "version": "2.1.35",
- "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
- "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
- "license": "MIT",
- "dependencies": {
- "mime-db": "1.52.0"
- },
- "engines": {
- "node": ">= 0.6"
- }
- },
- "node_modules/ms": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
- "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
- "license": "MIT"
- },
- "node_modules/negotiator": {
- "version": "0.6.3",
- "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz",
- "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==",
- "license": "MIT",
- "engines": {
- "node": ">= 0.6"
- }
- },
- "node_modules/object-assign": {
- "version": "4.1.1",
- "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
- "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
- "license": "MIT",
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/object-inspect": {
- "version": "1.13.4",
- "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz",
- "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==",
- "license": "MIT",
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/on-finished": {
- "version": "2.4.1",
- "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz",
- "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==",
- "license": "MIT",
- "dependencies": {
- "ee-first": "1.1.1"
- },
- "engines": {
- "node": ">= 0.8"
- }
- },
- "node_modules/parseurl": {
- "version": "1.3.3",
- "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
- "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==",
- "license": "MIT",
- "engines": {
- "node": ">= 0.8"
- }
- },
- "node_modules/path-to-regexp": {
- "version": "0.1.12",
- "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz",
- "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==",
- "license": "MIT"
- },
- "node_modules/proxy-addr": {
- "version": "2.0.7",
- "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
- "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==",
- "license": "MIT",
- "dependencies": {
- "forwarded": "0.2.0",
- "ipaddr.js": "1.9.1"
- },
- "engines": {
- "node": ">= 0.10"
- }
- },
- "node_modules/qs": {
- "version": "6.13.0",
- "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz",
- "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==",
- "license": "BSD-3-Clause",
- "dependencies": {
- "side-channel": "^1.0.6"
- },
- "engines": {
- "node": ">=0.6"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/range-parser": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
- "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==",
- "license": "MIT",
- "engines": {
- "node": ">= 0.6"
- }
- },
- "node_modules/raw-body": {
- "version": "2.5.2",
- "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz",
- "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==",
- "license": "MIT",
- "dependencies": {
- "bytes": "3.1.2",
- "http-errors": "2.0.0",
- "iconv-lite": "0.4.24",
- "unpipe": "1.0.0"
- },
- "engines": {
- "node": ">= 0.8"
- }
- },
- "node_modules/safe-buffer": {
- "version": "5.2.1",
- "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
- "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
- "funding": [
- {
- "type": "github",
- "url": "https://github.com/sponsors/feross"
- },
- {
- "type": "patreon",
- "url": "https://www.patreon.com/feross"
- },
- {
- "type": "consulting",
- "url": "https://feross.org/support"
- }
- ],
- "license": "MIT"
- },
- "node_modules/safer-buffer": {
- "version": "2.1.2",
- "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
- "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
- "license": "MIT"
- },
- "node_modules/send": {
- "version": "0.19.0",
- "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz",
- "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==",
- "license": "MIT",
- "dependencies": {
- "debug": "2.6.9",
- "depd": "2.0.0",
- "destroy": "1.2.0",
- "encodeurl": "~1.0.2",
- "escape-html": "~1.0.3",
- "etag": "~1.8.1",
- "fresh": "0.5.2",
- "http-errors": "2.0.0",
- "mime": "1.6.0",
- "ms": "2.1.3",
- "on-finished": "2.4.1",
- "range-parser": "~1.2.1",
- "statuses": "2.0.1"
- },
- "engines": {
- "node": ">= 0.8.0"
- }
- },
- "node_modules/send/node_modules/encodeurl": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
- "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==",
- "license": "MIT",
- "engines": {
- "node": ">= 0.8"
- }
- },
- "node_modules/send/node_modules/ms": {
- "version": "2.1.3",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
- "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
- "license": "MIT"
- },
- "node_modules/serve-static": {
- "version": "1.16.2",
- "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz",
- "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==",
- "license": "MIT",
- "dependencies": {
- "encodeurl": "~2.0.0",
- "escape-html": "~1.0.3",
- "parseurl": "~1.3.3",
- "send": "0.19.0"
- },
- "engines": {
- "node": ">= 0.8.0"
- }
- },
- "node_modules/setprototypeof": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
- "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==",
- "license": "ISC"
- },
- "node_modules/side-channel": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz",
- "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==",
- "license": "MIT",
- "dependencies": {
- "es-errors": "^1.3.0",
- "object-inspect": "^1.13.3",
- "side-channel-list": "^1.0.0",
- "side-channel-map": "^1.0.1",
- "side-channel-weakmap": "^1.0.2"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/side-channel-list": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz",
- "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==",
- "license": "MIT",
- "dependencies": {
- "es-errors": "^1.3.0",
- "object-inspect": "^1.13.3"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/side-channel-map": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz",
- "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==",
- "license": "MIT",
- "dependencies": {
- "call-bound": "^1.0.2",
- "es-errors": "^1.3.0",
- "get-intrinsic": "^1.2.5",
- "object-inspect": "^1.13.3"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/side-channel-weakmap": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz",
- "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==",
- "license": "MIT",
- "dependencies": {
- "call-bound": "^1.0.2",
- "es-errors": "^1.3.0",
- "get-intrinsic": "^1.2.5",
- "object-inspect": "^1.13.3",
- "side-channel-map": "^1.0.1"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/statuses": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
- "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==",
- "license": "MIT",
- "engines": {
- "node": ">= 0.8"
- }
- },
- "node_modules/supports-color": {
- "version": "7.2.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
- "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
- "license": "MIT",
- "dependencies": {
- "has-flag": "^4.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/toidentifier": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
- "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==",
- "license": "MIT",
- "engines": {
- "node": ">=0.6"
- }
- },
- "node_modules/type-is": {
- "version": "1.6.18",
- "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
- "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==",
- "license": "MIT",
- "dependencies": {
- "media-typer": "0.3.0",
- "mime-types": "~2.1.24"
- },
- "engines": {
- "node": ">= 0.6"
- }
- },
- "node_modules/unpipe": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
- "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==",
- "license": "MIT",
- "engines": {
- "node": ">= 0.8"
- }
- },
- "node_modules/utils-merge": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
- "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==",
- "license": "MIT",
- "engines": {
- "node": ">= 0.4.0"
- }
- },
- "node_modules/vary": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
- "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==",
- "license": "MIT",
- "engines": {
- "node": ">= 0.8"
- }
- }
- }
-}
diff --git a/server/package.json b/server/package.json
deleted file mode 100644
index 1e29ab3..0000000
--- a/server/package.json
+++ /dev/null
@@ -1,7 +0,0 @@
-{
- "dependencies": {
- "chalk": "^4.1.2",
- "cors": "^2.8.5",
- "express": "^4.21.2"
- }
-}
diff --git a/server/player.js b/server/player.js
deleted file mode 100644
index ce97d69..0000000
--- a/server/player.js
+++ /dev/null
@@ -1,83 +0,0 @@
-const fs = require('fs');
-const path = require('path');
-const express = require('express');
-const app = express();
-const port = 3000;
-
-// 使用 express.json() 中间件来解析 JSON 请求体
-app.use(express.json());
-
-// 处理用户登录请求
-app.post('/login', (req, res) => {
- const { user_name, user_password } = req.body;
- const filePath = path.join(__dirname, `Players/${user_name}.json`);
-
- fs.readFile(filePath, 'utf8', (err, data) => {
- if (err) {
- console.error('读取文件时出错:', err);
- console.error("用户:", user_name, '读取文件:', userData.user_name, ".json", "失败!", "原因:用户不存在");
- return res.status(404).json({ message: '用户不存在' });
- }
-
- try {
- const userData = JSON.parse(data);
-
- if (userData.user_password === user_password) {
- console.error("用户:", user_name, '读取文件:', userData.user_name, ".json", "成功!");
- return res.json({ message: '登录成功', data: userData });
-
- } else {
- console.error("用户:", user_name, '读取文件:', userData.user_name, ".json", "失败!","原因:密码错误");
- return res.status(401).json({ message: '密码错误' });
- }
- } catch (parseError) {
- console.error('解析 JSON 时出错:', parseError);
- return res.status(500).json({ message: '服务器错误', error: parseError });
- }
- });
-});
-
-// 处理保存数据请求
-app.post('/save', (req, res) => {
- const receivedData = req.body;
- const filePath = path.join(__dirname, `Players/${receivedData.user_name}.json`);
-
-
- // 将数据写入文件
- fs.writeFile(filePath, JSON.stringify(receivedData, null, 2), (err) => {
- if (err) {
- console.error('保存数据时出错:', err);
- return res.status(500).json({ message: '数据保存失败', error: err });
- }
- console.log(`数据已保存到 ${receivedData.user_name}.json`);
- console.log("用户:", receivedData.user_name, '保存数据到:', receivedData.user_name, ".json", "成功!");
- return res.json({ message: '数据保存成功', data: receivedData });
- });
-});
-
-
-// 处理新用户注册请求
-app.post('/register', (req, res) => {
- const newUserData = req.body;
- const filePath = path.join(__dirname, `Players/${newUserData.user_name}.json`);
-
- // 检查用户名是否已经存在
- if (fs.existsSync(filePath)) {
- console.error("新用户:", newUserData.user_name, '注册数据到:', newUserData.user_name, ".json", "失败!", "原因:用户名已存在");
- return res.status(400).json({ message: '用户名已存在' });
- }
-
- // 将新用户数据写入文件
- fs.writeFile(filePath, JSON.stringify(newUserData, null, 2), (err) => {
- if (err) {
- console.error("新用户:", newUserData.user_name, '注册数据到:', newUserData.user_name, ".json", "失败!", "原因:",err);
- return res.status(500).json({ message: '数据保存失败', error: err });
- }
- console.log("新用户:", newUserData.user_name, '注册数据到:', newUserData.user_name, ".json", "成功!");
- return res.json({ message: '注册成功', data: newUserData });
- });
-});
-
-app.listen(port, () => {
- console.log(`萌芽后端服务器正在运行在: http://localhost:${port}`);
-});
diff --git a/server/server.js b/server/server.js
deleted file mode 100644
index 1de4a2c..0000000
--- a/server/server.js
+++ /dev/null
@@ -1,199 +0,0 @@
-const express = require('express');
-const fs = require('fs');
-const path = require('path');
-const bodyParser = require('body-parser');
-const cors = require('cors');
-const chalk = require('chalk'); // 用于控制台颜色
-
-// 创建 Express 应用
-const app = express();
-const PORT = 3000;
-
-// 配置中间件
-app.use(cors()); // 允许跨域资源共享
-app.use(bodyParser.json()); // 解析 JSON 请求体
-
-// 服务器存储目录,模拟远程存储位置
-const SERVER_STORAGE_PATH = path.join(__dirname, 'game_saves');
-
-// 确保存储目录存在
-if (!fs.existsSync(SERVER_STORAGE_PATH)) {
- fs.mkdirSync(SERVER_STORAGE_PATH);
-}
-
-// 日志记录函数
-function logServer(message) {
- const timestamp = new Date().toLocaleTimeString();
- console.log(chalk.gray(`[${timestamp}] `) + chalk.cyan('[服务器] ') + message);
-}
-
-function logPlayer(player, message) {
- const timestamp = new Date().toLocaleTimeString();
- console.log(chalk.gray(`[${timestamp}] `) + chalk.yellow(`[${player}] `) + message);
-}
-
-function logWarning(message) {
- const timestamp = new Date().toLocaleTimeString();
- console.log(chalk.gray(`[${timestamp}] `) + chalk.yellow('[警告] ') + message);
-}
-
-function logError(message) {
- const timestamp = new Date().toLocaleTimeString();
- console.log(chalk.gray(`[${timestamp}] `) + chalk.red('[错误] ') + message);
-}
-
-/**
- * 登录路由
- * @route POST /login
- * @param {string} req.body.user_name - 用户名
- * @param {string} req.body.user_password - 用户密码
- * @returns {Object} 登录结果
- */
-app.post('/login', (req, res) => {
- try {
- const { user_name, user_password } = req.body;
-
- if (!user_name || !user_password) {
- logWarning(`登录尝试失败: 用户名或密码为空`);
- return res.json({
- message: '用户名和密码不能为空'
- });
- }
-
- const filePath = path.join(SERVER_STORAGE_PATH, `${user_name}.json`);
-
- if (!fs.existsSync(filePath)) {
- logWarning(`登录失败: 用户 ${user_name} 不存在`);
- return res.json({
- message: '用户不存在'
- });
- }
-
- const fileContent = fs.readFileSync(filePath, 'utf8');
- const userData = JSON.parse(fileContent);
-
- if (userData.user_password !== user_password) {
- logWarning(`用户 ${user_name} 登录失败: 密码错误`);
- return res.json({
- message: '密码错误'
- });
- }
-
- logPlayer(user_name, '成功登录游戏');
- res.json({
- message: '登录成功',
- data: userData
- });
- } catch (error) {
- logError(`登录过程发生错误: ${error.message}`);
- res.json({
- message: '服务器错误',
- error: error.message
- });
- }
-});
-
-/**
- * 注册路由
- * @route POST /register
- * @param {string} req.body.user_name - 用户名
- * @param {string} req.body.user_password - 用户密码
- * @param {string} req.body.farm_name - 农场名称
- * @returns {Object} 注册结果
- */
-app.post('/register', (req, res) => {
- try {
- const { user_name, user_password, farm_name } = req.body;
-
- if (!user_name || !user_password || !farm_name) {
- logWarning(`注册失败: 注册信息不完整`);
- return res.json({
- message: '注册信息不完整'
- });
- }
-
- const filePath = path.join(SERVER_STORAGE_PATH, `${user_name}.json`);
-
- if (fs.existsSync(filePath)) {
- logWarning(`注册失败: 用户名 ${user_name} 已存在`);
- return res.json({
- message: '用户名已存在'
- });
- }
-
- fs.writeFileSync(filePath, JSON.stringify(req.body, null, 2), 'utf8');
- logPlayer(user_name, `注册成功,农场名称: ${farm_name}`);
-
- res.json({
- message: '注册成功'
- });
- } catch (error) {
- logError(`注册过程发生错误: ${error.message}`);
- res.json({
- message: '服务器错误',
- error: error.message
- });
- }
-});
-
-/**
- * 保存游戏数据
- * @route POST /save
- * @param {string} req.body.user_name - 用户名
- * @param {Object} req.body - 游戏保存数据
- * @returns {Object} 保存结果
- */
-app.post('/save', (req, res) => {
- try {
- const { user_name, money, level, experience } = req.body;
-
- if (!user_name) {
- logWarning(`保存失败: 用户名为空`);
- return res.json({
- message: '用户名不能为空'
- });
- }
-
- const filePath = path.join(SERVER_STORAGE_PATH, `${user_name}.json`);
- fs.writeFileSync(filePath, JSON.stringify(req.body, null, 2), 'utf8');
-
- logPlayer(user_name, `保存游戏数据 [金钱: ${money}, 等级: ${level}, 经验: ${experience}]`);
- res.json({
- message: '保存成功'
- });
- } catch (error) {
- logError(`保存游戏数据时发生错误: ${error.message}`);
- res.json({
- message: '服务器错误',
- error: error.message
- });
- }
-});
-
-/**
- * 服务器健康检查路由
- * @route GET /health
- * @returns {Object} 服务器状态
- */
-app.get('/health', (req, res) => {
- logServer('收到健康检查请求');
- res.json({
- status: 'healthy',
- message: 'Godot农场游戏服务器正在运行'
- });
-});
-
-// 启动服务器
-app.listen(PORT, () => {
- logServer(chalk.green('农场游戏服务器启动成功'));
- logServer(`监听端口: ${PORT}`);
- logServer(`存储路径: ${SERVER_STORAGE_PATH}`);
- logServer('等待玩家连接...');
-});
-
-// 优雅关闭服务器
-process.on('SIGINT', () => {
- logServer(chalk.yellow('正在关闭服务器...'));
- // 这里可以添加一些清理工作
- process.exit();
-});
\ No newline at end of file
diff --git a/server/start.bat b/server/start.bat
index 3159c46..20d70f2 100644
--- a/server/start.bat
+++ b/server/start.bat
@@ -1,5 +1,4 @@
@echo off
chcp 65001
-title 启动 Node.js 服务器
-node server.js
+python TCPGameServer.py
pause
diff --git a/server/start.sh b/server/start.sh
index 9d26261..0314474 100644
--- a/server/start.sh
+++ b/server/start.sh
@@ -1,4 +1,5 @@
#!/bin/bash
-echo "正在启动服务器..."
-node server.js
-echo "服务器已启动。"
+# 设置UTF-8字符编码
+export LANG=en_US.UTF-8
+# 执行Python服务器程序
+python3 TCPGameServer.py
\ No newline at end of file
diff --git a/test/main.gd b/test/main.gd
deleted file mode 100644
index fb3af9a..0000000
--- a/test/main.gd
+++ /dev/null
@@ -1,615 +0,0 @@
-extends Node
-
-# 变量定义
-@onready var grid_container = $GridContainer # 农场地块的 GridContainer
-@onready var crop_item = $CropItem
-@onready var crop_list = $CropList # 作物选择的 ItemList
-@onready var show_money = $money # 显示当前剩余的钱
-@onready var show_experience = $experience # 显示当前玩家的经验
-@onready var show_level = $level # 显示当前玩家的等级
-@onready var toast = $ToastShow
-@onready var toast2 = $ToastShow2
-@onready var land_panel = $Land_Panel
-@onready var dig_button = $Land_Panel/VBox/HBox/Dig_button
-@onready var crop_grid_container = $ScrollContainer/Crop_GridContainer
-
-@onready var green_bar = $Copy_Nodes/Green #普通
-@onready var white_blue_bar = $Copy_Nodes/White_Blue #稀有
-@onready var orange_bar = $Copy_Nodes/Orange #优良
-@onready var pink_bar = $Copy_Nodes/Pink #史诗
-@onready var black_blue_bar = $Copy_Nodes/Black_Blue #传奇
-@onready var red_bar = $Copy_Nodes/Red #神圣
-
-#----------------网络联机部分--------------------------
-#用户登录账号,用QQ号代替
-@onready var username_input = $LoginPanel/username_input
-#用户登录密码
-@onready var password_input = $LoginPanel/password_input
-#登录按钮
-@onready var login_button = $LoginPanel/login_button
-#----------------网络联机部分--------------------------
-@onready var tip = $tip
-
-var money: int = 500 # 默认每个人初始为100元
-var experience: float = 0.0 # 初始每个玩家的经验为0
-var grow_speed: float = 1 # 作物生长速度
-var level: int = 1 # 初始玩家等级为1
-var farm_lots = [] # 用于保存每个地块的状态
-
-var dig_index = 0
-var dig_money = 1000
-var climate_death_timer = 0
-
-var blink_speed: float = 1 # 每秒闪烁的次数
-var is_blink_on: bool = false # 是否闪烁状态
-var blink_counter: float = 0.0 # 计数器,用于控制闪烁
-
-var can_planted_crop = {
- #玩家点击空地块时可以种植的作物
- #品质有 普通,优良,稀有,史诗,传奇,品质会影响作物的颜色
- #耐候性:种植的过程中可能会死亡
- #等级:需要玩家达到相应等级才能种植
- #经验:收获时可以获得的经验,经验到达某一程度,玩家会升等级
- #基础作物
- # 基础作物
- "测试作物": {"花费": 1, "生长时间": 3, "收益": 9999, "品质": "普通", "描述": "测试作物", "耐候性": 10, "等级": 1, "经验": 999}, # 1分钟
-
- "小麦": {"花费": 120, "生长时间": 120, "收益": 100, "品质": "普通", "描述": "基础作物,品质较低,适合新手种植", "耐候性": 10, "等级": 1, "经验": 10}, # 1分钟
- "稻谷": {"花费": 100, "生长时间": 240, "收益": 120, "品质": "普通", "描述": "适合大规模种植的基础作物", "耐候性": 10, "等级": 1, "经验": 10}, # 2分钟
- "玉米": {"花费": 70, "生长时间": 600, "收益": 90, "品质": "普通", "描述": "营养丰富的优良作物,适合稍有经验的玩家", "耐候性": 15, "等级": 2, "经验": 15}, # 5分钟
- "土豆": {"花费": 75, "生长时间": 360, "收益": 90, "品质": "普通", "描述": "容易种植的耐寒作物", "耐候性": 12, "等级": 1, "经验": 10}, # 3分钟
- "胡萝卜": {"花费": 60, "生长时间": 480, "收益": 80, "品质": "普通", "描述": "适合新手的健康作物", "耐候性": 12, "等级": 1, "经验": 10}, # 4分钟
-
- # 中级作物
- "草莓": {"花费": 120, "生长时间": 960, "收益": 150, "品质": "优良", "描述": "营养丰富的果实,收益不错", "耐候性": 14, "等级": 2, "经验": 20}, # 8分钟
- "番茄": {"花费": 100, "生长时间": 720, "收益": 130, "品质": "优良", "描述": "常见作物,适合小规模种植", "耐候性": 12, "等级": 2, "经验": 15}, # 6分钟
- "大豆": {"花费": 90, "生长时间": 840, "收益": 110, "品质": "优良", "描述": "富含蛋白质的基础作物", "耐候性": 11, "等级": 2, "经验": 12}, # 7分钟
-
- # 高级作物
- "蓝莓": {"花费": 150, "生长时间": 1200, "收益": 200, "品质": "稀有", "描述": "较为稀有的作物,市场价值较高", "耐候性": 18, "等级": 3, "经验": 25}, # 10分钟
- "洋葱": {"花费": 85, "生长时间": 600, "收益": 105, "品质": "稀有", "描述": "烹饪常用的作物,适合中级种植", "耐候性": 10, "等级": 2, "经验": 10}, # 5分钟
- "南瓜": {"花费": 180, "生长时间": 1440, "收益": 250, "品质": "稀有", "描述": "秋季收获的高收益作物", "耐候性": 20, "等级": 4, "经验": 30}, # 12分钟
- "葡萄": {"花费": 200, "生长时间": 1200, "收益": 300, "品质": "稀有", "描述": "需要特殊管理的高收益作物", "耐候性": 15, "等级": 4, "经验": 35}, # 10分钟
- "柿子": {"花费": 160, "生长时间": 1080, "收益": 240, "品质": "稀有", "描述": "富含营养的秋季作物", "耐候性": 18, "等级": 3, "经验": 28}, # 9分钟
- "花椰菜": {"花费": 130, "生长时间": 960, "收益": 170, "品质": "稀有", "描述": "耐寒的高品质作物,适合经验丰富的玩家", "耐候性": 17, "等级": 3, "经验": 22}, # 8分钟
- "芦笋": {"花费": 200, "生长时间": 1560, "收益": 280, "品质": "稀有", "描述": "市场需求量高的稀有作物", "耐候性": 15, "等级": 4, "经验": 30}, # 13分钟
-
- # 史诗作物
- "香草": {"花费": 250, "生长时间": 1800, "收益": 400, "品质": "史诗", "描述": "非常稀有且收益极高的作物", "耐候性": 22, "等级": 5, "经验": 40}, # 15分钟
- "西瓜": {"花费": 240, "生长时间": 2400, "收益": 420, "品质": "史诗", "描述": "夏季丰产的高价值作物", "耐候性": 21, "等级": 5, "经验": 45}, # 20分钟
- "甜菜": {"花费": 220, "生长时间": 2160, "收益": 350, "品质": "史诗", "描述": "营养丰富的根茎作物,收益较高", "耐候性": 20, "等级": 5, "经验": 38}, # 18分钟
- "甘蔗": {"花费": 260, "生长时间": 3000, "收益": 450, "品质": "史诗", "描述": "需要充足水源的高价值作物", "耐候性": 18, "等级": 5, "经验": 50}, # 25分钟
-
- # 传奇作物
- "龙果": {"花费": 400, "生长时间": 4800, "收益": 600, "品质": "传奇", "描述": "极为稀有的热带作物,产量和价值都极高", "耐候性": 25, "等级": 6, "经验": 60}, # 40分钟
- "松露": {"花费": 500, "生长时间": 7200, "收益": 700, "品质": "传奇", "描述": "极其珍贵的地下作物,市场价格极高", "耐候性": 23, "等级": 7, "经验": 80}, # 60分钟
- "人参": {"花费": 450, "生长时间": 6600, "收益": 650, "品质": "传奇", "描述": "需要耐心等待的珍贵药材", "耐候性": 22, "等级": 6, "经验": 75}, # 55分钟
- "金橘": {"花费": 420, "生长时间": 4800, "收益": 620, "品质": "传奇", "描述": "少见的耐寒果树,市场需求量极大", "耐候性": 26, "等级": 7, "经验": 70} # 40分钟
-};
-
-var selected_lot_index = -1 # 当前被选择的地块索引
-#电脑版路径(Windows或者Linux)
-#var game_path = "C:/Users/shumengya/Desktop/smyfarm/save.txt"
-#
-var game_path = "/storage/emulated/0/萌芽农场/保存.txt"
-
-var save_time = 10
-var farm_thread: Thread
-# 准备阶段
-func _ready():
-
- farm_thread = Thread.new()
- # 使用 Callable 创建可调用对象,指向当前对象的 _thread_update_farm_lots 方法
- var callable = Callable(self, "_thread_update_farm_lots")
- # 启动线程
- var error = farm_thread.start(callable)
- if error != OK:
- print("Failed to start thread: ", error)
-
- OS.request_permissions()
- toast.Toast("快去偷其他人的菜吧!", Color.GREEN)
- # 初始化农场地块
- _init_farm_lots(40)
- _update_farm_lots()
-
-
-
- # 连接点击事件
- #crop_list.connect("item_selected", Callable(self, "_on_crop_selected"))
- # 初始隐藏作物选择列表
- #crop_list.hide()
- crop_grid_container.hide()
-
- # 更新初始显示
- _update_ui()
-
- # 初始化作物选择列表
- _init_crop_list2()
-
- _load_game()
-
-# 初始化农场地块
-func _init_farm_lots(num_lots):
- for i in range(num_lots):
- farm_lots.append({
- "is_diged": false, # 是否开垦
- "is_planted": false, # 是否种植
- "is_dead": false, # 是否作物已死亡
- "crop_type": "", # 作物类型
- "grow_time": 0, # 生长时间
- "max_grow_time": 5 # 作物需要的最大生长时间(假设5秒成熟)
-
- })
-
-# 初始化作物选择列表
-# 初始化作物选择列表
-func _init_crop_list():
- crop_list.clear()
- for crop_name in can_planted_crop:
- var crop = can_planted_crop[crop_name]
- if crop["等级"] <= level: # 只显示当前等级可以种植的作物
-
- # 添加作物项
- crop_list.add_item(crop_name)
-
- # 随机生成颜色
- #var random_color = Color(randf(), randf(), randf())
- # 设置作物项的自定义背景颜色
- var item_index = crop_list.get_item_count() - 1 # 获取当前项的索引
- #crop_list.set_item_custom_bg_color(item_index, random_color)
-
- if crop["品质"] == "普通":
- crop_list.set_item_custom_bg_color(item_index, Color.GAINSBORO)
- pass
- elif crop["品质"] == "优良":
- crop_list.set_item_custom_bg_color(item_index, Color.DODGER_BLUE)
- pass
- elif crop["品质"] == "稀有":
- crop_list.set_item_custom_bg_color(item_index,Color.PURPLE )
- pass
- elif crop["品质"] == "史诗":
- crop_list.set_item_custom_bg_color(item_index,Color.YELLOW )
- pass
- elif crop["品质"] == "传奇":
- crop_list.set_item_custom_bg_color(item_index, Color.ORANGE_RED)
- pass
-
- # 如果需要设置文本颜色,可以使用下面的代码(可选)
- # crop_list.set_item_custom_color(item_index, Color.WHITE) # 设置文本颜色
-
-
-# 初始化作物选择列表
-func _init_crop_list2():
- for child in crop_grid_container.get_children():
- child.queue_free()
- for crop_name in can_planted_crop:
- var crop = can_planted_crop[crop_name]
-
- var level_btn = null
-
- var level6_btn = red_bar.duplicate()
-
- if crop["等级"] <= level: # 只显示当前等级可以种植的作物
-
-
- if crop["品质"] == "普通":
- level_btn = green_bar.duplicate()
- level_btn.connect("pressed", Callable(self, "_on_crop_selected").bind(crop_name))
- level_btn.text = str(crop_name)
- crop_grid_container.add_child(level_btn)
- pass
- elif crop["品质"] == "优良":
- level_btn = white_blue_bar.duplicate()
- level_btn.connect("pressed", Callable(self, "_on_crop_selected").bind(crop_name))
- level_btn.text = str(crop_name)
- crop_grid_container.add_child(level_btn)
- pass
- elif crop["品质"] == "稀有":
- level_btn = orange_bar.duplicate()
- level_btn.connect("pressed", Callable(self, "_on_crop_selected").bind(crop_name))
- level_btn.text = str(crop_name)
- crop_grid_container.add_child(level_btn)
- pass
- elif crop["品质"] == "史诗":
- level_btn = pink_bar.duplicate()
- level_btn.connect("pressed", Callable(self, "_on_crop_selected").bind(crop_name))
- level_btn.text = str(crop_name)
- crop_grid_container.add_child(level_btn)
- pass
- elif crop["品质"] == "传奇":
- level_btn = black_blue_bar.duplicate()
- level_btn.connect("pressed", Callable(self, "_on_crop_selected").bind(crop_name))
- level_btn.text = str(crop_name)
- crop_grid_container.add_child(level_btn)
- pass
-
- # 如果需要设置文本颜色,可以使用下面的代码(可选)
- # crop_list.set_item_custom_color(item_index, Color.WHITE) # 设置文本颜色
-
-
- pass
-
-
-# 更新农场地块状态到 GridContainer
-func _update_farm_lots(): #每一秒更新一次状态
- for child in grid_container.get_children():
- child.queue_free()
-
- for j in 5:
- if farm_lots[j]["is_diged"] == false:
- farm_lots[j]["is_diged"] = true
- pass
- pass
-
- for i in range(len(farm_lots)):
-
- var lot = farm_lots[i]
- var button = crop_item.duplicate()
- var label = button.get_node("Label")
- var progressbar = button.get_node("ProgressBar")
- pass
-
-
-
- if lot["is_diged"] == true:
- dig_money = (i+1) * 1000
- dig_button.text = "开垦"+"["+str(dig_money)+"]"
- if lot["is_planted"] == true:
-
- #寒冷环境配置,作物随机概率死亡
- climate_death_timer += 1
- if climate_death_timer >= 60 :
- if random_probability(can_planted_crop[lot["crop_type"]]["耐候性"]):
- lot["is_dead"] = true
- pass
- climate_death_timer = 0
-
- pass
-
- #如果作物已死亡!
- if lot["is_dead"] == true:
- print("["+farm_lots[i]["crop_type"]+"]"+"已死亡!")
- label.modulate = Color.NAVY_BLUE
- label.text = "["+farm_lots[i]["crop_type"]+"已死亡"+"]"
-
- pass
- #否者作物正常生长
- else:
- #label.text = lot["crop_type"] + " (" + str(int(lot["grow_time"])) + "/" + str(int(lot["max_grow_time"])) + ")"
- var crop_name = lot["crop_type"]
- label.text = "["+can_planted_crop[crop_name]["品质"]+"-"+lot["crop_type"]+"]"
-
- #根据品质显示颜色
- if(can_planted_crop[crop_name]["品质"]=="普通"):
- label.modulate = Color.GAINSBORO
- pass
- elif (can_planted_crop[crop_name]["品质"]=="优良"):
- label.modulate = Color.DODGER_BLUE
- pass
- elif (can_planted_crop[crop_name]["品质"]=="稀有"):
- label.modulate = Color.PURPLE
- pass
- elif (can_planted_crop[crop_name]["品质"]=="史诗"):
- label.modulate = Color.YELLOW
- pass
- elif (can_planted_crop[crop_name]["品质"]=="传奇"):
- label.modulate = Color.ORANGE_RED
- pass
-
- progressbar.show()
- progressbar.max_value = int(lot["max_grow_time"])
- progressbar.set_target_value( int(lot["grow_time"]) )
- #if is_blink_on:
- #label.modulate = Color.YELLOW
- #else:
- #label.modulate = Color.ORANGE
- pass
- pass
-
-
- else:
- #土地开垦后没有作物则显示为空地
- label.modulate =Color.GREEN
- label.text = "["+"空地"+"]"
- progressbar.hide()
- #label.modulate = Color.WHITE
- pass
- pass
- else :
- #土地没有开垦则显示未开垦
- label.modulate =Color.WEB_GRAY
- label.text = "["+"未开垦"+"]"
- progressbar.hide()
- #label.modulate = Color.WHITE
- pass
-
- # 设置最小尺寸
- #button.custom_minimum_size = Vector2(100, 100)
-
-
-
- button.connect("pressed", Callable(self, "_on_item_selected").bind(i))
- grid_container.add_child(button)
-
-# 更新玩家信息显示
-func _update_ui():
- show_money.text = "当前金钱:" + str(money) + " 元"
- show_money.modulate = Color.ORANGE
- show_experience.text = "当前经验:" + str(experience) + " 点"
- show_experience.modulate = Color.GREEN
- show_level.text = "当前等级:" + str(level) + " 级"
- show_level.modulate = Color.DODGER_BLUE
-
-# 处理地块点击事件
-func _on_item_selected(index):
- var lot = farm_lots[index]
- if lot["is_diged"]:
- if lot["is_planted"]:
- if lot["is_dead"]:
- print(lot["crop_type"]+"已被铲除")
- root_out_crop(index)
- #label.modulate = Color.NAVY_BLUE
- #label.text = "["+lot["crop_type"]+"已死亡"+"]"
- pass
- else:
- _harvest_crop(index)
- pass
- pass
- else:
- # 记录选中的地块索引,显示作物选择列表
- selected_lot_index = index
- double_click_close(crop_grid_container)
- pass
- pass
- else :
- double_click_close(land_panel)
- dig_index = index
-
- pass
-
-
-func double_click_close(node):
- if node.visible == false:
- node.show()
- pass
- else :
- node.hide()
- pass
- pass
-
-# 处理作物选择事件
-func _on_crop_selected(crop_index):
- print(crop_index)
- #var crop_name = crop_list.get_item_text(crop_index).split(" (")[0]
- var crop_name = crop_index
-
- if selected_lot_index != -1:
- _plant_crop(selected_lot_index, crop_name)
- selected_lot_index = -1
-
- #crop_list.hide() # 种植完成后隐藏作物选择列表
- crop_grid_container.hide()
-
-# 种植作物
-func _plant_crop(index, crop_name):
- var crop = can_planted_crop[crop_name]
- if money < crop["花费"]:
- print("金钱不足,无法种植 " + crop_name)
- toast.Toast("金钱不足,无法种植 " + crop_name, Color.RED)
- return
-
- money -= crop["花费"]
- farm_lots[index]["is_planted"] = true
- farm_lots[index]["crop_type"] = crop_name
- farm_lots[index]["grow_time"] = 0
- farm_lots[index]["max_grow_time"] = crop["生长时间"]
-
- print("在地块[[" + str(index) + "]种植了[" + crop_name + "]")
- toast.Toast("在地块[[" + str(index) + "]种植了[" + crop_name + "]", Color.GREEN)
- toast2.Toast(
- "名称:"+crop_name+"\n"+
- "花费:"+str(crop["花费"])+"\n"+
- "成熟时间:"+str(crop["生长时间"])+"\n"+
- "收益:"+str(crop["收益"])+"\n"+
- "品质:"+str(crop["品质"])+"\n"+
- "描述:"+str(crop["描述"])+"\n"+
- "耐候性:"+str(crop["耐候性"])+"\n"+
- "种植等级:"+str(crop["等级"])+"\n"+
- "获得经验:"+str(crop["经验"])+"\n"
- , Color.ORANGE)
-
- _update_ui()
- _update_farm_lots()
-
-#OS
-
-# 收获作物
-func _harvest_crop(index):
- var lot = farm_lots[index]
- if lot["grow_time"] >= lot["max_grow_time"]:
- var crop = can_planted_crop[lot["crop_type"]]
- money += crop["收益"]+crop["花费"]
- experience += crop["经验"]
- toast.Toast("从地块[" + str(index) + "]收获了[" + lot["crop_type"] + "]作物", Color.YELLOW)
- print("从地块[" + str(index) + "]收获了[" + lot["crop_type"] + "]作物")
-
- lot["is_planted"] = false
- lot["crop_type"] = ""
- lot["grow_time"] = 0
-
- _check_level_up()
- _update_ui()
- _update_farm_lots()
- else:
- print("作物还未成熟")
- toast.Toast("作物还未成熟", Color.RED)
-
-func root_out_crop(index):
- var lot = farm_lots[index]
- lot["is_planted"] = false
- lot["grow_time"] = 0
- toast.Toast("从地块[" + str(index) + "]铲除了[" + lot["crop_type"] + "]作物", Color.YELLOW)
- lot["crop_type"] = ""
- _check_level_up()
- _update_ui()
- _update_farm_lots()
- pass
-
-# 检查玩家是否可以升级
-func _check_level_up():
- var level_up_experience = 100 * level
- if experience >= level_up_experience:
- level += 1
- experience -= level_up_experience
- print("恭喜!你升到了等级 ", level)
- toast.Toast("恭喜!你升到了" + str(level) + "级 ", Color.SKY_BLUE)
- _init_crop_list2()
-
-# 使用 _process 实现作物生长机制
-var update_timer: float = 0.0
-var update_interval: float = 0.5
-
-func _physics_process(delta):
- update_timer += delta
-
- #当作物成熟后(一个一秒钟计时器)
- if update_timer >= update_interval:
- tip.text = "游戏自动保存剩余【"+str(save_time)+"】秒"
- save_time -= 1
- if save_time < 0:
- _save_game()
- save_time = 10
- pass
-
- for i in range(len(farm_lots)):
- var lot = farm_lots[i]
- if lot["is_planted"]:
- lot["grow_time"] += grow_speed * update_interval
- if lot["grow_time"] >= lot["max_grow_time"]:
- lot["grow_time"] = lot["max_grow_time"]
-
- blink_counter += blink_speed * update_interval
- is_blink_on = int(blink_counter) % 2 == 0
- else:
- is_blink_on = false
- blink_counter = 0.0
-
- #_update_farm_lots() # 更新地块信息
- update_timer = 0.0 # 重置计时器
-
-
-func _on_dig_button_pressed():
- if money < dig_money:
- print("金钱不足,无法开垦" )
- toast.Toast("金钱不足,无法开垦", Color.RED)
- else:
- money -= dig_money
- farm_lots[dig_index]["is_diged"] = true
- land_panel.hide()
- _update_ui()
- _update_farm_lots()
- pass
-
-
-
-# 保存游戏数据
-func _save_game():
- # 创建一个字典来保存游戏状态
- var save_data = {
- "money": money,
- "experience": experience,
- "level": level,
- "farm_lots": farm_lots
- }
- write_txt_file(game_path, str(save_data), false)
- # 将字典写入文件
-
-
-# 加载游戏数据
-func _load_game():
- pass
- ## 读取字典
- #var save_data = JSON.parse_string(read_txt_file(game_path))
- ##print(read_json_file("C:/Users/shumengya/Desktop/smyfarm/save.txt"))
- #
- #money = save_data["money"]
- #experience = save_data["experience"]
- #level = save_data["level"]
- #farm_lots = save_data["farm_lots"]
- ##file.close()
- #toast.Toast("游戏已加载!", Color.GREEN)
- #_update_ui()
- #_update_farm_lots()
- #_init_crop_list2()
-
-# 添加按键触发保存和加载的功能
-func _input(event):
- if event.is_action_pressed("ui_save"): # 需要在输入设置中定义这个动作
- _save_game()
- elif event.is_action_pressed("ui_load"): # 需要在输入设置中定义这个动作
- _load_game()
-
-# 写入 TXT 文件
-func write_txt_file(file_path: String, text: String, append: bool = false) -> void:
- var file
- if append == true:
- file = FileAccess.open(file_path, FileAccess.READ_WRITE) # 追加模式
- if file:
- file.seek_end() # 移动光标到文件末尾
- else:
- file = FileAccess.open(file_path, FileAccess.WRITE) # 覆盖模式
- if file:
- file.store_string(text)
- file.close()
- toast.Toast("游戏已保存!", Color.GREEN)
- else:
- print("写入文件时打开失败: ", file_path)
- toast.Toast("写入文件时打开失败!", Color.RED)
-
-# 读取 TXT 文件
-func read_txt_file(file_path: String) -> String:
- var file = FileAccess.open(file_path, FileAccess.READ)
- if file:
- var text = file.get_as_text()
- file.close()
- return text
- else:
- print("打开文件失败: ", file_path)
- return ""
-
-
-func random_probability(probability: float) -> bool:
- # 确保传入的概率值在 0 到 1 之间
- if probability*0.001 < 0.0 or probability*0.001 > 1.0:
- print("概率值必须在 0 和 1 之间")
- return false
-
- # 生成一个 0 到 1 之间的随机数
- var random_value = randf()
-
- # 如果随机数小于等于概率值,则返回 true
- return random_value <= (probability*0.001)
-
-
-#这里处理登录逻辑,如果用户没有账号,直接注册一个新的json文件
-func _on_login_button_pressed():
- var user_name = username_input.text
- var user_password = password_input.text
- if(username_input == " " or password_input == " "):
- print("用户名或密码不能为空!")
- pass
- else :
- #这里处理登录逻辑
- pass
- pass
-
-
-# 在线程中执行的函数
-func _thread_update_farm_lots(data):
- while true:
- _update_farm_lots() # 更新地块信息
-
-
-
- # 控制更新频率
- OS.delay_msec(1000)