Upload logs to the server.

支持上传日志到服务器。
This commit is contained in:
Cold-Mint 2024-07-15 20:37:30 +08:00
parent 7365434f2b
commit 0b5e2c3217
23 changed files with 540 additions and 229 deletions

1
.gitignore vendored
View File

@ -5,3 +5,4 @@ export_presets.cfg
.vs/ .vs/
*.translation *.translation
*.user *.user
AppConfig.yaml

View File

@ -52,6 +52,34 @@ You need to fill in the Export Presets > Resources > Filter to export non-resour
data/* data/*
``` ```
## Configuring Openobserve
> This is optional, and the game will work even if you do not configure Openobserve.
openobserve is used to continuously collect logs and alarm information after a game has been released.
#### Set up the openobserve server
see[openobserve](https://github.com/openobserve/openobserve)
#### Write configuration
After you have set up an openobserve server, follow the following steps to configure the file:
1. Create a configuration file named **AppConfig.yaml** in the root directory of your project.
2. Fill in the information for the remote server.
```yaml
open_observe:
address: [address]
access_token: [token]
org_id: [org_id]
stream_name: [stream_name]
```
address Indicates the address of the server in the format of http(s)://www.example.com. (Support http and https)
## Participate in translation ## Participate in translation
The project is prepared for localization at the beginning of writing. You can edit the csv file in the locals directory. To modify and add new translations. The project is prepared for localization at the beginning of writing. You can edit the csv file in the locals directory. To modify and add new translations.

View File

@ -50,6 +50,34 @@ git clone https://github.com/Cold-Mint/Traveller.git
data/* data/*
``` ```
## はいちOpenobserve
> これはオプションなので、Openobserveを設定しなくてもゲームは正常に動作します。
openobserveは、リリース後にログやアラームを継続的に収集するために使用されます。
#### 搭建openobserve衣服务器
読み過ごす:[openobserve](https://github.com/openobserve/openobserve)
#### 構成を書きます
openobserveのサーバーを構築したら、次のようにファイルを設定します。
1. プロジェクトのルートディレクトリに**AppConfig.yaml **というプロファイルを作成します。
2. リモートサーバーの情報を入力します。
```yaml
open_observe:
address: [address]
access_token: [token]
org_id: [org_id]
stream_name: [stream_name]
```
address サーバーのアドレス、フォーマットはこうなります http(s)://www.example.com。支持http和https
## 翻訳に携わります ## 翻訳に携わります
このプロジェクトは、当初からローカライズの準備ができていました。localsディレクトリのcsvファイルを編集することができます。新しい翻訳を加えたり修正したりしています このプロジェクトは、当初からローカライズの準備ができていました。localsディレクトリのcsvファイルを編集することができます。新しい翻訳を加えたり修正したりしています

View File

@ -52,6 +52,34 @@ git clone https://github.com/Cold-Mint/Traveller.git
data/* data/*
``` ```
## 配置Openobserve
> 这是可选的操作即使您不配置Openobserve游戏也能正常运行。
openobserve用于在游戏发布后持续收集日志和报警信息。
#### 搭建openobserve服务器
请见:[openobserve](https://github.com/openobserve/openobserve)
#### 编写配置
在您搭建完毕openobserve的服务器后按如下步骤配置文件
1. 在项目的根目录创建名为**AppConfig.yaml**的配置文件。
2. 填入远程服务器的信息。
```yaml
open_observe:
address: [address]
access_token: [token]
org_id: [org_id]
stream_name: [stream_name]
```
address 服务器的地址,格式为 http(s)://www.example.com。支持http和https
## 参与翻译 ## 参与翻译
此项目在编写之初就为本地化做好了准备。您可以编辑locals目录下的csv文件。来修改和添加新的翻译。 此项目在编写之初就为本地化做好了准备。您可以编辑locals目录下的csv文件。来修改和添加新的翻译。

View File

@ -23,7 +23,7 @@ log_player_packed_scene_not_exist,玩家预制场景不存在。,Player packed s
log_exit_the_room_debug,节点{0}退出房间{1}。,"Node {0} exits room {1}.",ノード{0}が部屋{1}を退出します。 log_exit_the_room_debug,节点{0}退出房间{1}。,"Node {0} exits room {1}.",ノード{0}が部屋{1}を退出します。
log_enter_the_room_debug,节点{0}进入房间{1}。,"Node {0} enters room {1}.",ノード{0}が部屋{1}に入ります。 log_enter_the_room_debug,节点{0}进入房间{1}。,"Node {0} enters room {1}.",ノード{0}が部屋{1}に入ります。
log_death_info,生物{0}被{1}击败。,"Creature {0} was defeated by {1}.",生物{0}が{1}によって打ち負かされました。 log_death_info,生物{0}被{1}击败。,"Creature {0} was defeated by {1}.",生物{0}が{1}によって打ち負かされました。
log_appConfig_not_exist,您可以在项目根目录创建名为AppConfig.yaml的文件并在其中配置OpenObserve的数据以便在游戏发布后持续收集日志和运行数据。,You can create a file named AppConfig.yaml in the project root directory and configure OpenObserve data in it to collect log and run data continuously after the game has been released.,プロジェクトのルートディレクトリにappconfig.yamlというファイルを作成し、そこにOpenObserveのデータを配置して、リリース後も継続的にログや実行データを収集することができます。
log_loot_list_has_no_entries,ID为{0}的战利品表,没有指定条目。,"Loot list with ID {0}, no entry specified.",ID{0}の戦利品テーブルは、エントリ指定されていません。 log_loot_list_has_no_entries,ID为{0}的战利品表,没有指定条目。,"Loot list with ID {0}, no entry specified.",ID{0}の戦利品テーブルは、エントリ指定されていません。
log_not_within_the_loot_spawn_range,给定的数值{0}没有在战利品{1}的生成范围{2}内。,The given value {0} is not within the spawn range {2} of loot {1}.,与えられた数値{0}は戦利品{1}の生成範囲{2}内にありません。 log_not_within_the_loot_spawn_range,给定的数值{0}没有在战利品{1}的生成范围{2}内。,The given value {0} is not within the spawn range {2} of loot {1}.,与えられた数値{0}は戦利品{1}の生成範囲{2}内にありません。
log_loot_data_quantity,有{0}个战利品数据被返回。,{0} loot data was returned.,{0}個の戦利品データが返されます。 log_loot_data_quantity,有{0}个战利品数据被返回。,{0} loot data was returned.,{0}個の戦利品データが返されます。
@ -75,4 +75,8 @@ log_owner_is_not_AiCharacter,所有者不是AiCharacter。,Owner is not AiCharac
log_weaponContainer_is_null,武器容器为空。,Weapon container is null.,武器コンテナが空です。 log_weaponContainer_is_null,武器容器为空。,Weapon container is null.,武器コンテナが空です。
log_find_nearest_item,查找最近的物品。,Find the nearest item.,最も近いアイテムを見つけます。 log_find_nearest_item,查找最近的物品。,Find the nearest item.,最も近いアイテムを見つけます。
log_float_label_instantiate_failed,浮动标签实例化失败。,Float label instantiation failed.,フロートラベルのインスタンス化に失敗しました。 log_float_label_instantiate_failed,浮动标签实例化失败。,Float label instantiation failed.,フロートラベルのインスタンス化に失敗しました。
log_pickable_picked_up,可拾捡物被捡起了,那么不显示标签。,"If the pickable item is picked up, the label is not displayed.",でも、拾得物が拾い上げられたら、ラベルは表示されません。 log_pickable_picked_up,可拾捡物被捡起了,那么不显示标签。,"If the pickable item is picked up, the label is not displayed.",でも、拾得物が拾い上げられたら、ラベルは表示されません。
log_start_uploading,开始上传{0}条日志。,Start uploading {0} logs.,{0}個のログをアップロードを開始します。
log_upload_successful,上传成功,已上传{0}条日志,剩余{1}条日志待上传。,"Upload successful, {0} logs uploaded, {1} logs remaining.",アップロードが成功しました、{0}個のログがアップロードされ、{1}個のログが残っています。
log_upload_failed,上传失败,错误代码:{0},剩余{1}条日志待上传。,"Upload failed, error code: {0}, {1} logs remaining.",アップロードに失敗しました、エラーコード:{0}、{1}個のログが残っています。
log_upload_status,已记录{0}条日志,上传阈值为{1}。,"{0} logs recorded, upload threshold is {1}.",{0}個のログが記録され、アップロード閾値は{1}です。
1 id zh en ja
23 log_exit_the_room_debug 节点{0}退出房间{1}。 Node {0} exits room {1}. ノード{0}が部屋{1}を退出します。
24 log_enter_the_room_debug 节点{0}进入房间{1}。 Node {0} enters room {1}. ノード{0}が部屋{1}に入ります。
25 log_death_info 生物{0}被{1}击败。 Creature {0} was defeated by {1}. 生物{0}が{1}によって打ち負かされました。
26 log_loot_list_has_no_entries log_appConfig_not_exist ID为{0}的战利品表,没有指定条目。 您可以在项目根目录创建名为AppConfig.yaml的文件,并在其中配置OpenObserve的数据,以便在游戏发布后持续收集日志和运行数据。 Loot list with ID {0}, no entry specified. You can create a file named AppConfig.yaml in the project root directory and configure OpenObserve data in it to collect log and run data continuously after the game has been released. ID{0}の戦利品テーブルは、エントリ指定されていません。 プロジェクトのルートディレクトリにappconfig.yamlというファイルを作成し、そこにOpenObserveのデータを配置して、リリース後も継続的にログや実行データを収集することができます。
27 log_not_within_the_loot_spawn_range log_loot_list_has_no_entries 给定的数值{0}没有在战利品{1}的生成范围{2}内。 ID为{0}的战利品表,没有指定条目。 The given value {0} is not within the spawn range {2} of loot {1}. Loot list with ID {0}, no entry specified. 与えられた数値{0}は戦利品{1}の生成範囲{2}内にありません。 ID{0}の戦利品テーブルは、エントリ指定されていません。
28 log_loot_data_quantity log_not_within_the_loot_spawn_range 有{0}个战利品数据被返回。 给定的数值{0}没有在战利品{1}的生成范围{2}内。 {0} loot data was returned. The given value {0} is not within the spawn range {2} of loot {1}. {0}個の戦利品データが返されます。 与えられた数値{0}は戦利品{1}の生成範囲{2}内にありません。
29 log_loot_data_add log_loot_data_quantity 生成战利品{0} 有{0}个战利品数据被返回。 Add loot {0} {0} loot data was returned. 戦利品{0}を生成する {0}個の戦利品データが返されます。
75 log_pickable_picked_up log_float_label_instantiate_failed 可拾捡物被捡起了,那么不显示标签。 浮动标签实例化失败。 If the pickable item is picked up, the label is not displayed. Float label instantiation failed. でも、拾得物が拾い上げられたら、ラベルは表示されません。 フロートラベルのインスタンス化に失敗しました。
76 log_pickable_picked_up 可拾捡物被捡起了,那么不显示标签。 If the pickable item is picked up, the label is not displayed. でも、拾得物が拾い上げられたら、ラベルは表示されません。
77 log_start_uploading 开始上传{0}条日志。 Start uploading {0} logs. {0}個のログをアップロードを開始します。
78 log_upload_successful 上传成功,已上传{0}条日志,剩余{1}条日志待上传。 Upload successful, {0} logs uploaded, {1} logs remaining. アップロードが成功しました、{0}個のログがアップロードされ、{1}個のログが残っています。
79 log_upload_failed 上传失败,错误代码:{0},剩余{1}条日志待上传。 Upload failed, error code: {0}, {1} logs remaining. アップロードに失敗しました、エラーコード:{0}、{1}個のログが残っています。
80 log_upload_status 已记录{0}条日志,上传阈值为{1}。 {0} logs recorded, upload threshold is {1}. {0}個のログが記録され、アップロード閾値は{1}です。
81
82

82
scripts/AppConfig.cs Normal file
View File

@ -0,0 +1,82 @@
using ColdMint.scripts.debug;
using ColdMint.scripts.openObserve;
using ColdMint.scripts.serialization;
using Godot;
namespace ColdMint.scripts;
public class AppConfig
{
/// <summary>
/// <para>Load configuration from file</para>
/// <para>从文件加载配置</para>
/// </summary>
public static AppConfigData? LoadFromFile()
{
var appConfigExists = FileAccess.FileExists(Config.AppConfigPath);
if (!appConfigExists)
{
LogCat.LogWarning("appConfig_not_exist");
return null;
}
var appConfigFileAccess = FileAccess.Open(Config.AppConfigPath, FileAccess.ModeFlags.Read);
var yamlData = appConfigFileAccess.GetAsText();
appConfigFileAccess.Close();
return YamlSerialization.Deserialize<AppConfigData>(yamlData);
}
/// <summary>
/// <para>ApplyAppConfig</para>
/// <para>应用配置</para>
/// </summary>
/// <param name="appConfigData"></param>
public static void ApplyAppConfig(AppConfigData appConfigData)
{
if (appConfigData.OpenObserve != null)
{
LogCollector.UpdateHttpClient(appConfigData.OpenObserve);
}
}
}
public class AppConfigData
{
/// <summary>
/// <para>OpenObserve configuration information</para>
/// <para>OpenObserve的配置信息</para>
/// </summary>
public OpenObserve? OpenObserve { get; set; }
}
/// <summary>
/// <para>OpenObserve Configuration information</para>
/// <para>OpenObserve配置信息</para>
/// </summary>
public class OpenObserve
{
/// <summary>
/// <para>server address</para>
/// <para>服务器地址</para>
/// </summary>
public string? Address { get; set; }
/// <summary>
/// <para>Access Token</para>
/// <para>访问密匙</para>
/// </summary>
public string? AccessToken { get; set; }
/// <summary>
/// <para>Organization ID</para>
/// <para>组织ID</para>
/// </summary>
public string? OrgId { get; set; }
/// <summary>
/// <para>Stream Name</para>
/// <para>流名称</para>
/// </summary>
public string? StreamName { get; set; }
}

View File

@ -85,6 +85,12 @@ public static class Config
public const string Aborigines = "Aborigines"; public const string Aborigines = "Aborigines";
} }
/// <summary>
/// <para>Path of the App configuration file</para>
/// <para>App配置文件路径</para>
/// </summary>
public const string AppConfigPath = "res://AppConfig.yaml";
/// <summary> /// <summary>
/// <para>The percentage of speed reduced after a thrown item hits an enemy</para> /// <para>The percentage of speed reduced after a thrown item hits an enemy</para>
/// <para>抛出的物品击中敌人后减少的速度百分比</para> /// <para>抛出的物品击中敌人后减少的速度百分比</para>

View File

@ -45,7 +45,7 @@ public partial class BubbleMarker : Marker2D
{ {
if (!_bubbleDictionary.TryGetValue(id, out var value)) if (!_bubbleDictionary.TryGetValue(id, out var value))
{ {
LogCat.LogErrorWithFormat("bubble_not_found", LogCat.LogLabel.BubbleMarker, id); LogCat.LogErrorWithFormat("bubble_not_found", LogCat.LogLabel.BubbleMarker, LogCat.UploadFormat,id);
return; return;
} }
@ -60,7 +60,7 @@ public partial class BubbleMarker : Marker2D
{ {
if (!_bubbleDictionary.TryGetValue(id, out var value)) if (!_bubbleDictionary.TryGetValue(id, out var value))
{ {
LogCat.LogErrorWithFormat("bubble_not_found", LogCat.LogLabel.BubbleMarker, id); LogCat.LogErrorWithFormat("bubble_not_found", LogCat.LogLabel.BubbleMarker, LogCat.UploadFormat,id);
return; return;
} }

View File

@ -40,7 +40,7 @@ public static class CampManager
if (camp.Id != Config.CampId.Default) return false; if (camp.Id != Config.CampId.Default) return false;
_defaultCamp = camp; _defaultCamp = camp;
AddCamp(camp); AddCamp(camp);
LogCat.LogWithFormat("set_default_camp", label: LogCat.LogLabel.CampManager, camp.Id); LogCat.LogWithFormat("set_default_camp", label: LogCat.LogLabel.CampManager, LogCat.UploadFormat, camp.Id);
return true; return true;
} }

View File

@ -585,12 +585,12 @@ public partial class CharacterTemplate : CharacterBody2D
if (damageTemplate.Attacker is CharacterTemplate characterTemplate && if (damageTemplate.Attacker is CharacterTemplate characterTemplate &&
!string.IsNullOrEmpty(characterTemplate.CharacterName)) !string.IsNullOrEmpty(characterTemplate.CharacterName))
{ {
LogCat.LogWithFormat("death_info", LogCat.LogLabel.Default, CharacterName, LogCat.LogWithFormat("death_info", LogCat.LogLabel.Default, LogCat.UploadFormat,CharacterName,
characterTemplate.CharacterName); characterTemplate.CharacterName);
} }
else else
{ {
LogCat.LogWithFormat("death_info", LogCat.LogLabel.Default, CharacterName, LogCat.LogWithFormat("death_info", LogCat.LogLabel.Default, LogCat.UploadFormat,CharacterName,
damageTemplate.Attacker.Name); damageTemplate.Attacker.Name);
} }
} }

View File

@ -48,7 +48,7 @@ public partial class Player : CharacterTemplate
{ {
base._Ready(); base._Ready();
CharacterName = TranslationServerUtils.Translate("default_player_name"); CharacterName = TranslationServerUtils.Translate("default_player_name");
LogCat.LogWithFormat("player_spawn_debug", LogCat.LogLabel.Default, ReadOnlyCharacterName, LogCat.LogWithFormat("player_spawn_debug", LogCat.LogLabel.Default, LogCat.UploadFormat,ReadOnlyCharacterName,
GlobalPosition); GlobalPosition);
var floatLabelPackedScene = GD.Load<PackedScene>("res://prefab/ui/FloatLabel.tscn"); var floatLabelPackedScene = GD.Load<PackedScene>("res://prefab/ui/FloatLabel.tscn");
//Initializes the float label. //Initializes the float label.

View File

@ -1,6 +1,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Text; using System.Text;
using ColdMint.scripts.openObserve;
using ColdMint.scripts.utils; using ColdMint.scripts.utils;
using Godot; using Godot;
@ -27,19 +28,19 @@ public static class LogCat
/// <para>阵营管理器</para> /// <para>阵营管理器</para>
/// </summary> /// </summary>
public const string CampManager = "CampManager"; public const string CampManager = "CampManager";
/// <summary> /// <summary>
/// <para>State context</para> /// <para>State context</para>
/// <para>状态上下文</para> /// <para>状态上下文</para>
/// </summary> /// </summary>
public const string StateContext = "StateContext"; public const string StateContext = "StateContext";
/// <summary> /// <summary>
/// <para>StateMachineTemplate</para> /// <para>StateMachineTemplate</para>
/// <para>状态机模板</para> /// <para>状态机模板</para>
/// </summary> /// </summary>
public const string StateMachineTemplate = "StateMachineTemplate"; public const string StateMachineTemplate = "StateMachineTemplate";
/// <summary> /// <summary>
/// <para>Pursuit enemy processor</para> /// <para>Pursuit enemy processor</para>
/// <para>追击敌人处理器</para> /// <para>追击敌人处理器</para>
@ -50,7 +51,13 @@ public static class LogCat
/// <para>BubbleMarker</para> /// <para>BubbleMarker</para>
/// <para>气泡标记</para> /// <para>气泡标记</para>
/// </summary> /// </summary>
public static string BubbleMarker = "BubbleMarker"; public const string BubbleMarker = "BubbleMarker";
/// <summary>
/// <para>LogCollector</para>
/// <para>日志收集器</para>
/// </summary>
public const string LogCollector = "LogCollector";
} }
@ -94,6 +101,12 @@ public static class LogCat
set => _minLogLevel = value; set => _minLogLevel = value;
} }
/// <summary>
/// <para>Whether to upload logs that need to be formatted by default</para>
/// <para>是否默认上传需要格式化的日志</para>
/// </summary>
public static bool UploadFormat { get; set; } = true;
private static readonly StringBuilder StringBuilder = new StringBuilder(); private static readonly StringBuilder StringBuilder = new StringBuilder();
/// <summary> /// <summary>
@ -194,7 +207,14 @@ public static class LogCat
/// </param> /// </param>
/// <param name="label"> /// <param name="label">
/// </param> /// </param>
public static void Log(string message, string label = LogLabel.Default) /// <param name="upload">
/// </param>
public static void Log(string message, string label = LogLabel.Default, bool upload = true)
{
PrintLog(InfoLogLevel, HandleMessage(InfoLogLevel, message, label).ToString(), label, upload);
}
private static void PrintLog(int level, string concreteLog, string label, bool upload)
{ {
if (!IsEnabledLogLabel(label)) if (!IsEnabledLogLabel(label))
{ {
@ -206,7 +226,18 @@ public static class LogCat
return; return;
} }
GD.Print(HandleMessage(InfoLogLevel, message, label)); if (LogCollector.CanUploadLog && upload)
{
var logData = new LogData
{
Level = level,
Message = concreteLog,
AppId = "none"
};
LogCollector.Push(logData);
}
GD.Print(concreteLog);
} }
/// <summary> /// <summary>
@ -220,80 +251,34 @@ public static class LogCat
/// <para>这个消息支持本地化输出假设已存在翻译keyHello = 你好传入Hello则会输出你好。</para> /// <para>这个消息支持本地化输出假设已存在翻译keyHello = 你好传入Hello则会输出你好。</para>
/// </param> /// </param>
/// <param name="label"></param> /// <param name="label"></param>
public static void LogError(string message, string label = LogLabel.Default) /// <param name="upload"></param>
public static void LogError(string message, string label = LogLabel.Default, bool upload = true)
{ {
if (!IsEnabledLogLabel(label)) PrintLog(ErrorLogLevel, HandleMessage(ErrorLogLevel, message, label).ToString(), label, upload);
{
return;
}
if (_minLogLevel > ErrorLogLevel)
{
return;
}
GD.PrintErr(HandleMessage(ErrorLogLevel, message, label));
} }
public static void LogWarning(string message, string label = LogLabel.Default) public static void LogWarning(string message, string label = LogLabel.Default, bool upload = true)
{ {
if (!IsEnabledLogLabel(label)) PrintLog(WarningLogLevel, HandleMessage(WarningLogLevel, message, label).ToString(), label, upload);
{
return;
}
if (_minLogLevel > WarningLogLevel)
{
return;
}
GD.Print(HandleMessage(WarningLogLevel, message, label));
} }
public static void LogErrorWithFormat(string message, string label, params object?[] args) public static void LogErrorWithFormat(string message, string label, bool upload, params object?[] args)
{ {
if (!IsEnabledLogLabel(label)) PrintLog(WarningLogLevel, string.Format(HandleMessage(ErrorLogLevel, message, label).ToString(), args), label,
{ upload);
return;
}
if (_minLogLevel > ErrorLogLevel)
{
return;
}
GD.PrintErr(string.Format(HandleMessage(ErrorLogLevel, message, label).ToString(), args));
} }
public static void LogWithFormat(string message, string label, params object?[] args) public static void LogWithFormat(string message, string label, bool upload, params object?[] args)
{ {
if (!IsEnabledLogLabel(label)) PrintLog(InfoLogLevel, string.Format(HandleMessage(InfoLogLevel, message, label).ToString(), args), label,
{ upload);
return;
}
if (_minLogLevel > InfoLogLevel)
{
return;
}
GD.Print(string.Format(HandleMessage(InfoLogLevel, message, label).ToString(), args));
} }
public static void LogWarningWithFormat(string message, string label, params object?[] args) public static void LogWarningWithFormat(string message, bool upload, string label, params object?[] args)
{ {
if (!IsEnabledLogLabel(label)) PrintLog(WarningLogLevel, string.Format(HandleMessage(WarningLogLevel, message, label).ToString(), args), label,
{ upload);
return;
}
if (_minLogLevel > InfoLogLevel)
{
return;
}
GD.Print(string.Format(HandleMessage(WarningLogLevel, message, label).ToString(), args));
} }
/// <summary> /// <summary>
@ -311,6 +296,7 @@ public static class LogCat
//Log an exception here or send it to the server. //Log an exception here or send it to the server.
//请在这里记录异常或将异常发送至服务器。 //请在这里记录异常或将异常发送至服务器。
GD.PrintErr(HandleMessage(ErrorLogLevel, e.Message, label).Append('\n').Append(e.StackTrace)); PrintLog(ErrorLogLevel,
HandleMessage(ErrorLogLevel, e.Message, label).Append('\n').Append(e.StackTrace).ToString(), label, true);
} }
} }

View File

@ -36,7 +36,7 @@ public static class ItemTypeRegister
var error = DirAccess.GetOpenError(); var error = DirAccess.GetOpenError();
if (error is not Error.Ok) if (error is not Error.Ok)
{ {
LogCat.LogError("error_when_open_item_regs_dir",error.ToString()); LogCat.LogError("error_when_open_item_regs_dir", error.ToString());
} }
//找到文件 //找到文件
@ -44,16 +44,16 @@ public static class ItemTypeRegister
var files = itemRegsDir.GetFiles(); var files = itemRegsDir.GetFiles();
if (files == null) if (files == null)
{ {
LogCat.LogWithFormat("found_files", LogCat.LogLabel.Default, 0); LogCat.LogWithFormat("found_files", LogCat.LogLabel.Default, LogCat.UploadFormat, 0);
return; return;
} }
LogCat.LogWithFormat("found_files", LogCat.LogLabel.Default, files.Length); LogCat.LogWithFormat("found_files", LogCat.LogLabel.Default, LogCat.UploadFormat, files.Length);
//将文件解析为项目类型信息 //将文件解析为项目类型信息
//parse files to item type infos //parse files to item type infos
IEnumerable<ItemTypeInfo> typeInfos = IEnumerable<ItemTypeInfo> typeInfos =
files.SelectMany(file => ParseFile($"{itemRegsDirPath}/{file}")).ToList(); files.SelectMany(file => ParseFile($"{itemRegsDirPath}/{file}")).ToList();
LogCat.LogWithFormat("found_item_types", LogCat.LogLabel.Default, typeInfos.Count()); LogCat.LogWithFormat("found_item_types", LogCat.LogLabel.Default, LogCat.UploadFormat, typeInfos.Count());
//遍历类型信息并注册它们。 //遍历类型信息并注册它们。
//traverse type infos and register them. //traverse type infos and register them.
@ -120,7 +120,8 @@ public static class ItemTypeRegister
}, },
icon, typeInfo.MaxStackValue); icon, typeInfo.MaxStackValue);
var succeed = ItemTypeManager.Register(itemType); var succeed = ItemTypeManager.Register(itemType);
LogCat.LogWithFormat("register_item", label: LogCat.LogLabel.Default, itemType.Id, succeed); LogCat.LogWithFormat("register_item", label: LogCat.LogLabel.Default, LogCat.UploadFormat, itemType.Id,
succeed);
} }
//Use for yaml deserialization //Use for yaml deserialization
@ -151,7 +152,8 @@ public static class ItemTypeRegister
var ss = s.Split(','); var ss = s.Split(',');
if (ss.Length != 2) if (ss.Length != 2)
{ {
LogCat.LogErrorWithFormat("wrong_custom_arg", LogCat.LogLabel.Default, "Vector2", s); LogCat.LogErrorWithFormat("wrong_custom_arg", LogCat.LogLabel.Default, LogCat.UploadFormat, "Vector2",
s);
return Vector2.Zero; return Vector2.Zero;
} }

View File

@ -20,148 +20,154 @@ namespace ColdMint.scripts.loader.uiLoader;
/// </summary> /// </summary>
public partial class MainMenuLoader : UiLoaderTemplate public partial class MainMenuLoader : UiLoaderTemplate
{ {
private Button? _startGameButton; private Button? _startGameButton;
private Label? _copyrightLabel; private Label? _copyrightLabel;
private StringBuilder? _copyrightBuilder; private StringBuilder? _copyrightBuilder;
private PackedScene? _gameScene; private PackedScene? _gameScene;
private PackedScene? _contributor; private PackedScene? _contributor;
private PackedScene? _levelGraphEditor; private PackedScene? _levelGraphEditor;
private Label? _sloganLabel; private Label? _sloganLabel;
private Label? _versionLabel; private Label? _versionLabel;
private Button? _levelGraphEditorButton; private Button? _levelGraphEditorButton;
private LinkButton? _contributorButton; private LinkButton? _contributorButton;
public override void InitializeData() public override void InitializeData()
{ {
if (Config.IsDebug()) AppConfigData? appConfigData = AppConfig.LoadFromFile();
{ if (appConfigData != null)
//Set the minimum log level to Info in debug mode.(Print all logs) {
//在调试模式下将最小日志等级设置为Info。打印全部日志 AppConfig.ApplyAppConfig(appConfigData);
LogCat.MinLogLevel = LogCat.InfoLogLevel; }
}
else
{
//Disable all logs in the release version.
//在发行版禁用所有日志。
LogCat.MinLogLevel = LogCat.DisableAllLogLevel;
}
ContributorDataManager.RegisterAllContributorData(); if (Config.IsDebug())
DeathInfoGenerator.RegisterDeathInfoHandler(new SelfDeathInfoHandler()); {
MapGenerator.RegisterRoomInjectionProcessor(new ChanceRoomInjectionProcessor()); //Set the minimum log level to Info in debug mode.(Print all logs)
MapGenerator.RegisterRoomInjectionProcessor(new TimeIntervalRoomInjectorProcessor()); //在调试模式下将最小日志等级设置为Info。打印全部日志
//Register the corresponding encoding provider to solve the problem of garbled Chinese path of the compressed package LogCat.MinLogLevel = LogCat.InfoLogLevel;
//注册对应的编码提供程序,解决压缩包中文路径乱码问题 }
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance); else
//创建游戏数据文件夹 {
var dataPath = Config.GetGameDataDirectory(); //Disable all logs in the release version.
if (!Directory.Exists(dataPath)) //在发行版禁用所有日志。
{ LogCat.MinLogLevel = LogCat.DisableAllLogLevel;
Directory.CreateDirectory(dataPath); }
}
ContributorDataManager.RegisterAllContributorData();
DeathInfoGenerator.RegisterDeathInfoHandler(new SelfDeathInfoHandler());
MapGenerator.RegisterRoomInjectionProcessor(new ChanceRoomInjectionProcessor());
MapGenerator.RegisterRoomInjectionProcessor(new TimeIntervalRoomInjectorProcessor());
//Register the corresponding encoding provider to solve the problem of garbled Chinese path of the compressed package
//注册对应的编码提供程序,解决压缩包中文路径乱码问题
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
//创建游戏数据文件夹
var dataPath = Config.GetGameDataDirectory();
if (!Directory.Exists(dataPath))
{
Directory.CreateDirectory(dataPath);
}
//Registered camp //Registered camp
//注册阵营 //注册阵营
var defaultCamp = new Camp(Config.CampId.Default) var defaultCamp = new Camp(Config.CampId.Default)
{ {
FriendInjury = true FriendInjury = true
}; };
CampManager.SetDefaultCamp(defaultCamp); CampManager.SetDefaultCamp(defaultCamp);
var mazoku = new Camp(Config.CampId.Mazoku); var mazoku = new Camp(Config.CampId.Mazoku);
CampManager.AddCamp(mazoku); CampManager.AddCamp(mazoku);
var aborigines = new Camp(Config.CampId.Aborigines); var aborigines = new Camp(Config.CampId.Aborigines);
CampManager.AddCamp(aborigines); CampManager.AddCamp(aborigines);
_gameScene = GD.Load<PackedScene>("res://scenes/game.tscn"); _gameScene = GD.Load<PackedScene>("res://scenes/game.tscn");
_contributor = GD.Load<PackedScene>("res://scenes/contributor.tscn"); _contributor = GD.Load<PackedScene>("res://scenes/contributor.tscn");
_levelGraphEditor = GD.Load<PackedScene>("res://scenes/levelGraphEditor.tscn"); _levelGraphEditor = GD.Load<PackedScene>("res://scenes/levelGraphEditor.tscn");
//Register ItemTypes from file //Register ItemTypes from file
//从文件注册物品类型 //从文件注册物品类型
ItemTypeRegister.RegisterFromFile(); ItemTypeRegister.RegisterFromFile();
//Hardcoded ItemTypes Register //Hardcoded ItemTypes Register
//硬编码注册物品类型 //硬编码注册物品类型
ItemTypeRegister.StaticRegister(); ItemTypeRegister.StaticRegister();
//静态注册掉落表 //静态注册掉落表
LootRegister.StaticRegister(); LootRegister.StaticRegister();
} }
public override void InitializeUi() public override void InitializeUi()
{ {
_contributorButton = GetNode<LinkButton>("VBoxContainer2/ContributorButton"); _contributorButton = GetNode<LinkButton>("VBoxContainer2/ContributorButton");
_startGameButton = GetNode<Button>("StartGameButton"); _startGameButton = GetNode<Button>("StartGameButton");
_levelGraphEditorButton = GetNode<Button>("levelGraphEditorButton"); _levelGraphEditorButton = GetNode<Button>("levelGraphEditorButton");
//The level map editor is only available in debug mode. //The level map editor is only available in debug mode.
//关卡图编辑器仅在调试模式可用。 //关卡图编辑器仅在调试模式可用。
_levelGraphEditorButton.Visible = Config.IsDebug(); _levelGraphEditorButton.Visible = Config.IsDebug();
_startGameButton.GrabFocus(); _startGameButton.GrabFocus();
_versionLabel = GetNode<Label>("VBoxContainer2/VersionLabel"); _versionLabel = GetNode<Label>("VBoxContainer2/VersionLabel");
//Generative copyright //Generative copyright
//生成版权 //生成版权
_copyrightLabel = GetNode<Label>("VBoxContainer/CopyrightLabel"); _copyrightLabel = GetNode<Label>("VBoxContainer/CopyrightLabel");
_sloganLabel = GetNode<Label>("CenterContainer2/SloganLabel"); _sloganLabel = GetNode<Label>("CenterContainer2/SloganLabel");
_copyrightBuilder = new StringBuilder(); _copyrightBuilder = new StringBuilder();
_copyrightBuilder.Append('\u00a9'); _copyrightBuilder.Append('\u00a9');
var currentYear = DateTime.Now.Year; var currentYear = DateTime.Now.Year;
_copyrightBuilder.Append(Config.CreationYear); _copyrightBuilder.Append(Config.CreationYear);
if (currentYear != Config.CreationYear) if (currentYear != Config.CreationYear)
{ {
_copyrightBuilder.Append('-'); _copyrightBuilder.Append('-');
_copyrightBuilder.Append(currentYear); _copyrightBuilder.Append(currentYear);
} }
_copyrightBuilder.Append(' '); _copyrightBuilder.Append(' ');
_copyrightBuilder.Append(Config.CompanyName); _copyrightBuilder.Append(Config.CompanyName);
_copyrightBuilder.Append(" all rights reserved."); _copyrightBuilder.Append(" all rights reserved.");
_copyrightLabel.Text = _copyrightBuilder.ToString(); _copyrightLabel.Text = _copyrightBuilder.ToString();
_versionLabel.Text = "ver." + Config.GetVersion(); _versionLabel.Text = "ver." + Config.GetVersion();
_sloganLabel.Text = SloganProvider.GetSlogan(); _sloganLabel.Text = SloganProvider.GetSlogan();
_contributorButton.Text = _contributorButton.Text =
TranslationServerUtils.TranslateWithFormat("ui_contributor_tips", TranslationServerUtils.TranslateWithFormat("ui_contributor_tips",
ContributorDataManager.GetContributorTotals()); ContributorDataManager.GetContributorTotals());
} }
public override void LoadUiActions() public override void LoadUiActions()
{ {
if (_startGameButton != null) if (_startGameButton != null)
{ {
_startGameButton.Pressed += () => _startGameButton.Pressed += () =>
{ {
if (_gameScene == null) if (_gameScene == null)
{ {
return; return;
} }
GetTree().ChangeSceneToPacked(_gameScene); GetTree().ChangeSceneToPacked(_gameScene);
}; };
} }
if (_contributorButton != null) if (_contributorButton != null)
{ {
_contributorButton.Pressed += () => _contributorButton.Pressed += () =>
{ {
if (_contributor == null) if (_contributor == null)
{ {
return; return;
} }
GetTree().ChangeSceneToPacked(_contributor); GetTree().ChangeSceneToPacked(_contributor);
}; };
} }
if (_levelGraphEditorButton != null) if (_levelGraphEditorButton != null)
{ {
_levelGraphEditorButton.Pressed += () => _levelGraphEditorButton.Pressed += () =>
{ {
LogCat.Log("level_graph_editor"); LogCat.Log("level_graph_editor");
if (_levelGraphEditor == null) if (_levelGraphEditor == null)
{ {
return; return;
} }
GetTree().ChangeSceneToPacked(_levelGraphEditor); GetTree().ChangeSceneToPacked(_levelGraphEditor);
}; };
} }
} }
} }

View File

@ -25,7 +25,7 @@ public readonly struct LootList(string id, IList<LootGroup> groups)
{ {
if (Groups is []) if (Groups is [])
{ {
LogCat.LogWithFormat("loot_list_has_no_entries", LogCat.LogLabel.Default, Id); LogCat.LogWithFormat("loot_list_has_no_entries", LogCat.LogLabel.Default, LogCat.UploadFormat, Id);
return []; return [];
} }
@ -41,10 +41,10 @@ public readonly struct LootList(string id, IList<LootGroup> groups)
//我们为每个战利品条目生成一个战利品数据。 //我们为每个战利品条目生成一个战利品数据。
var datum = group.GenerateLootData(); var datum = group.GenerateLootData();
lootDataList.Add(datum); lootDataList.Add(datum);
LogCat.LogWithFormat("loot_data_add", LogCat.LogLabel.Default, datum); LogCat.LogWithFormat("loot_data_add", LogCat.LogLabel.Default, LogCat.UploadFormat,datum);
} }
LogCat.LogWithFormat("loot_data_quantity", LogCat.LogLabel.Default, lootDataList.Count); LogCat.LogWithFormat("loot_data_quantity", LogCat.LogLabel.Default, LogCat.UploadFormat,lootDataList.Count);
return lootDataList.ToArray(); return lootDataList.ToArray();
} }
} }

View File

@ -241,7 +241,7 @@ public static class MapGenerator
//If the room injection processor cannot be found, a print error occurs. //If the room injection processor cannot be found, a print error occurs.
//如果找不到房间注入处理器,那么打印错误。 //如果找不到房间注入处理器,那么打印错误。
LogCat.LogErrorWithFormat("room_injection_processor_does_not_exist", LogCat.LogErrorWithFormat("room_injection_processor_does_not_exist",
LogCat.LogLabel.Default, injectionProcessorData.Id); LogCat.LogLabel.Default, LogCat.UploadFormat,injectionProcessorData.Id);
continue; continue;
} }
@ -278,7 +278,7 @@ public static class MapGenerator
if (roomPlacementData == null) if (roomPlacementData == null)
{ {
LogCat.LogWithFormat("failed_to_calculate_the_room_location", LogCat.LogLabel.Default, LogCat.LogWithFormat("failed_to_calculate_the_room_location", LogCat.LogLabel.Default,
roomNodeData.Id); LogCat.UploadFormat,roomNodeData.Id);
continue; continue;
} }
@ -324,18 +324,18 @@ public static class MapGenerator
if (dictionary.ContainsKey(roomNodeDataId)) if (dictionary.ContainsKey(roomNodeDataId))
{ {
LogCat.LogWithFormat("place_existing_rooms", LogCat.LogLabel.Default, roomNodeDataId); LogCat.LogWithFormat("place_existing_rooms", LogCat.LogLabel.Default, LogCat.UploadFormat,roomNodeDataId);
return false; return false;
} }
if (!await _roomPlacementStrategy.PlaceRoom(_mapRoot, roomPlacementData)) if (!await _roomPlacementStrategy.PlaceRoom(_mapRoot, roomPlacementData))
{ {
LogCat.LogWarningWithFormat("room_placement_failed", LogCat.LogLabel.Default, roomNodeDataId); LogCat.LogWarningWithFormat("room_placement_failed", LogCat.UploadFormat,LogCat.LogLabel.Default, roomNodeDataId);
return false; return false;
} }
dictionary.Add(roomNodeDataId, roomPlacementData.Room); dictionary.Add(roomNodeDataId, roomPlacementData.Room);
LogCat.LogWithFormat("room_placement_information", LogCat.LogLabel.Default, roomNodeDataId, LogCat.LogWithFormat("room_placement_information", LogCat.LogLabel.Default, LogCat.UploadFormat,roomNodeDataId,
roomPlacementData.Position.ToString()); roomPlacementData.Position.ToString());
return true; return true;
} }

View File

@ -36,7 +36,7 @@ public class Room
{ {
if (_rootNode != null) if (_rootNode != null)
{ {
LogCat.LogWithFormat("enter_the_room_debug", LogCat.LogLabel.Default, node.Name, _rootNode.Name); LogCat.LogWithFormat("enter_the_room_debug", LogCat.LogLabel.Default, LogCat.UploadFormat,node.Name, _rootNode.Name);
} }
if (string.IsNullOrEmpty(EnterRoomEventHandlerId)) if (string.IsNullOrEmpty(EnterRoomEventHandlerId))
@ -57,7 +57,7 @@ public class Room
{ {
if (_rootNode != null) if (_rootNode != null)
{ {
LogCat.LogWithFormat("exit_the_room_debug", LogCat.LogLabel.Default, node.Name, _rootNode.Name); LogCat.LogWithFormat("exit_the_room_debug", LogCat.LogLabel.Default, LogCat.UploadFormat,node.Name, _rootNode.Name);
} }
if (string.IsNullOrEmpty(ExitRoomEventHandlerId)) if (string.IsNullOrEmpty(ExitRoomEventHandlerId))

View File

@ -0,0 +1,139 @@
using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Http.Json;
using System.Threading.Tasks;
using ColdMint.scripts.debug;
using HttpClient = System.Net.Http.HttpClient;
namespace ColdMint.scripts.openObserve;
/// <summary>
/// <para>LogCollector</para>
/// <para>日志收集器</para>
/// </summary>
public static class LogCollector
{
private static readonly List<LogData> LogDataList = [];
/// <summary>
/// <para>Automatic upload threshold</para>
/// <para>自动上传的阈值</para>
/// </summary>
/// <remarks>
///<para>An attempt is made to upload logs when messages reach this number.</para>
///<para>当消息到达此数量后将尝试上传日志。</para>
/// </remarks>
public static int UploadThreshold { get; set; } = 300;
private static bool _lockList = false;
/// <summary>
/// <para>httpClient</para>
/// <para>Http客户</para>
/// </summary>
private static HttpClient? _httpClient;
private static string? _orgId;
private static string? _streamName;
/// <summary>
/// <para>CanUploadLog</para>
/// <para>是否能上传日志</para>
/// </summary>
public static bool CanUploadLog => _httpClient != null;
/// <summary>
/// <para>UpdateHttpClient</para>
/// <para>更新Http客户端</para>
/// </summary>
/// <param name="openObserve"></param>
public static void UpdateHttpClient(OpenObserve openObserve)
{
if (openObserve.Address == null || openObserve.AccessToken == null || openObserve.OrgId == null ||
openObserve.StreamName == null)
{
return;
}
var httpClient = new HttpClient();
httpClient.BaseAddress = new Uri(openObserve.Address);
//Add a Cookie to the request header
//添加Cookie到请求头
var cookie = new Cookie("auth_tokens",
"{\"access_token\":\"Basic " + openObserve.AccessToken + "\",\"refresh_token\":\"\"}");
httpClient.DefaultRequestHeaders.Add("Cookie", cookie.ToString());
_httpClient = httpClient;
_orgId = openObserve.OrgId;
_streamName = openObserve.StreamName;
}
/// <summary>
/// <para>Push log</para>
/// <para>推送日志</para>
/// </summary>
/// <param name="logRequestBean"></param>
private static async Task PostLog(List<LogData> logRequestBean)
{
if (_httpClient == null)
{
return;
}
_lockList = true;
LogCat.LogWithFormat("start_uploading", label: LogCat.LogLabel.LogCollector, false, logRequestBean.Count);
var httpResponseMessage =
await _httpClient.PostAsJsonAsync("/api/" + _orgId + "/" + _streamName + "/_json", logRequestBean);
_lockList = false;
if (httpResponseMessage.IsSuccessStatusCode)
{
LogDataList.RemoveRange(0, logRequestBean.Count);
LogCat.LogWithFormat("upload_successful", label: LogCat.LogLabel.LogCollector, false,
logRequestBean.Count, LogDataList.Count);
if (LogDataList.Count > UploadThreshold)
{
//After the upload succeeds, if the threshold is still met, continue uploading.
//上传成功后,如果依然满足阈值,那么继续上传。
PostLog(LogDataList.GetRange(0, UploadThreshold));
}
}
else
{
LogCat.LogWithFormat("upload_failed", label: LogCat.LogLabel.LogCollector, false,
httpResponseMessage.StatusCode.ToString(), LogDataList.Count);
}
}
public static void Push(LogData logData)
{
LogDataList.Add(logData);
LogCat.LogWithFormat("upload_status", LogCat.LogLabel.LogCollector, false, LogDataList.Count, UploadThreshold);
if (!_lockList && LogDataList.Count > UploadThreshold)
{
//执行上传
PostLog(LogDataList.GetRange(0, UploadThreshold));
}
}
}
public class LogData
{
/// <summary>
/// <para>The AppId of this application</para>
/// <para>此应用的AppId</para>
/// </summary>
public string? AppId { get; set; }
/// <summary>
/// <para>message</para>
/// <para>消息</para>
/// </summary>
public string? Message { get; set; }
/// <summary>
/// <para>level</para>
/// <para>错误等级</para>
/// </summary>
public int Level { get; set; }
}

View File

@ -33,7 +33,7 @@ public class StateContext
return; return;
} }
LogCat.LogWithFormat("state_change", label: LogCat.LogLabel.StateContext, _currentState, value); LogCat.LogWithFormat("state_change", label: LogCat.LogLabel.StateContext, LogCat.UploadFormat,_currentState, value);
OnStateChange?.Invoke(_currentState, value); OnStateChange?.Invoke(_currentState, value);
_previousState = _currentState; _previousState = _currentState;
_currentState = value; _currentState = value;

View File

@ -69,7 +69,7 @@ public abstract class StateMachineTemplate : IStateMachine
else else
{ {
LogCat.LogErrorWithFormat("state_processor_not_found", label: LogCat.LogLabel.StateMachineTemplate, LogCat.LogErrorWithFormat("state_processor_not_found", label: LogCat.LogLabel.StateMachineTemplate,
newState); LogCat.UploadFormat,newState);
} }
} }

View File

@ -78,7 +78,7 @@ public class PatrolStateProcessor : StateProcessorTemplate
_originPosition = aiCharacter.GlobalPosition; _originPosition = aiCharacter.GlobalPosition;
LogCat.LogWithFormat("patrol_origin_position", LogCat.LogLabel.PatrolStateProcessor, LogCat.LogWithFormat("patrol_origin_position", LogCat.LogLabel.PatrolStateProcessor,
_originPosition); LogCat.UploadFormat,_originPosition);
} }
var point = _originPosition + Points[_index]; var point = _originPosition + Points[_index];
@ -87,7 +87,7 @@ public class PatrolStateProcessor : StateProcessorTemplate
{ {
//No need to actually come to the patrol point, we just need a distance to get close. //No need to actually come to the patrol point, we just need a distance to get close.
//无需真正的来到巡逻点,我们只需要一个距离接近了就可以了。 //无需真正的来到巡逻点,我们只需要一个距离接近了就可以了。
LogCat.LogWithFormat("patrol_arrival_point", LogCat.LogLabel.PatrolStateProcessor, point); LogCat.LogWithFormat("patrol_arrival_point", LogCat.LogLabel.PatrolStateProcessor, LogCat.UploadFormat,point);
_index++; _index++;
if (_index >= Points.Length) if (_index >= Points.Length)
{ {
@ -96,7 +96,7 @@ public class PatrolStateProcessor : StateProcessorTemplate
} }
else else
{ {
LogCat.LogWithFormat("patrol_to_next_point", label: LogCat.LogLabel.PatrolStateProcessor, point, LogCat.LogWithFormat("patrol_to_next_point", label: LogCat.LogLabel.PatrolStateProcessor, LogCat.UploadFormat,point,
aiCharacter.GlobalPosition, Points[_index], aiCharacter.GlobalPosition, Points[_index],
distance); distance);
aiCharacter.SetTargetPosition(point.Value); aiCharacter.SetTargetPosition(point.Value);

View File

@ -279,7 +279,8 @@ public static class NodeUtils
if (node is T result) return result; if (node is T result) return result;
// If the transformation fails, release the created node // If the transformation fails, release the created node
//如果转型失败,释放所创建的节点 //如果转型失败,释放所创建的节点
LogCat.LogWarningWithFormat("warning_node_cannot_cast_to", LogCat.LogLabel.Default, node, nameof(T)); LogCat.LogWarningWithFormat("warning_node_cannot_cast_to", LogCat.UploadFormat, LogCat.LogLabel.Default, node,
nameof(T));
node.QueueFree(); node.QueueFree();
return null; return null;
} }

View File

@ -33,7 +33,7 @@ public static class TimeUtils
var compNum1 = DateTime.Compare(dateTime, dtStartTime); var compNum1 = DateTime.Compare(dateTime, dtStartTime);
var compNum2 = DateTime.Compare(dateTime, dtEndTime); var compNum2 = DateTime.Compare(dateTime, dtEndTime);
var result = compNum1 >= 0 && compNum2 <= 0; var result = compNum1 >= 0 && compNum2 <= 0;
LogCat.LogWithFormat("time_range_debug", LogCat.LogLabel.Default, dateTime, dtStartTime, dtEndTime, LogCat.LogWithFormat("time_range_debug", LogCat.LogLabel.Default, LogCat.UploadFormat,dateTime, dtStartTime, dtEndTime,
result); result);
return result; return result;
} }