update: 更新到godot4.4.1,并大量重构代码

This commit is contained in:
ZZY
2025-06-09 18:17:06 +08:00
parent b27abb55a2
commit 3fa39fc71e
39 changed files with 801 additions and 790 deletions

7
.gitignore vendored
View File

@ -16,13 +16,14 @@ data_*/
mono_crash.*.json
# MyProject specific ignores
.*/
.vscode/
.vs/
android/
Bin/
bin/
*.aseprite
*.csproj
*.csproj.old
*.sln
*.error
*.key*
@ -34,3 +35,7 @@ bin/
# Test files
Test/bin
Test/obj
# temp ignores
Lang/*
*.zip

File diff suppressed because one or more lines are too long

View File

@ -1,4 +1,4 @@
<Project Sdk="Godot.NET.Sdk/4.4.0">
<Project Sdk="Godot.NET.Sdk/4.4.1">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<EnableDynamicLoading>true</EnableDynamicLoading>
@ -7,5 +7,16 @@
</PropertyGroup>
<ItemGroup>
<Compile Remove="Test\**\*" />
<Protobuf Include="Protos\chess.proto" GrpcServices="Client" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Google.Protobuf" Version="3.30.2" />
<PackageReference Include="Grpc.Net.Client" Version="2.70.0" />
<PackageReference Include="Grpc.Tools" Version="2.71.0">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="KeraLua" Version="1.4.5" />
<PackageReference Include="NLua" Version="1.7.5" />
</ItemGroup>
</Project>

16
Main.cs
View File

@ -29,7 +29,7 @@ public partial class Main : Node2D
// }
// Called when the node enters the scene tree for the first time.
Global global = null;
GlobalManager global = null!;
public override void _Ready() {
// GetTree().Connect("screen_resized", ResizeChessboardToFitScreen);
// Button undo = GetNode<Button>("Undo");
@ -40,9 +40,9 @@ public partial class Main : Node2D
// ChessBoard board1 = GetChild<ChessBoard>(0);
// board.Visible = false;
// board.Can
global = GetNode<Global>("/root/Global");
global = GlobalManager.Instance;
global.GlobalTheme = GetChild<Control>(GetChildCount() - 1).Theme;
global.ConfigFlush();
global.GlobalThemeConfigFlush();
}
// Called every frame. 'delta' is the elapsed time since the previous frame.
@ -51,16 +51,20 @@ public partial class Main : Node2D
private void GoToSignlePlayer() {
// global.GotoScene("res://Scenes/SinglePlayer.tscn");
global.GotoScene("res://Scenes/ChessGame.tscn");
global?.GotoScene("res://Scenes/ChessGame.tscn");
}
private void GoToMultiPlayer() {
// global.GotoScene("res://Scenes/MultiPlayer.tscn");
global.GotoScene("res://Scenes/GameLobby.tscn");
global?.GotoScene("res://Scenes/GameLobby.tscn");
}
private void GoToSetting() {
global.GotoScene("res://Scenes/Setting.tscn");
global?.GotoScene("res://Scenes/Setting.tscn");
}
private void GotoMods() {
global?.GotoScene("res://Scenes/Mods.tscn");
}
// private void goToMenu() {

View File

@ -6,46 +6,54 @@
[node name="Main" type="Node2D"]
script = ExtResource("1_h4cv2")
[node name="Control" type="Control" parent="."]
layout_mode = 3
anchors_preset = 0
[node name="CenterContainer" type="CenterContainer" parent="."]
offset_right = 720.0
offset_bottom = 1280.0
theme = ExtResource("2_afihr")
[node name="SignlePlayer" type="Button" parent="Control"]
layout_mode = 0
offset_left = 83.0
offset_top = 671.0
offset_right = 298.0
offset_bottom = 850.0
text = "单人"
[node name="VBoxContainer" type="VBoxContainer" parent="CenterContainer"]
custom_minimum_size = Vector2(720, 720)
layout_mode = 2
theme_override_constants/separation = 30
[node name="MultiPlayer" type="Button" parent="Control"]
layout_mode = 0
offset_left = 406.0
offset_top = 670.0
offset_right = 612.0
offset_bottom = 852.0
text = "多人"
[node name="Label" type="Label" parent="Control"]
layout_mode = 0
offset_left = 191.0
offset_top = 265.0
offset_right = 501.0
offset_bottom = 451.0
[node name="Label" type="Label" parent="CenterContainer/VBoxContainer"]
layout_mode = 2
size_flags_vertical = 6
theme_override_font_sizes/font_size = 48
text = "中国象棋"
text = "KEY_ChessGame"
horizontal_alignment = 1
vertical_alignment = 1
[node name="Setting" type="Button" parent="Control"]
layout_mode = 0
offset_left = 239.0
offset_top = 967.0
offset_right = 450.0
offset_bottom = 1150.0
text = "设置"
[node name="MarginContainer" type="MarginContainer" parent="CenterContainer/VBoxContainer"]
layout_mode = 2
theme_override_constants/margin_left = 30
theme_override_constants/margin_right = 30
[connection signal="pressed" from="Control/SignlePlayer" to="." method="GoToSignlePlayer"]
[connection signal="pressed" from="Control/MultiPlayer" to="." method="GoToMultiPlayer"]
[connection signal="pressed" from="Control/Setting" to="." method="GoToSetting"]
[node name="VBoxContainer" type="VBoxContainer" parent="CenterContainer/VBoxContainer/MarginContainer"]
layout_mode = 2
[node name="HBoxContainer" type="HBoxContainer" parent="CenterContainer/VBoxContainer/MarginContainer/VBoxContainer"]
layout_mode = 2
[node name="SignlePlayer" type="Button" parent="CenterContainer/VBoxContainer/MarginContainer/VBoxContainer/HBoxContainer"]
layout_mode = 2
size_flags_horizontal = 3
text = "KEY_SinglePlayer"
[node name="MultiPlayer" type="Button" parent="CenterContainer/VBoxContainer/MarginContainer/VBoxContainer/HBoxContainer"]
layout_mode = 2
size_flags_horizontal = 3
text = "KEY_MultiPlayer"
[node name="Setting" type="Button" parent="CenterContainer/VBoxContainer/MarginContainer/VBoxContainer"]
layout_mode = 2
text = "KEY_Setting"
[node name="Mod" type="Button" parent="CenterContainer/VBoxContainer/MarginContainer/VBoxContainer"]
layout_mode = 2
text = "KEY_Mode"
[connection signal="pressed" from="CenterContainer/VBoxContainer/MarginContainer/VBoxContainer/HBoxContainer/SignlePlayer" to="." method="GoToSignlePlayer"]
[connection signal="pressed" from="CenterContainer/VBoxContainer/MarginContainer/VBoxContainer/HBoxContainer/MultiPlayer" to="." method="GoToMultiPlayer"]
[connection signal="pressed" from="CenterContainer/VBoxContainer/MarginContainer/VBoxContainer/Setting" to="." method="GoToSetting"]
[connection signal="pressed" from="CenterContainer/VBoxContainer/MarginContainer/VBoxContainer/Mod" to="." method="GotoMods"]

View File

@ -38,7 +38,7 @@ size_flags_horizontal = 3
[node name="Home" type="Button" parent="Control/VBoxContainer/MarginContainer/HBoxContainer/MarginContainer"]
layout_mode = 2
text = "返回主页"
text = "KEY_BackHome"
[node name="MarginContainer2" type="MarginContainer" parent="Control/VBoxContainer/MarginContainer/HBoxContainer"]
layout_mode = 2
@ -47,7 +47,7 @@ size_flags_horizontal = 3
[node name="Undo" type="Button" parent="Control/VBoxContainer/MarginContainer/HBoxContainer/MarginContainer2"]
layout_mode = 2
size_flags_vertical = 4
text = "撤回"
text = "KEY_GameUndo"
[node name="MarginContainer3" type="MarginContainer" parent="Control/VBoxContainer/MarginContainer/HBoxContainer"]
layout_mode = 2
@ -55,7 +55,7 @@ size_flags_horizontal = 3
[node name="ReInit" type="Button" parent="Control/VBoxContainer/MarginContainer/HBoxContainer/MarginContainer3"]
layout_mode = 2
text = "重开"
text = "KEY_GameReInit"
[node name="MarginContainer3" type="MarginContainer" parent="Control/VBoxContainer"]
layout_mode = 2
@ -65,8 +65,7 @@ layout_mode = 2
[node name="Label" type="Label" parent="Control/VBoxContainer/MarginContainer3/HFlowContainer"]
layout_mode = 2
text = "You Are
"
text = "KEY_Content_YouAre"
[node name="LineEdit" type="LineEdit" parent="Control/VBoxContainer/MarginContainer3/HFlowContainer"]
layout_mode = 2
@ -75,7 +74,7 @@ editable = false
[node name="Label2" type="Label" parent="Control/VBoxContainer/MarginContainer3/HFlowContainer"]
layout_mode = 2
text = "Turns On"
text = "KEY_Content_TurnOn"
[node name="LineEdit2" type="LineEdit" parent="Control/VBoxContainer/MarginContainer3/HFlowContainer"]
layout_mode = 2
@ -94,8 +93,7 @@ grow_vertical = 0
[node name="Over" type="Button" parent="Control/MarginContainer2"]
layout_mode = 2
text = "结束回合
(提示对方结束)"
text = "KEY_OverThisTurn"
[connection signal="pressed" from="Control/VBoxContainer/MarginContainer/HBoxContainer/MarginContainer/Home" to="." method="GoHome"]
[connection signal="pressed" from="Control/VBoxContainer/MarginContainer/HBoxContainer/MarginContainer2/Undo" to="." method="Undo"]

View File

@ -10,7 +10,7 @@ metadata/_edit_use_anchors_ = true
[node name="Label" type="Label" parent="."]
layout_mode = 2
size_flags_horizontal = 0
text = "Server Status"
text = "KEY_ServerConnectStatus"
[node name="ColorRect" type="ColorRect" parent="."]
custom_minimum_size = Vector2(15, 15)

View File

@ -29,8 +29,7 @@ layout_mode = 2
[node name="Button" type="Button" parent="MarginContainer/VBoxContainer/MarginContainer"]
layout_mode = 2
text = "Back
"
text = "KEY_BackHome"
[node name="MarginContainer2" type="HFlowContainer" parent="MarginContainer/VBoxContainer"]
layout_mode = 2
@ -40,7 +39,7 @@ layout_mode = 2
[node name="Label" type="Label" parent="MarginContainer/VBoxContainer/MarginContainer2/MarginContainer"]
layout_mode = 2
text = "Connect States"
text = "KEY_ServerConnectStatus"
[node name="MarginContainer2" type="MarginContainer" parent="MarginContainer/VBoxContainer/MarginContainer2"]
layout_mode = 2

23
Scenes/Mods.tscn Normal file
View File

@ -0,0 +1,23 @@
[gd_scene load_steps=3 format=3 uid="uid://c2ov83uk7r6rq"]
[ext_resource type="Theme" uid="uid://intlbeu8h82r" path="res://Asserts/defaultTheme.tres" id="1_mhtia"]
[ext_resource type="Script" uid="uid://c8t8d8e7inajy" path="res://Scripts/Controllers/Mods.cs" id="1_mnyng"]
[node name="MarginContainer" type="MarginContainer"]
offset_right = 720.0
offset_bottom = 1280.0
theme = ExtResource("1_mhtia")
theme_override_constants/margin_left = 30
theme_override_constants/margin_top = 30
theme_override_constants/margin_right = 30
theme_override_constants/margin_bottom = 30
script = ExtResource("1_mnyng")
[node name="VBoxContainer" type="VBoxContainer" parent="."]
layout_mode = 2
[node name="Button" type="Button" parent="VBoxContainer"]
layout_mode = 2
text = "back"
[connection signal="pressed" from="VBoxContainer/Button" to="." method="OnBack"]

View File

@ -1,9 +1,11 @@
[gd_scene load_steps=4 format=3 uid="uid://c6gxufppw1fu3"]
[gd_scene load_steps=5 format=3 uid="uid://c6gxufppw1fu3"]
[ext_resource type="Theme" uid="uid://intlbeu8h82r" path="res://Asserts/defaultTheme.tres" id="1_6yfoi"]
[ext_resource type="Script" uid="uid://71ril3nh84rw" path="res://Scripts/Controllers/Setting.cs" id="1_xbvb3"]
[ext_resource type="PackedScene" uid="uid://pc83bstfltn" path="res://Scenes/Entities/ServerStatus.tscn" id="3_e50hu"]
[sub_resource type="ButtonGroup" id="ButtonGroup_efio3"]
[node name="Setting" type="MarginContainer"]
anchors_preset = 15
anchor_right = 1.0
@ -21,14 +23,21 @@ layout_mode = 2
[node name="Back" type="Button" parent="BoxContainer/MarginContainer"]
layout_mode = 2
text = "Back"
text = "KEY_BackHome"
[node name="MarginContainer7" type="MarginContainer" parent="BoxContainer"]
layout_mode = 2
[node name="Button" type="Button" parent="BoxContainer/MarginContainer7"]
layout_mode = 2
text = "Save"
text = "KEY_SaveConfigFile"
[node name="MarginContainer9" type="MarginContainer" parent="BoxContainer"]
layout_mode = 2
[node name="Button" type="Button" parent="BoxContainer/MarginContainer9"]
layout_mode = 2
text = "KEY_GetConfigDir"
[node name="MarginContainer2" type="MarginContainer" parent="BoxContainer"]
layout_mode = 2
@ -38,7 +47,7 @@ layout_mode = 2
[node name="Label" type="Label" parent="BoxContainer/MarginContainer2/Server"]
layout_mode = 2
text = "Server IP"
text = "KEY_ServerIP"
[node name="LineEdit" type="LineEdit" parent="BoxContainer/MarginContainer2/Server"]
layout_mode = 2
@ -52,7 +61,7 @@ layout_mode = 2
[node name="Label" type="Label" parent="BoxContainer/MarginContainer3/Name"]
layout_mode = 2
text = "Name"
text = "KEY_UserName"
[node name="LineEdit" type="LineEdit" parent="BoxContainer/MarginContainer3/Name"]
layout_mode = 2
@ -86,7 +95,7 @@ layout_mode = 2
[node name="Label" type="Label" parent="BoxContainer/MarginContainer5/HBoxContainer"]
layout_mode = 2
text = "Font Size"
text = "KEY_GlobalFontSize"
[node name="FontSize" type="LineEdit" parent="BoxContainer/MarginContainer5/HBoxContainer"]
layout_mode = 2
@ -103,6 +112,30 @@ min_value = 10.0
max_value = 50.0
value = 10.0
[node name="HBoxContainer2" type="HFlowContainer" parent="BoxContainer"]
layout_mode = 2
[node name="MarginContainer" type="MarginContainer" parent="BoxContainer/HBoxContainer2"]
layout_mode = 2
size_flags_horizontal = 3
[node name="Button" type="Button" parent="BoxContainer/HBoxContainer2/MarginContainer"]
layout_mode = 2
size_flags_horizontal = 3
toggle_mode = true
button_group = SubResource("ButtonGroup_efio3")
text = "简体中文"
[node name="MarginContainer2" type="MarginContainer" parent="BoxContainer/HBoxContainer2"]
layout_mode = 2
size_flags_horizontal = 3
[node name="Button2" type="Button" parent="BoxContainer/HBoxContainer2/MarginContainer2"]
layout_mode = 2
toggle_mode = true
button_group = SubResource("ButtonGroup_efio3")
text = "English"
[node name="HBoxContainer" type="HFlowContainer" parent="BoxContainer"]
layout_mode = 2
@ -161,9 +194,12 @@ text = "Trace Color"
[connection signal="pressed" from="BoxContainer/MarginContainer/Back" to="." method="OnBack"]
[connection signal="pressed" from="BoxContainer/MarginContainer7/Button" to="." method="OnSave"]
[connection signal="pressed" from="BoxContainer/MarginContainer9/Button" to="." method="OnGetSettingsFile"]
[connection signal="text_changed" from="BoxContainer/MarginContainer2/Server/LineEdit" to="." method="OnServerUrlChanged"]
[connection signal="text_changed" from="BoxContainer/MarginContainer3/Name/LineEdit" to="." method="OnNameChanged"]
[connection signal="value_changed" from="BoxContainer/MarginContainer6/FontSizeBar" to="." method="OnFontSizeChanged"]
[connection signal="toggled" from="BoxContainer/HBoxContainer2/MarginContainer/Button" to="." method="ChangeLangZHCN"]
[connection signal="toggled" from="BoxContainer/HBoxContainer2/MarginContainer2/Button2" to="." method="ChangeLangEN"]
[connection signal="pressed" from="BoxContainer/HBoxContainer/MarginContainer2/Button2" to="." method="OnClearUserData"]
[connection signal="pressed" from="BoxContainer/HFlowContainer/Button" to="." method="OnGetCacheDir"]
[connection signal="pressed" from="BoxContainer/HFlowContainer/Button2" to="." method="OnGetConfigDir"]

View File

@ -5,7 +5,7 @@ using ChineseChess;
public partial class ChessGame : Node2D {
ChessBoard board;
Global global;
GlobalManager global = GlobalManager.Instance;
ConfirmationDialog dialog;
private bool isSession = false;
ChessCore Game;
@ -15,15 +15,17 @@ public partial class ChessGame : Node2D {
// Called when the node enters the scene tree for the first time.
public override void _Ready() {
// Init.Call();
global = GetNode<Global>("/root/Global");
board = GetNode<ChessBoard>("Chessboard");
isSession = global.RPClient.IsOnline();
// ChessGameAPI api = new();
// api.BindToLua(global.ModManager.lua);
// isSession = global.RPClient.IsOnline();
GetNode<LineEdit>("Control/VBoxContainer/MarginContainer3/HFlowContainer/LineEdit")
.Text = global.GlobalData["player_color"].AsString();
LineEdit turnSideEdit = GetNode<LineEdit>("Control/VBoxContainer/MarginContainer3/HFlowContainer/LineEdit2");
turnSideEdit.Text = "red";
GD.Print("ChessGame uid:", global.RPClient.GetUserId(), " color:",global.GlobalData["player_color"]);
// GD.Print("ChessGame uid:", global.RPClient.GetUserId(), " color:",global.GlobalData["player_color"]);
dialog = new ConfirmationDialog {
DialogAutowrap = true,
@ -52,12 +54,12 @@ public partial class ChessGame : Node2D {
Vector.Vector2I vector = new(posX, posY);
if (isSession) {
Game.OnPosClicked(vector, ChessCore.PlayerSideType.Self);
var res = global.RPClient.SendSessionToAll(global.sessionId, new Dictionary {
{"type", "mouseClicked"},
{"X", pos.X},
{"Y", pos.Y},
{"id", global.RPClient.GetUserId()}
});
// var res = global.RPClient.SendSessionToAll(global.sessionId, new Dictionary {
// {"type", "mouseClicked"},
// {"X", pos.X},
// {"Y", pos.Y},
// {"id", global.RPClient.GetUserId()}
// });
} else {
Game.OnPosClicked(vector);
}
@ -66,13 +68,13 @@ public partial class ChessGame : Node2D {
if (isSession) {
GD.Print("ws is connected");
global.RPClient.OnPRCSessionExit += (cmd, code) => {
GoHome();
};
// global.RPClient.OnPRCSessionExit += (cmd, code) => {
// GoHome();
// };
global.RPClient.OnPRCSessionRecv += (msg) => {
SessionMsgHandle(msg["msg"].AsGodotDictionary());
};
// global.RPClient.OnPRCSessionRecv += (msg) => {
// SessionMsgHandle(msg["msg"].AsGodotDictionary());
// };
}
}
@ -80,50 +82,50 @@ public partial class ChessGame : Node2D {
public override void _Process(double delta) {
}
private void SessionMsgHandle(Dictionary msg) {
GD.PrintErr($"session msg: {msg}");
switch (msg["type"].AsString()) {
case "over":
if (global.RPClient.GetUserId() == msg["id"].AsString()) {
break;
}
dialog.Title = "Opponent Finished";
dialog.DialogText = "Turn On You\n";
dialog.Visible = true;
break;
case "mouseClicked":
if (msg["id"].ToString() == global.RPClient.GetUserId()) {
break;
}
Vector2 mouseClicked = new(GD.StrToVar(msg["X"].ToString()).AsInt32(),
GD.StrToVar(msg["Y"].ToString()).AsInt32());
Vector.Vector2I vector = new((int)mouseClicked.X, (int)mouseClicked.Y);
Game.OnPosClicked(vector, ChessCore.PlayerSideType.Opponent);
break;
case "undo":
Game.Undo();
break;
case "reInit":
Game.ReInit();
break;
}
}
// private void SessionMsgHandle(Dictionary msg) {
// GD.PrintErr($"session msg: {msg}");
// switch (msg["type"].AsString()) {
// case "over":
// if (global.RPClient.GetUserId() == msg["id"].AsString()) {
// break;
// }
// dialog.Title = "Opponent Finished";
// dialog.DialogText = "Turn On You\n";
// dialog.Visible = true;
// break;
// case "mouseClicked":
// if (msg["id"].ToString() == global.RPClient.GetUserId()) {
// break;
// }
// Vector2 mouseClicked = new(GD.StrToVar(msg["X"].ToString()).AsInt32(),
// GD.StrToVar(msg["Y"].ToString()).AsInt32());
// Vector.Vector2I vector = new((int)mouseClicked.X, (int)mouseClicked.Y);
// Game.OnPosClicked(vector, ChessCore.PlayerSideType.Opponent);
// break;
// case "undo":
// Game.Undo();
// break;
// case "reInit":
// Game.ReInit();
// break;
// }
// }
private void BtnOver() {
GD.Print($"BtnOver {isSession}");
if (isSession == false) {
return;
}
global.RPClient.SendSessionToAll(global.sessionId, new Dictionary{
{"type", "over"},
{"id", global.RPClient.GetUserId()},
});
// global.RPClient.SendSessionToAll(global.sessionId, new Dictionary{
// {"type", "over"},
// {"id", global.RPClient.GetUserId()},
// });
}
public void GoHome() {
if (global.RPClient.IsOnline()) {
global.RPClient.ExitServer();
}
// if (global.RPClient.IsOnline()) {
// global.RPClient.ExitServer();
// }
global.GotoScene("res://Main.tscn");
}
@ -131,10 +133,10 @@ public partial class ChessGame : Node2D {
GD.Print($"Undo {isSession}");
if (isSession) {
global.RPClient.SendSessionToAll(global.sessionId, new Dictionary{
{"type", "undo"},
{"id", global.RPClient.GetUserId()},
});
// global.RPClient.SendSessionToAll(global.sessionId, new Dictionary{
// {"type", "undo"},
// {"id", global.RPClient.GetUserId()},
// });
} else {
if (Game.board.Steps == 0) board.Clear();
Game.Undo();
@ -145,9 +147,9 @@ public partial class ChessGame : Node2D {
GD.PrintErr($"ReInit {isSession}");
if (isSession) {
global.RPClient.SendSessionToAll(global.sessionId, new Dictionary{
{"type", "reInit"},
});
// global.RPClient.SendSessionToAll(global.sessionId, new Dictionary{
// {"type", "reInit"},
// });
} else {
Game.ReInit();
board.Clear();

View File

@ -3,7 +3,7 @@ using Godot;
using Godot.Collections;
public partial class GameLobby : Control {
Global global = null;
GlobalManager global = GlobalManager.Instance;
Timer timer = null;
ItemList lists = null;
@ -15,32 +15,31 @@ public partial class GameLobby : Control {
// Called when the node enters the scene tree for the first time.
public override void _Ready() {
global = GetNode<Global>("/root/Global");
lists = GetNode<ItemList>("MarginContainer/VBoxContainer/MarginContainer3/ItemList");
dialog = GetNode<ConfirmationDialog>("Dialogs/ConfirmationDialog");
URL = global.GlobalConfigDict["server_url"].AsString();
userName = global.GlobalConfigDict["user_name"].AsString();
URL = global.ConfigManager.GetValue<string>("server_url");
userName = global.ConfigManager.GetValue<string>("user_name");
dialog.MinSize = new Vector2I(400, 200);
dialog.DialogAutowrap = true;
dialog.Canceled += () => {
if (dialog.Title == "Session Created")
global.RPClient.SessionAckCreate(dialog.GetMeta("sessionId").ToString(), false);
// if (dialog.Title == "Session Created")
// global.RPClient.SessionAckCreate(dialog.GetMeta("sessionId").ToString(), false);
};
dialog.Confirmed += () => {
if (dialog.Title == "Session Created") {
// FIXME
isAcceptedPart = true;
global.RPClient.SessionAckCreate(dialog.GetMeta("sessionId").ToString(), true);
// global.RPClient.SessionAckCreate(dialog.GetMeta("sessionId").ToString(), true);
}
};
global.RPClient.OnOpen += (string eventName, object[] args) => {
global.RPClient.UserInit(userName, "godot chessboard", () => {
global.RPClient.UserRename(userName);
return global.RPClient.RegionAdd("server");
});
};
// global.RPClient.OnOpen += (eventName, args) => {
// global.RPClient.UserInit(userName, "godot chessboard", () => {
// global.RPClient.UserRename(userName);
// return global.RPClient.RegionAdd("server");
// });
// };
// global.RPClient.OnOpen += (eventName, args) => {
// global.RPClient.UserInit(userName, "none", () => {
// GD.PrintErr($"User Init Success");
@ -49,59 +48,59 @@ public partial class GameLobby : Control {
// });
// // global.RPClient.UserRename(userName);
// };
global.RPClient.RegSessionAckCreateCallback((sessionId, res, reqUserId, reqUserName) => {
if (reqUserId != null) {
dialog.Title = "Session Created";
dialog.SetMeta("reqUserName", reqUserName);
dialog.SetMeta("reqUserId", reqUserId);
dialog.SetMeta("sessionId", sessionId);
// dialog.GetLabel==>Text = $"{sessdata["reqUserName"]}";
dialog.DialogText = $"username: {reqUserName}\n" +
$"reqUserId: {reqUserId}\n";
dialog.Visible = true;
} else {
if (res) {
// TODO FIXME
global.sessionId = sessionId;
if (!isAcceptedPart) {
global.GlobalData["player_color"] = "red";
} else {
global.GlobalData["player_color"] = "black";
}
// GD.PrintErr("sessionId: ", reqUserId, "color: ", global.GlobalData["player_color"].AsString());
global.GotoScene("res://Scenes/ChessGame.tscn");
} else {
dialog.Title = "Failed";
dialog.DialogText = $"session create failed";
dialog.Visible = true;
}
}
return true;
});
// global.RPClient.RegSessionAckCreateCallback((sessionId, res, reqUserId, reqUserName) => {
// if (reqUserId != null) {
// dialog.Title = "Session Created";
// dialog.SetMeta("reqUserName", reqUserName);
// dialog.SetMeta("reqUserId", reqUserId);
// dialog.SetMeta("sessionId", sessionId);
// // dialog.GetLabel==>Text = $"{sessdata["reqUserName"]}";
// dialog.DialogText = $"username: {reqUserName}\n" +
// $"reqUserId: {reqUserId}\n";
// dialog.Visible = true;
// } else {
// if (res) {
// // TODO FIXME
// global.sessionId = sessionId;
// if (!isAcceptedPart) {
// global.GlobalData["player_color"] = "red";
// } else {
// global.GlobalData["player_color"] = "black";
// }
// // GD.PrintErr("sessionId: ", reqUserId, "color: ", global.GlobalData["player_color"].AsString());
// global.GotoScene("res://Scenes/ChessGame.tscn");
// } else {
// dialog.Title = "Failed";
// dialog.DialogText = $"session create failed";
// dialog.Visible = true;
// }
// }
// return true;
// });
timer = new Timer();
AddChild(timer);
// timer = new Timer();
// AddChild(timer);
ColorRect colorRect = GetNode<ColorRect>("MarginContainer/VBoxContainer/MarginContainer2/MarginContainer2/ColorRect");
timer.Connect("timeout", Callable.From(() => {
if (global.RPClient.GetIsConnected()) {
colorRect.Color = Colors.Green;
} else {
colorRect.Color = Colors.Red;
}
FlushData();
}));
timer.Start(1);
// timer.Connect("timeout", Callable.From(() => {
// if (global.RPClient.GetIsConnected()) {
// colorRect.Color = Colors.Green;
// } else {
// colorRect.Color = Colors.Red;
// }
// FlushData();
// }));
// timer.Start(1);
Connect();
}
public void Connect() {
GD.Print("Connect");
if (global.RPClient.GetIsConnected()) {
return;
}
// if (global.RPClient.GetIsConnected()) {
// return;
// }
// global.RPClient.ExitServer();
global.RPClient.ConnectToUrlEx(URL);
// global.RPClient.ConnectToUrlEx(URL);
global.SetProcess(true);
}
@ -109,33 +108,33 @@ public partial class GameLobby : Control {
Dictionary item = lists.GetItemMetadata(index).AsGodotDictionary();
GD.Print($"Item {index} selected, {item}");
string[] strings = { item["id"].ToString() };
global.RPClient.SessionCreate(strings);
// global.RPClient.SessionCreate(strings);
}
private void FlushData() {
global.RPClient.RegionInspect("server", (data) => {
// GD.Print(data);
lists?.Clear();
foreach (Dictionary<string, string> user in data) {
string userId = user["id"].ToString();
string userName = user["name"].ToString();
if (userId == global.RPClient.GetUserId()) {
lists.SetItemDisabled(
lists.AddItem($"Name: {userName}"),
true);
continue;
}
var idx = lists.AddItem($"Name: {userName}");
lists.SetItemMetadata(idx, user);
lists.SetItemTooltip(idx, $"User ID: {userId}");
}
return true;
});
// global.RPClient.RegionInspect("server", (data) => {
// // GD.Print(data);
// lists?.Clear();
// foreach (Dictionary<string, string> user in data) {
// string userId = user["id"].ToString();
// string userName = user["name"].ToString();
// if (userId == global.RPClient.GetUserId()) {
// lists.SetItemDisabled(
// lists.AddItem($"Name: {userName}"),
// true);
// continue;
// }
// var idx = lists.AddItem($"Name: {userName}");
// lists.SetItemMetadata(idx, user);
// lists.SetItemTooltip(idx, $"User ID: {userId}");
// }
// return true;
// });
}
private void OnBack() {
global.RPClient.ExitServer();
// global.RPClient.ExitServer();
global.GotoScene("res://Main.tscn");
}
}

View File

@ -0,0 +1,30 @@
using Godot;
using System;
public partial class Mods : Control {
GlobalManager global = GlobalManager.Instance;
public override void _Ready() {
// RunDemo();
// ModManager modManager = new();
// modManager.RegistryFunc("OnInit", () => { GD.Print("OnInit"); }, true);
// modManager.RegistryFunc("foo", () => { GD.Print("Hello"); });
// LuaMod mod = new(ProjectSettings.GlobalizePath("res://Protos/test.lua"));
// mod.BindFunc(modManager);
// try {
// modManager.InvokeFunc<Action>("OnInit");
// }
// catch (System.Exception e) {
// GD.PrintErr("OnInit error: ", e.Message, e.StackTrace);
// }
}
public void OnOpenModFileDir() {
OS.ShellOpen(global.ConfigManager.GetValue<string>("mods_fpath") ?? "user://Mods/");
}
public void OnBack() {
ArgumentNullException.ThrowIfNull(global);
global.GotoScene("res://Main.tscn");
}
}

View File

@ -0,0 +1 @@
uid://c8t8d8e7inajy

View File

@ -1,35 +1,32 @@
using Godot;
using System;
using System.IO;
public partial class Setting : Control
{
Global global;
public partial class Setting : Control {
private GlobalManager global = GlobalManager.Instance;
private IConfigManager config = GlobalManager.Instance.ConfigManager;
int font_size;
LineEdit fontOut;
private LineEdit fontOut = null!;
// Called when the node enters the scene tree for the first time.
public override void _Ready()
{
global = GetNode<Global>("/root/Global");
public override void _Ready() {
fontOut = GetNode<LineEdit>("BoxContainer/MarginContainer5/HBoxContainer/FontSize");
font_size = (int)global.GlobalConfigDict["font_size"];
font_size = config.GetValue<int>("font_size");
GetNode<HSlider>("BoxContainer/MarginContainer6/FontSizeBar")
.Value = font_size;
fontOut.Text = font_size.ToString();
FillingData();
}
private void FillingData()
{
private void FillingData() {
GetNode<LineEdit>("BoxContainer/MarginContainer2/Server/LineEdit")
.Text = global.GlobalConfigDict["server_url"].ToString();
.Text = config.GetValue<string>("server_url");
GetNode<LineEdit>("BoxContainer/MarginContainer3/Name/LineEdit")
.Text = global.GlobalConfigDict["user_name"].ToString();
.Text = config.GetValue<string>("user_name");
}
// Called every frame. 'delta' is the elapsed time since the previous frame.
public override void _Process(double delta)
{
public override void _Process(double delta) {
}
private void OnBack() {
@ -41,23 +38,20 @@ public partial class Setting : Control
// OS.Alert("Saved", "Setting");
}
void OnNameChanged(string Value)
{
global.GlobalConfigDict["user_name"] = Value;
// global.ConfigFlush();
void OnNameChanged(string Value) {
config.SetValue("user_name", Value);
// config.GetValue<>Flush();
}
private void OnServerUrlChanged(string Value)
{
global.GlobalConfigDict["server_url"] = Value;
// global.ConfigFlush();
private void OnServerUrlChanged(string Value) {
config.SetValue("server_url", Value);
// config.GetValue<>Flush();
}
private void OnFontSizeChanged(float Value)
{
private void OnFontSizeChanged(float Value) {
font_size = (int)Value;
global.GlobalConfigDict["font_size"] = font_size;
global.ConfigFlush();
config.SetValue("font_size", font_size);
global.GlobalThemeConfigFlush();
fontOut.Text = font_size.ToString();
}
@ -77,6 +71,11 @@ public partial class Setting : Control
}
}
private static void OnGetSettingsFile() {
string path = ProjectSettings.GlobalizePath(GlobalManager.ConfigPath);
OS.ShellOpen(Path.GetDirectoryName(path));
}
private static void OnGetCacheDir() {
OS.Alert(OS.GetCacheDir(), "Cache Dir");
}
@ -92,4 +91,7 @@ public partial class Setting : Control
private static void OnGetUserDataDir() {
OS.Alert(OS.GetUserDataDir(), "User Data Dir");
}
private static void ChangeLangZHCN(bool _) => TranslationServer.SetLocale("zh_CN");
private static void ChangeLangEN(bool _) => TranslationServer.SetLocale("en");
}

View File

@ -1,8 +1,6 @@
// Chesspiece.cs
using Godot;
using ChineseChess;
using System.Linq;
using System;
using static IPiece;
public partial class ChessPiece : Sprite2D, IPieceOn {

View File

@ -1 +0,0 @@
uid://dd84v12101t1n

View File

@ -1,49 +1,69 @@
#nullable disable
using System.Collections.Generic;
using Godot;
using RPPackage;
public partial class Global : Node {
public RPClientEDWS RPClient = new();
public string sessionId;
public Node CurrentScene { get; set; }
public Theme GlobalTheme = null;
public partial class GlobalManager : Node {
public static GlobalManager Instance { get; private set; } = null!;
public static string ConfigPath { get; private set; } = "user://config.json";
private GlobalManager() {
ConfigManager.SetFilePath(ProjectSettings.GlobalizePath(ConfigPath));
ConfigManager.SetDefault(_default_config);
ConfigManager.LoadFromFile();
GD.Print("GameSystem Singleton Initialized");
}
readonly GodotConfigManager GlobalConfig = new("user://config.cfg");
public Dictionary<string, Variant> GlobalConfigDict = new() {
// TODO Will Change It
public readonly IConfigManager ConfigManager = new JsonConfigManager();
private static readonly Dictionary<string, object> _default_config = new() {
{"font_size", 20},
{"server_url", "wss://game.zzyxyz.com/"},
{"user_name", "undefined"}
{"user_name", "undefined"},
{"mods_fpath", "user://Mods/"},
{"mods_allowed", false},
};
public string sessionId = "";
public Node CurrentScene { get; set; } = null!;
public Theme GlobalTheme = null!;
// readonly GodotConfigManager GlobalConfig = new("user://config.cfg");
// TODO will remove this
public Dictionary<string, Variant> GlobalData = new() {
{"player_color", "red"},
};
// Called when the node enters the scene tree for the first time.
public override void _Ready() {
if (Instance == null) {
Instance = this;
}
else {
GD.PushError("GlobalManager already exists");
QueueFree();
}
if (OS.GetName() == "Android") {
bool ret = OS.RequestPermissions();
GD.Print($"RequestPermissions ret is {ret}");
}
// OS.RequestPermissions();
RPClient.OnRPCError += (string errCode, string type, string cmd, string errMsg) => {
GD.PrintErr($"errCode {errCode}, type/cmd {type}/{cmd}, errMsg {errMsg}");
};
RPClient.OnClose += (string eventName, object[] args) => {
SetProcess(false);
};
// RPClient.OnRPCError += (errCode, type, cmd, errMsg) => {
// GD.PrintErr($"errCode {errCode}, type/cmd {type}/{cmd}, errMsg {errMsg}");
// };
// RPClient.OnClose += (eventName, args) => {
// SetProcess(false);
// };
Viewport root = GetTree().Root;
CurrentScene = root.GetChild(root.GetChildCount() - 1);
GlobalConfig.LoadConfig("Global", GlobalConfigDict);
SetProcess(false);
}
public void ConfigFlush() {
int font_size = (int)GlobalConfigDict["font_size"];
public void GlobalThemeConfigFlush() {
int font_size = ConfigManager.GetValue<int>("font_size");
GlobalTheme.DefaultFontSize = font_size;
// GlobalTheme?.SetFontSize("font_size", "Label", font_size);
// GlobalTheme?.SetFontSize("font_size", "Button", font_size);
@ -53,29 +73,30 @@ public partial class Global : Node {
}
private void OnGotoScene() {
ConfigFlush();
GlobalThemeConfigFlush();
}
public void SaveConfig() {
GlobalConfig.SaveConfig("Global", GlobalConfigDict);
ConfigManager.SaveToFile();
// GlobalConfig.SaveConfig("Global", _conf_dict);
}
// Called every frame. 'delta' is the elapsed time since the previous frame.
public override void _Process(double delta) {
RPClient.PollEx(delta);
// RPClient.PollEx(delta);
}
public override void _Notification(int what) {
if (what == NotificationWMCloseRequest) {
// SaveConfig();
RPClient.Close();
// RPClient.Close();
GetTree().Quit(); // default behavior
}
}
public delegate void ChangeSceneCallback(Node newSence);
private static ChangeSceneCallback changeSceneCallback = null;
public void GotoScene(string path, ChangeSceneCallback callback = null) {
private static ChangeSceneCallback? changeSceneCallback = null;
public void GotoScene(string path, ChangeSceneCallback? callback = null) {
// This function will usually be called from a signal callback,
// or some other function from the current scene.
// Deleting the current scene at this point is

View File

@ -0,0 +1 @@
uid://gfwgyu7p8hoi

View File

@ -1,328 +0,0 @@
using Godot;
using Godot.Collections;
namespace RPPackage {
public partial class RPClientBaseEDWS : EventDrivenWebSocket {
public delegate void RPClientEventHandler(string cmd, Dictionary? data);
public delegate void RPClientErrorHandler(string errCode, string type, string cmd, string errMsg);
public event RPClientEventHandler? OnRPCUser;
public event RPClientEventHandler? OnRPCRegion;
public event RPClientEventHandler? OnRPCSession;
public event RPClientEventHandler? OnRPCMsg;
public event RPClientErrorHandler? OnRPCError;
public RPClientBaseEDWS() : base() {
OnText += (text) => {
// GD.Print($"response: {text}");
RPMessage? msg = RPHelper.HandleIncomingMessage(text);
if (msg == null) {
MakeRPCError("9999", "Unknown Msg", "Error", null);
return;
}
if (msg.Code != "0000") {
OnRPCError?.Invoke(msg.Code ?? "9999", msg.Type, msg.Cmd,
msg.Data?.ToString() ?? "");
return;
}
switch (msg.Type) {
case "user":
OnRPCUser?.Invoke(msg.Cmd, msg.Data);
break;
case "region":
OnRPCRegion?.Invoke(msg.Cmd, msg.Data);
break;
case "session":
OnRPCSession?.Invoke(msg.Cmd, msg.Data);
break;
case "msg":
OnRPCMsg?.Invoke(msg.Cmd, msg.Data);
break;
default:
MakeRPCError(msg.Code, "unknown", msg.Cmd, msg.Data?.ToString());
break;
}
};
}
protected void MakeRPCError(string errCode, string type, string cmd, string? errMsg) {
OnRPCError?.Invoke(errCode, type, cmd, errMsg ?? "null");
}
}
public partial class RPClientEDWS : RPClientBaseEDWS {
string? userName;
string? userId;
string? userToken;
string? regionId;
public string? GetUserId() { return userId; }
public delegate void SessionRecvHandle(Dictionary? msg);
public event SessionRecvHandle? OnPRCSessionRecv;
public event RPClientEventHandler? OnPRCSessionExit;
public RPClientEDWS() : base() {
OnRPCUser += (cmd, msg) => {
if (msg == null) {
MakeRPCError("0000", "User", "unknown", "unknown");
return;
}
switch (cmd) {
case "init":
userId = msg["userId"].AsString();
userToken = msg["token"].AsString();
_userInitCallback?.Invoke();
break;
case "rename":
userName = msg["_"].AsString();
break;
default:
MakeRPCError("0000", "user", "unknown", msg?.ToString());
break;
}
};
OnRPCRegion += (cmd, msg) => {
switch (cmd) {
case "add":
break;
case "inspect":
// var regions = msg["_"].AsGodotArray<Dictionary>();
_regionRecvCallback?.Invoke(cmd, msg);
break;
case "list":
// var users = msg["_"].AsGodotArray<Dictionary>();
_regionRecvCallback?.Invoke(cmd, msg);
break;
default:
MakeRPCError("0000", "region", "unknown", msg?.ToString());
break;
}
};
OnRPCSession += (cmd, msg) => {
switch (cmd) {
case "sendAll":
OnPRCSessionRecv?.Invoke(msg);
break;
case "create":
break;
case "ackCreate":
// GD.PrintErr($"{cmd} {msg} {__SessionAckCreateCallback__ == null}");
_sessionAckCreateCallback?.Invoke(cmd, msg);
break;
case "exit":
OnPRCSessionExit?.Invoke(cmd, msg);
break;
default:
break;
}
};
OnRPCMsg += (cmd, msg) => {
switch(cmd) {
case "echo":
GD.Print(msg?["_"].AsString());
break;
default:
break;
}
};
OnRPCError += (code, type, cmd, msg) => {
};
}
public static void ClearRPCClientFunc() {
}
public bool IsOnline() {
return GetIsConnected() && userId != null;
}
public static void ConnectServer(string url) {
}
public void ExitServer() {
this.SendRPMessage(new RPMessage {
Type = "user",
Cmd = "exit",
Uid = userId,
Token = userToken,
});
userId = null;
userToken = null;
this.Close();
}
public delegate bool UserInitCallback();
private UserInitCallback? _userInitCallback;
public bool UserInit(string userName, string fingerPrint, UserInitCallback callback) {
if (this.GetIsConnected() == false) {
return false;
}
this.SendRPMessage(new RPMessage{
Type = "user",
Cmd = "init",
Data = new Dictionary {
{ "userName", userName },
{ "fingerPrint", fingerPrint }
}
});
_userInitCallback = null;
if (callback != null) _userInitCallback += callback;
return true;
}
public bool UserRename(string newName) {
if (this.GetIsConnected() == false) {
return false;
}
this.SendRPMessage(new RPMessage{
Type = "user",
Cmd = "rename",
Uid = userId,
Token = userToken,
Data = new Dictionary {
{ "_", newName }
}
});
return true;
}
public bool RegionAdd(string regionId) {
if (this.GetIsConnected() == false || this.userId == null) {
return false;
}
this.SendRPMessage(new RPMessage{
Type = "region",
Cmd = "add",
Uid = userId,
Token = userToken,
Data = new Dictionary {
{ "regionId", regionId }
}
});
return true;
}
public delegate bool RegionInspectCallback(
Array<Dictionary<string, string>> _
);
private RPClientEventHandler? _regionRecvCallback;
public bool RegionInspect(string regionId, RegionInspectCallback callback) {
if (this.GetIsConnected() == false || this.userId == null) {
return false;
}
_regionRecvCallback = null;
_regionRecvCallback += (cmd, msg) => {
if (cmd != "inspect" || msg == null) {
return;
}
callback(msg["_"].AsGodotArray<Dictionary<string, string>>());
};
this.SendRPMessage(new RPMessage{
Type = "region",
Cmd = "inspect",
Uid = userId,
Token = userToken,
Data = new Dictionary {
{ "regionId", regionId }
}
});
return true;
}
public delegate bool SessionAckCreateCallback(
string sessionId,
bool res,
string? reqUserId,
string? reqUserName
);
private RPClientEventHandler? _sessionAckCreateCallback;
public void RegSessionAckCreateCallback(SessionAckCreateCallback recvCallback) {
_sessionAckCreateCallback = null;
_sessionAckCreateCallback += (cmd, msg) => {
if (msg == null) return;
string sessionId = msg["sessionId"].AsString();
bool res = msg.ContainsKey("res") && msg["res"].AsBool();
string? reqUserId = msg.ContainsKey("reqUserId") ? msg["reqUserId"].AsString() : null;
string? reqUserName = msg.ContainsKey("reqUserName") ? msg["reqUserName"].AsString() : null;
recvCallback(sessionId, res, reqUserId, reqUserName);
};
}
public bool SessionCreate(string[] usersId) {
if (this.GetIsConnected() == false || this.userId == null) {
return false;
}
this.SendRPMessage(new RPMessage {
Type = "session",
Cmd = "create",
Uid = userId,
Token = userToken,
Data = new Dictionary {
{ "_", usersId }
}
});
return true;
}
public bool SessionAckCreate(string sessionId, bool response)
{
if (this.GetIsConnected() == false || this.userId == null) {
return false;
}
// 根据响应情况发送确认消息给服务器
string code = response ? "0000" : "0001";
this.SendRPMessage(new RPMessage {
Type = "session",
Cmd = "ackCreate",
Uid = userId,
Token = userToken,
Code = code,
Data = new Dictionary {
{ "sessionId", sessionId },
{ "res", response }
}
});
return true;
}
public bool SendSessionToAll(string sessionId, Variant data) {
if (this.GetIsConnected() == false || this.userId == null || sessionId == null) {
return false;
}
this.SendRPMessage(new RPMessage{
Type = "session",
Cmd = "sendAll",
Uid = userId,
Token = userToken,
Data = new Dictionary {
{ "sessionId", sessionId },
{ "msg", data },
}
});
return true;
}
// ws.OnOpen += (eventName, args) => {
// ws.SendRPMessage(new RPMessage{
// Type = "user",
// Cmd = "tmp",
// });
// };
// ws.OnError += (eventName, args) => {
// GD.PrintErr(args);
// // SetProcess(false);
// };
// ws.OnClose += (eventName, args) => {
// // GD.Print("close");
// SetProcess(false);
// };
}
}

View File

@ -1 +0,0 @@
uid://piu7vpl63m2m

View File

@ -1,47 +0,0 @@
using Godot;
using Godot.Collections;
namespace RPPackage {
public static class RPHelper
{
public static Dictionary SerializeRPMessage(RPMessage message)
{
return message.ToDictionary();
}
public static RPMessage? DeserializeRPMessage(Dictionary data)
{
if (!data.ContainsKey("type") || !data.ContainsKey("cmd")) {
return null;
}
return new RPMessage {
Type = (string)data["type"],
Cmd = (string)data["cmd"],
Code = data.ContainsKey("code") ? (string)data["code"] : null,
Uid = data.ContainsKey("uid") ? (string)data["uid"] : null,
Token = data.ContainsKey("token") ? (string)data["token"] : null,
Data = data.ContainsKey("data") ? data["data"].AsGodotDictionary() : null,
};
}
// 假设你有WebSocket通信的实现这里仅展示如何使用上述方法
public static void SendRPMessage(this EventDrivenWebSocket ws, RPMessage message)
{
ws.SendJsonEx(RPHelper.SerializeRPMessage(message));
}
public static RPMessage? HandleIncomingMessage(string jsonMessage)
{
var dataDict = Json.ParseString(jsonMessage).AsGodotDictionary();
if (dataDict != null)
{
return RPHelper.DeserializeRPMessage(dataDict);
}
else
{
GD.PrintErr("Failed to parse incoming message.");
return null;
}
}
}
}

View File

@ -1 +0,0 @@
uid://bg8nobv3n6cek

View File

@ -1,34 +0,0 @@
using Godot;
using Godot.Collections;
namespace RPPackage {
public class RPMessage
{
public string Type { get; set; } = string.Empty;
public string Cmd { get; set; } = string.Empty;
public Dictionary? Data { get; set; }
public string? Uid { get; set; }
public string? Token { get; set; }
public string? Code { get; set; }
public Dictionary ToDictionary()
{
var dict = new Dictionary {
// if (Type != null)
{ "type", Type },
// if (Cmd != null)
{ "cmd", Cmd }
};
if (Data != null)
dict.Add("data", Data);
if (Uid != null)
dict.Add("uid", Uid);
if (Token != null)
dict.Add("token", Token);
if (Code != null)
dict.Add("code", Code);
return dict;
}
}
}

View File

@ -1 +0,0 @@
uid://bunvpv6p54l78

View File

@ -1,114 +0,0 @@
using Godot;
using Godot.Collections;
public partial class EventDrivenWebSocket : WebSocketPeer {
public delegate void WebSocketEventHandler(string eventName, params object[]? args);
public delegate void WSBinMsgEventHandler(byte[] args);
public delegate void WSMsgEventHandler(string args);
public event WebSocketEventHandler? OnOpen;
public event WSBinMsgEventHandler? OnMessage;
public event WSMsgEventHandler? OnText;
public event WSBinMsgEventHandler? OnBinary;
public event WebSocketEventHandler? OnClose;
public event WebSocketEventHandler? OnError;
private bool isConnected = false;
private bool isCloseEventFired = false;
private double connectingTime = double.NegativeInfinity;
public EventDrivenWebSocket() : base() {
isConnected = false;
}
public bool GetIsConnected() {
return isConnected;
}
public void PollEx(double delta) {
base.Poll();
CheckAndDispatchEvents(delta);
}
public void ConnectToUrlEx(string url, double delayTime = 3,
TlsOptions? tlsClientOptions = null) {
if (connectingTime >= 0) {
return;
}
Error err = ConnectToUrl(url, tlsClientOptions);
if (err != Error.Ok) {
OnError?.Invoke("error", err);
}
connectingTime = delayTime;
}
protected void CheckAndDispatchEvents(double delta) {
var state = GetReadyState();
switch (state) {
case State.Open when !isConnected:
isConnected = true;
OnOpen?.Invoke("open", null);
break;
case State.Open:
while (GetAvailablePacketCount() > 0) {
byte[] packet = GetPacket();
OnMessage?.Invoke(packet);
if (WasStringPacket()) {
OnText?.Invoke(packet.GetStringFromUtf8());
} else {
OnBinary?.Invoke(packet);
}
}
break;
case State.Closed:
connectingTime = double.NegativeInfinity;
OnClose?.Invoke("closed", GetCloseCode(), GetCloseReason());
isConnected = false;
break;
case State.Closing:
// OnClose?.Invoke("closing");
break;
case State.Connecting:
if (connectingTime >= 0) {
connectingTime -= delta;
} else if (connectingTime != double.NegativeInfinity){
connectingTime = double.NegativeInfinity;
Close();
OnError?.Invoke("connectTimeOut", Error.Timeout);
}
break;
default:
// 可以在这里处理其他状态或错误
OnError?.Invoke("error", "Unknown WebSocket state.");
break;
}
}
public void SendBinaryEx(byte[] data) {
SendEx(data);
}
public void SendJsonEx(Dictionary msg) {
SendTextEx(Json.Stringify(msg));
}
public Error SendTextEx(string message) {
if (isConnected) {
return SendText(message);
} else {
OnError?.Invoke("error", "Attempt to send on a closed connection.");
return Error.ConnectionError;
}
}
public Error SendEx(byte[] message, WriteMode writeMode = WriteMode.Binary) {
if (isConnected) {
return Send(message, writeMode);
} else {
OnError?.Invoke("error", "Attempt to send on a closed connection.");
return Error.ConnectionError;
}
}
}

View File

@ -1 +0,0 @@
uid://bsali4mwx62tt

View File

@ -0,0 +1,69 @@
using Godot;
using NLua;
using System;
using System.Text;
public class GlobalModManager
{
public readonly Lua lua = new();
private readonly string modsPath;
public GlobalModManager(string modsPath = "user://Mods/") {
this.modsPath = modsPath;
lua.State.Encoding = Encoding.UTF8;
// lua.State.SetHook(KeraLua.LuaHookMask.Count, 1000000);
InitSandBox();
// RegisterAPI();
}
public void LoadAllMods()
{
if (!DirAccess.DirExistsAbsolute(modsPath))
return;
using var dir = DirAccess.Open(modsPath);
if (dir == null) return;
dir.ListDirBegin();
string fileName = dir.GetNext();
while (!string.IsNullOrEmpty(fileName))
{
if (fileName.EndsWith(".lua"))
{
LoadMod(fileName);
}
fileName = dir.GetNext();
}
}
private void InitSandBox() {
}
private void LoadMod(string filePath)
{
try
{
string luaCode = LoadFile(filePath);
lua.DoString(luaCode);
GD.Print($"成功加载Mod: {filePath}");
}
catch (Exception e)
{
GD.PrintErr($"加载Mod {filePath} 失败: {e.Message}");
}
}
private static void SaveFile(string path, string content)
{
using var file = FileAccess.Open(path, FileAccess.ModeFlags.Write);
file.StoreString(content);
}
private static string LoadFile(string path)
{
using var file = FileAccess.Open(path, FileAccess.ModeFlags.Read);
string content = file.GetAsText();
return content;
}
}

View File

@ -0,0 +1 @@
uid://c45a7ldunixnh

View File

@ -0,0 +1,40 @@
using System;
using System.IO;
using System.Linq;
using Godot;
using NLua;
class LuaMod : IDisposable {
private readonly Lua lua = new();
public LuaMod(string path, string? package_path = null) {
lua.LoadCLRPackage();
lua.State.Encoding = System.Text.Encoding.UTF8;
lua["package.path"] = package_path ?? Path.GetDirectoryName(path) + "/?.lua;";
lua.RegisterFunction("print", new Action<object[]>(GD.Print).Method);
// Action bar = () => { GD.Print("bar"); };
// lua.RegisterFunction("bar", bar.Target, bar.Method);
lua.DoFile(path);
}
public void BindFunc(ModManager mod) {
foreach (var api in mod.GetAPIs()) {
lua.RegisterFunction(api.Key, api.Value.Target, api.Value.Method);
}
foreach (var hook in mod.GetHooks()) {
if (lua[hook.Key] is LuaFunction func) {
mod.AddHook(hook.Key, (args) => {
var rets = func.Call(args).FirstOrDefault();
if (rets is bool b) return b;
return false;
});
}
}
}
public void Dispose() {
lua?.Dispose();
GC.SuppressFinalize(this);
}
}

View File

@ -0,0 +1 @@
uid://dtqaboju24vmn

View File

@ -0,0 +1,45 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Reflection;
class ModManager {
private readonly Dictionary<string, Delegate> _api = [];
private readonly Dictionary<string, Delegate> _hooks = [];
public delegate bool OnCallback(params object[] args);
private readonly Dictionary<string, List<OnCallback>> _callbackList = [];
public ReadOnlyDictionary<string, Delegate> GetAPIs() => new(_api);
public ReadOnlyDictionary<string, Delegate> GetHooks() => new(_hooks);
public ModManager RegistryFunc<TDelegate>(string name, TDelegate handler, bool isHook = false)
where TDelegate : Delegate {
MethodInfo _ = handler.Method;
Dictionary<string, Delegate> dict = isHook ? _hooks : _api;
dict.Add(name, handler);
return this;
}
public bool AddHook(string name, OnCallback handler) {
if (_hooks.ContainsKey(name)) {
if (!_callbackList.TryGetValue(name, out var list)) {
list = [];
_callbackList[name] = list;
}
list.Add(handler);
return true;
}
return false;
}
public bool InvokeFunc<TDelegate>(string name, params object[] args)
where TDelegate : Delegate {
List<object> res = [];
if (_callbackList.TryGetValue(name, out var callback)) {
foreach (var func in callback) {
func?.Invoke(args);
}
}
return true;
}
}

View File

@ -0,0 +1 @@
uid://lmuddan86bi8

View File

@ -1,6 +1,5 @@
using Godot;
using System.Collections.Generic;
using System.IO;
class GodotConfigManager {
private readonly string ConfigFilePath;
@ -41,8 +40,8 @@ class GodotConfigManager {
}
}
public void SaveConfig(string SessionName,
Dictionary<string, Variant> data) {
public void SaveConfig(string SessionName, Dictionary<string, Variant> data)
{
// 将 GlobalConfig 中的键值对写入配置文件
foreach (var key in data.Keys)
{

View File

@ -0,0 +1,17 @@
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
public interface IConfigManager {
void SetFilePath(string filePath);
void SetDefault(Dictionary<string, object> defalutConfig);
T GetValue<T>(string key);
void SetValue<T>(string key, [NotNull]T value) {
ArgumentNullException.ThrowIfNull(key);
SetValue(key, (object?)value);
}
void SetValue(string key, [NotNull]object? value);
bool HasKey(string key);
void SaveToFile();
void LoadFromFile();
}

View File

@ -0,0 +1 @@
uid://b8jvplvi4a7iv

View File

@ -0,0 +1,53 @@
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Text.Json;
public class JsonConfigManager : IConfigManager {
private string? filePath;
private Dictionary<string, object> config = [];
private Dictionary<string, object>? defaultConfig;
public T GetValue<T>(string key) {
if (config.TryGetValue(key, out object? val)) {
if (val is T t) {
return t;
} else if (val is JsonElement element) {
return element.Deserialize<T>() ??
throw new InvalidCastException($"无法将键'{key}'的值转换为类型{typeof(T).Name}");
}
}
if (
defaultConfig != null &&
defaultConfig.TryGetValue(key, out object? dval) &&
dval is T ret) {
return ret;
}
throw new KeyNotFoundException($"Key '{key}' not found in config.");
}
public bool HasKey(string key) => config.ContainsKey(key);
public void SaveToFile() {
ArgumentException.ThrowIfNullOrWhiteSpace(filePath);
File.WriteAllText(filePath, JsonSerializer.Serialize(config));
}
public void LoadFromFile() {
ArgumentException.ThrowIfNullOrWhiteSpace(filePath);
if (!File.Exists(filePath)) {
return;
}
config = JsonSerializer.Deserialize
<Dictionary<string, object>>(File.ReadAllText(filePath)) ?? [];
}
public void SetDefault(Dictionary<string, object> defaultConfig) => this.defaultConfig = defaultConfig;
public void SetFilePath(string filePath) => this.filePath = filePath;
public void SetValue(string key, [NotNull]object? value) {
ArgumentNullException.ThrowIfNull(value);
config[key] = value;
}
}

View File

@ -0,0 +1 @@
uid://ddvrwflje2x87

View File

@ -14,11 +14,10 @@ config/name="ChessGame"
config/version="0.0.6"
run/main_scene="res://Main.tscn"
config/features=PackedStringArray("4.4", "C#", "Mobile")
config/icon="uid://c0wpthj7y1ayp"
[autoload]
Global="*res://Scripts/Global.cs"
GlobalManager="*res://Scripts/GlobalManager.cs"
[display]
@ -31,6 +30,10 @@ window/handheld/orientation=1
project/assembly_name="ChessGame"
[internationalization]
locale/translations=PackedStringArray("res://Lang/godot_chessgame/content/zh_Hans.po", "res://Lang/godot_chessgame/content/en_devel.po")
[navigation]
2d/name_localized={}