LubanAssistant添加配置定义加载相关代码

main
walon 2021-10-11 23:06:41 +08:00
parent 8288591827
commit 1e7fb10db2
38 changed files with 5347 additions and 13 deletions

View File

@ -0,0 +1,152 @@

namespace LubanAssistant
{
partial class AssistantTab : Microsoft.Office.Tools.Ribbon.RibbonBase
{
/// <summary>
/// 必需的设计器变量。
/// </summary>
private System.ComponentModel.IContainer components = null;
public AssistantTab()
: base(Globals.Factory.GetRibbonFactory())
{
InitializeComponent();
}
/// <summary>
/// 清理所有正在使用的资源。
/// </summary>
/// <param name="disposing">如果应释放托管资源,为 true否则为 false。</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region 组件设计器生成的代码
/// <summary>
/// 设计器支持所需的方法 - 不要修改
/// 使用代码编辑器修改此方法的内容。
/// </summary>
private void InitializeComponent()
{
this.tab1 = this.Factory.CreateRibbonTab();
this.group3 = this.Factory.CreateRibbonGroup();
this.SetRootFile = this.Factory.CreateRibbonButton();
this.group1 = this.Factory.CreateRibbonGroup();
this.load = this.Factory.CreateRibbonButton();
this.group2 = this.Factory.CreateRibbonGroup();
this.saveAll = this.Factory.CreateRibbonButton();
this.saveSelected = this.Factory.CreateRibbonButton();
this.openFileDialog1 = new System.Windows.Forms.OpenFileDialog();
this.tab1.SuspendLayout();
this.group3.SuspendLayout();
this.group1.SuspendLayout();
this.group2.SuspendLayout();
this.SuspendLayout();
//
// tab1
//
this.tab1.ControlId.ControlIdType = Microsoft.Office.Tools.Ribbon.RibbonControlIdType.Office;
this.tab1.Groups.Add(this.group3);
this.tab1.Groups.Add(this.group1);
this.tab1.Groups.Add(this.group2);
this.tab1.Label = "TabAddIns";
this.tab1.Name = "tab1";
//
// group3
//
this.group3.Items.Add(this.SetRootFile);
this.group3.Name = "group3";
//
// SetRootFile
//
this.SetRootFile.ControlSize = Microsoft.Office.Core.RibbonControlSize.RibbonControlSizeLarge;
this.SetRootFile.Label = "设置Root文件";
this.SetRootFile.Name = "SetRootFile";
this.SetRootFile.ShowImage = true;
this.SetRootFile.Click += new Microsoft.Office.Tools.Ribbon.RibbonControlEventHandler(this.BtnChooseRootFileClick);
//
// group1
//
this.group1.Items.Add(this.load);
this.group1.Name = "group1";
//
// load
//
this.load.ControlSize = Microsoft.Office.Core.RibbonControlSize.RibbonControlSizeLarge;
this.load.Label = "加载数据表";
this.load.Name = "load";
this.load.ShowImage = true;
this.load.Click += new Microsoft.Office.Tools.Ribbon.RibbonControlEventHandler(this.BtnLoadClick);
//
// group2
//
this.group2.Items.Add(this.saveAll);
this.group2.Items.Add(this.saveSelected);
this.group2.Name = "group2";
//
// saveAll
//
this.saveAll.ControlSize = Microsoft.Office.Core.RibbonControlSize.RibbonControlSizeLarge;
this.saveAll.Label = "保存所有";
this.saveAll.Name = "saveAll";
this.saveAll.ShowImage = true;
this.saveAll.Click += new Microsoft.Office.Tools.Ribbon.RibbonControlEventHandler(this.BtnSaveAllClick);
//
// saveSelected
//
this.saveSelected.ControlSize = Microsoft.Office.Core.RibbonControlSize.RibbonControlSizeLarge;
this.saveSelected.Label = "保存选中";
this.saveSelected.Name = "saveSelected";
this.saveSelected.ShowImage = true;
this.saveSelected.Click += new Microsoft.Office.Tools.Ribbon.RibbonControlEventHandler(this.BtnSaveSelectedClick);
//
// openFileDialog1
//
this.openFileDialog1.FileName = "openFileDialog1";
//
// AssistantTab
//
this.Name = "AssistantTab";
this.RibbonType = "Microsoft.Excel.Workbook";
this.Tabs.Add(this.tab1);
this.Load += new Microsoft.Office.Tools.Ribbon.RibbonUIEventHandler(this.AssistantTab_Load);
this.tab1.ResumeLayout(false);
this.tab1.PerformLayout();
this.group3.ResumeLayout(false);
this.group3.PerformLayout();
this.group1.ResumeLayout(false);
this.group1.PerformLayout();
this.group2.ResumeLayout(false);
this.group2.PerformLayout();
this.ResumeLayout(false);
}
#endregion
internal Microsoft.Office.Tools.Ribbon.RibbonTab tab1;
internal Microsoft.Office.Tools.Ribbon.RibbonGroup group1;
internal Microsoft.Office.Tools.Ribbon.RibbonButton load;
internal Microsoft.Office.Tools.Ribbon.RibbonGroup group2;
internal Microsoft.Office.Tools.Ribbon.RibbonButton saveAll;
internal Microsoft.Office.Tools.Ribbon.RibbonGroup group3;
internal Microsoft.Office.Tools.Ribbon.RibbonButton SetRootFile;
internal Microsoft.Office.Tools.Ribbon.RibbonButton saveSelected;
private System.Windows.Forms.OpenFileDialog openFileDialog1;
}
partial class ThisRibbonCollection
{
internal AssistantTab AssistantTab
{
get { return this.GetRibbon<AssistantTab>(); }
}
}
}

View File

@ -0,0 +1,82 @@
using Microsoft.Office.Tools.Ribbon;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace LubanAssistant
{
public partial class AssistantTab
{
private string RootDefineFile
{
get => Properties.Settings.Default.rootDefineFile;
set
{
Properties.Settings.Default.rootDefineFile = value;
Properties.Settings.Default.Save();
}
}
private void AssistantTab_Load(object sender, RibbonUIEventArgs e)
{
}
private bool CheckChooseRootDefineFile()
{
if (string.IsNullOrWhiteSpace(RootDefineFile) || !File.Exists(RootDefineFile))
{
if (TryChooseRootDefineFile(out var rootDefineFile))
{
RootDefineFile = rootDefineFile;
return true;
}
}
return false;
}
private bool TryChooseRootDefineFile(out string rootDefineFile)
{
var dialog = new OpenFileDialog();
dialog.DefaultExt = "xml";
dialog.Filter = "root file (*.xml)|*.xml";
dialog.Title = "Choose Root Xml File";
dialog.CheckFileExists = true;
if (dialog.ShowDialog() == DialogResult.OK)
{
rootDefineFile = dialog.FileName;
return true;
}
rootDefineFile = null;
return false;
}
private void BtnChooseRootFileClick(object sender, RibbonControlEventArgs e)
{
if (TryChooseRootDefineFile(out var rootDefineFile))
{
RootDefineFile = rootDefineFile;
}
}
private void BtnLoadClick(object sender, RibbonControlEventArgs e)
{
if (CheckChooseRootDefineFile())
{
MessageBox.Show("load");
}
}
private void BtnSaveAllClick(object sender, RibbonControlEventArgs e)
{
MessageBox.Show("点击save");
}
private void BtnSaveSelectedClick(object sender, RibbonControlEventArgs e)
{
MessageBox.Show("点击save");
}
}
}

View File

@ -0,0 +1,123 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<metadata name="openFileDialog1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>17, 17</value>
</metadata>
</root>

View File

@ -1,4 +1,5 @@
<Project ToolsVersion="16.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="..\packages\Scriban.4.1.0\build\Scriban.props" Condition="Exists('..\packages\Scriban.4.1.0\build\Scriban.props')" />
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<!--
This section defines project-level properties.
@ -31,6 +32,8 @@
<DefineConstants>VSTO40</DefineConstants>
<BootstrapperEnabled>true</BootstrapperEnabled>
<BootstrapperComponentsLocation>HomeSite</BootstrapperComponentsLocation>
<NuGetPackageImportStamp>
</NuGetPackageImportStamp>
</PropertyGroup>
<ItemGroup>
<BootstrapperPackage Include="Microsoft.VSTORuntime.4.0">
@ -46,6 +49,9 @@
-->
<OfficeApplication>Excel</OfficeApplication>
</PropertyGroup>
<PropertyGroup>
<LangVersion>9.0</LangVersion>
</PropertyGroup>
<!--
This section defines properties that are set when the "Debug" configuration is selected.
@ -68,8 +74,9 @@
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<EnableUnmanagedDebugging>false</EnableUnmanagedDebugging>
<DefineConstants>$(DefineConstants);DEBUG;TRACE</DefineConstants>
<DefineConstants>TRACE;DEBUG;VSTO40,LUBAN_ASSISTANT</DefineConstants>
<WarningLevel>4</WarningLevel>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<!--
This section defines properties that are set when the "Release" configuration is selected.
@ -100,15 +107,66 @@
-->
<ItemGroup>
<Reference Include="Accessibility" />
<Reference Include="CommandLine, Version=2.8.0.0, Culture=neutral, PublicKeyToken=5a870481e358d379, processorArchitecture=MSIL">
<HintPath>..\packages\CommandLineParser.2.8.0\lib\net461\CommandLine.dll</HintPath>
</Reference>
<Reference Include="ExcelDataReader, Version=3.6.0.0, Culture=neutral, PublicKeyToken=93517dbe6a4012fa, processorArchitecture=MSIL">
<HintPath>..\packages\ExcelDataReader.3.6.0\lib\net45\ExcelDataReader.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Bcl.AsyncInterfaces, Version=5.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.Bcl.AsyncInterfaces.5.0.0\lib\net461\Microsoft.Bcl.AsyncInterfaces.dll</HintPath>
</Reference>
<Reference Include="Neo.Lua, Version=5.3.0.0, Culture=neutral, PublicKeyToken=fdb0cd4fe8a6e3b2, processorArchitecture=MSIL">
<HintPath>..\packages\NeoLua.1.3.13\lib\net47\Neo.Lua.dll</HintPath>
</Reference>
<Reference Include="NLog, Version=4.0.0.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c, processorArchitecture=MSIL">
<HintPath>..\packages\NLog.4.7.11\lib\net45\NLog.dll</HintPath>
</Reference>
<Reference Include="Scriban, Version=4.1.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Scriban.4.1.0\lib\netstandard2.0\Scriban.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Buffers, Version=4.0.3.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\packages\System.Buffers.4.5.1\lib\net461\System.Buffers.dll</HintPath>
</Reference>
<Reference Include="System.Configuration" />
<Reference Include="System.Data" />
<Reference Include="System.Drawing" />
<Reference Include="System.IO.Compression" />
<Reference Include="System.Memory, Version=4.0.1.1, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\packages\System.Memory.4.5.4\lib\net461\System.Memory.dll</HintPath>
</Reference>
<Reference Include="System.Numerics" />
<Reference Include="System.Numerics.Vectors, Version=4.1.4.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Numerics.Vectors.4.5.0\lib\net46\System.Numerics.Vectors.dll</HintPath>
</Reference>
<Reference Include="System.Runtime.CompilerServices.Unsafe, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Runtime.CompilerServices.Unsafe.5.0.0\lib\net45\System.Runtime.CompilerServices.Unsafe.dll</HintPath>
</Reference>
<Reference Include="System.Runtime.Serialization" />
<Reference Include="System.ServiceModel" />
<Reference Include="System.Text.Encodings.Web, Version=5.0.0.1, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\packages\System.Text.Encodings.Web.5.0.1\lib\net461\System.Text.Encodings.Web.dll</HintPath>
</Reference>
<Reference Include="System.Text.Json, Version=5.0.0.2, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\packages\System.Text.Json.5.0.2\lib\net461\System.Text.Json.dll</HintPath>
</Reference>
<Reference Include="System.Threading.Tasks.Extensions, Version=4.2.0.1, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\packages\System.Threading.Tasks.Extensions.4.5.4\lib\net461\System.Threading.Tasks.Extensions.dll</HintPath>
</Reference>
<Reference Include="System.Transactions" />
<Reference Include="System.ValueTuple, Version=4.0.3.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\packages\System.ValueTuple.4.5.0\lib\net47\System.ValueTuple.dll</HintPath>
</Reference>
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Xml" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="YamlDotNet, Version=11.0.0.0, Culture=neutral, PublicKeyToken=ec19458f3c15af5e, processorArchitecture=MSIL">
<HintPath>..\packages\YamlDotNet.11.2.1\lib\net45\YamlDotNet.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>
<Reference Include="Microsoft.Office.Tools.v4.0.Framework, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
@ -156,9 +214,309 @@
can be found.
-->
<ItemGroup>
<Compile Include="..\Luban.Common\Source\EErrorCode.cs">
<Link>Source\EErrorCode.cs</Link>
</Compile>
<Compile Include="..\Luban.Common\Source\Utils\FileUtil.cs">
<Link>Source\Utils\FileUtil.cs</Link>
</Compile>
<Compile Include="..\Luban.Common\Source\Utils\LogUtil.cs">
<Link>Source\Utils\LogUtil.cs</Link>
</Compile>
<Compile Include="..\Luban.Common\Source\Utils\TypeUtil.cs">
<Link>Source\Utils\TypeUtil.cs</Link>
</Compile>
<Compile Include="..\Luban.Common\Source\Utils\XmlUtil.cs">
<Link>Source\Utils\XmlUtil.cs</Link>
</Compile>
<Compile Include="..\Luban.Job.Cfg\Source\DataCreators\DataCreateException.cs">
<Link>Source\DataCreators\DataCreateException.cs</Link>
</Compile>
<Compile Include="..\Luban.Job.Cfg\Source\DataCreators\ExcelDataCreator.cs">
<Link>Source\DataCreators\ExcelDataCreator.cs</Link>
</Compile>
<Compile Include="..\Luban.Job.Cfg\Source\DataCreators\ExcelNamedRowDataCreator.cs">
<Link>Source\DataCreators\ExcelNamedRowDataCreator.cs</Link>
</Compile>
<Compile Include="..\Luban.Job.Cfg\Source\DataCreators\JsonDataCreator.cs">
<Link>Source\DataCreators\JsonDataCreator.cs</Link>
</Compile>
<Compile Include="..\Luban.Job.Cfg\Source\DataCreators\MultiRowExcelDataCreator.cs">
<Link>Source\DataCreators\MultiRowExcelDataCreator.cs</Link>
</Compile>
<Compile Include="..\Luban.Job.Cfg\Source\DataCreators\StringDataCreator.cs">
<Link>Source\DataCreators\StringDataCreator.cs</Link>
</Compile>
<Compile Include="..\Luban.Job.Cfg\Source\DataSources\AbstractDataSource.cs">
<Link>Source\DataSources\AbstractDataSource.cs</Link>
</Compile>
<Compile Include="..\Luban.Job.Cfg\Source\DataSources\Excel\ExcelDataSource.cs">
<Link>Source\DataSources\Excel\ExcelDataSource.cs</Link>
</Compile>
<Compile Include="..\Luban.Job.Cfg\Source\DataSources\Excel\ExcelStream.cs">
<Link>Source\DataSources\Excel\ExcelStream.cs</Link>
</Compile>
<Compile Include="..\Luban.Job.Cfg\Source\DataSources\Excel\Sheet.cs">
<Link>Source\DataSources\Excel\Sheet.cs</Link>
</Compile>
<Compile Include="..\Luban.Job.Cfg\Source\DataSources\Json\JsonDataSource.cs">
<Link>Source\DataSources\Json\JsonDataSource.cs</Link>
</Compile>
<Compile Include="..\Luban.Job.Cfg\Source\Datas\DArray.cs">
<Link>Source\Datas\DArray.cs</Link>
</Compile>
<Compile Include="..\Luban.Job.Cfg\Source\Datas\DBean.cs">
<Link>Source\Datas\DBean.cs</Link>
</Compile>
<Compile Include="..\Luban.Job.Cfg\Source\Datas\DBool.cs">
<Link>Source\Datas\DBool.cs</Link>
</Compile>
<Compile Include="..\Luban.Job.Cfg\Source\Datas\DByte.cs">
<Link>Source\Datas\DByte.cs</Link>
</Compile>
<Compile Include="..\Luban.Job.Cfg\Source\Datas\DBytes.cs">
<Link>Source\Datas\DBytes.cs</Link>
</Compile>
<Compile Include="..\Luban.Job.Cfg\Source\Datas\DDateTime.cs">
<Link>Source\Datas\DDateTime.cs</Link>
</Compile>
<Compile Include="..\Luban.Job.Cfg\Source\Datas\DDouble.cs">
<Link>Source\Datas\DDouble.cs</Link>
</Compile>
<Compile Include="..\Luban.Job.Cfg\Source\Datas\DEnum.cs">
<Link>Source\Datas\DEnum.cs</Link>
</Compile>
<Compile Include="..\Luban.Job.Cfg\Source\Datas\DFint.cs">
<Link>Source\Datas\DFint.cs</Link>
</Compile>
<Compile Include="..\Luban.Job.Cfg\Source\Datas\DFloat.cs">
<Link>Source\Datas\DFloat.cs</Link>
</Compile>
<Compile Include="..\Luban.Job.Cfg\Source\Datas\DFlong.cs">
<Link>Source\Datas\DFlong.cs</Link>
</Compile>
<Compile Include="..\Luban.Job.Cfg\Source\Datas\DFshort.cs">
<Link>Source\Datas\DFshort.cs</Link>
</Compile>
<Compile Include="..\Luban.Job.Cfg\Source\Datas\DInt.cs">
<Link>Source\Datas\DInt.cs</Link>
</Compile>
<Compile Include="..\Luban.Job.Cfg\Source\Datas\DList.cs">
<Link>Source\Datas\DList.cs</Link>
</Compile>
<Compile Include="..\Luban.Job.Cfg\Source\Datas\DLong.cs">
<Link>Source\Datas\DLong.cs</Link>
</Compile>
<Compile Include="..\Luban.Job.Cfg\Source\Datas\DMap.cs">
<Link>Source\Datas\DMap.cs</Link>
</Compile>
<Compile Include="..\Luban.Job.Cfg\Source\Datas\DSet.cs">
<Link>Source\Datas\DSet.cs</Link>
</Compile>
<Compile Include="..\Luban.Job.Cfg\Source\Datas\DShort.cs">
<Link>Source\Datas\DShort.cs</Link>
</Compile>
<Compile Include="..\Luban.Job.Cfg\Source\Datas\DString.cs">
<Link>Source\Datas\DString.cs</Link>
</Compile>
<Compile Include="..\Luban.Job.Cfg\Source\Datas\DVector2.cs">
<Link>Source\Datas\DVector2.cs</Link>
</Compile>
<Compile Include="..\Luban.Job.Cfg\Source\Datas\DVector3.cs">
<Link>Source\Datas\DVector3.cs</Link>
</Compile>
<Compile Include="..\Luban.Job.Cfg\Source\Datas\DVector4.cs">
<Link>Source\Datas\DVector4.cs</Link>
</Compile>
<Compile Include="..\Luban.Job.Cfg\Source\Datas\Record.cs">
<Link>Source\Datas\Record.cs</Link>
</Compile>
<Compile Include="..\Luban.Job.Cfg\Source\DataVisitors\IDataActionVisitor.cs">
<Link>Source\DataVisitors\IDataActionVisitor.cs</Link>
</Compile>
<Compile Include="..\Luban.Job.Cfg\Source\DataVisitors\IDataFuncVisitor.cs">
<Link>Source\DataVisitors\IDataFuncVisitor.cs</Link>
</Compile>
<Compile Include="..\Luban.Job.Cfg\Source\Defs\CfgDefTypeBase.cs">
<Link>Source\Defs\CfgDefTypeBase.cs</Link>
</Compile>
<Compile Include="..\Luban.Job.Cfg\Source\Defs\DefBean.cs">
<Link>Source\Defs\DefBean.cs</Link>
</Compile>
<Compile Include="..\Luban.Job.Cfg\Source\Defs\DefTable.cs">
<Link>Source\Defs\DefTable.cs</Link>
</Compile>
<Compile Include="..\Luban.Job.Cfg\Source\RawDefs\CfgBean.cs">
<Link>Source\RawDefs\CfgBean.cs</Link>
</Compile>
<Compile Include="..\Luban.Job.Cfg\Source\RawDefs\CfgField.cs">
<Link>Source\RawDefs\CfgField.cs</Link>
</Compile>
<Compile Include="..\Luban.Job.Cfg\Source\RawDefs\Defines.cs">
<Link>Source\RawDefs\Defines.cs</Link>
</Compile>
<Compile Include="..\Luban.Job.Cfg\Source\RawDefs\Group.cs">
<Link>Source\RawDefs\Group.cs</Link>
</Compile>
<Compile Include="..\Luban.Job.Cfg\Source\RawDefs\Patch.cs">
<Link>Source\RawDefs\Patch.cs</Link>
</Compile>
<Compile Include="..\Luban.Job.Cfg\Source\RawDefs\ResourceInfo.cs">
<Link>Source\RawDefs\ResourceInfo.cs</Link>
</Compile>
<Compile Include="..\Luban.Job.Cfg\Source\RawDefs\Service.cs">
<Link>Source\RawDefs\Service.cs</Link>
</Compile>
<Compile Include="..\Luban.Job.Cfg\Source\RawDefs\Table.cs">
<Link>Source\RawDefs\Table.cs</Link>
</Compile>
<Compile Include="..\Luban.Job.Cfg\Source\TypeVisitors\DeepCompareTypeDefine.cs">
<Link>Source\TypeVisitors\DeepCompareTypeDefine.cs</Link>
</Compile>
<Compile Include="..\Luban.Job.Cfg\Source\TypeVisitors\IsMultiData.cs">
<Link>Source\TypeVisitors\IsMultiData.cs</Link>
</Compile>
<Compile Include="..\Luban.Job.Cfg\Source\TypeVisitors\IsNotSepTypeVisitor.cs">
<Link>Source\TypeVisitors\IsNotSepTypeVisitor.cs</Link>
</Compile>
<Compile Include="..\Luban.Job.Cfg\Source\TypeVisitors\RefTypeVisitor.cs">
<Link>Source\Defs\RefTypeVisitor.cs</Link>
</Compile>
<Compile Include="..\Luban.Job.Cfg\Source\Utils\DataUtil.cs">
<Link>Source\Utils\DataUtil.cs</Link>
</Compile>
<Compile Include="..\Luban.Job.Common\Source\Defs\CommonDefLoader.cs">
<Link>Source\Defs\CommonDefLoader.cs</Link>
</Compile>
<Compile Include="..\Luban.Job.Common\Source\Defs\DefAssemblyBase.cs">
<Link>Source\Defs\DefAssemblyBase.cs</Link>
</Compile>
<Compile Include="..\Luban.Job.Common\Source\Defs\DefBeanBase.cs">
<Link>Source\Defs\DefBeanBase.cs</Link>
</Compile>
<Compile Include="..\Luban.Job.Common\Source\Defs\DefEnum.cs">
<Link>Source\Defs\DefEnum.cs</Link>
</Compile>
<Compile Include="..\Luban.Job.Common\Source\Defs\DefFieldBase.cs">
<Link>Source\Defs\DefFieldBase.cs</Link>
</Compile>
<Compile Include="..\Luban.Job.Common\Source\ELanguage.cs">
<Link>Source\ELanguage.cs</Link>
</Compile>
<Compile Include="..\Luban.Job.Common\Source\RawDefs\Bean.cs">
<Link>Source\RawDefs\Bean.cs</Link>
</Compile>
<Compile Include="..\Luban.Job.Common\Source\RawDefs\Field.cs">
<Link>Source\RawDefs\Field.cs</Link>
</Compile>
<Compile Include="..\Luban.Job.Common\Source\RawDefs\PEnum.cs">
<Link>Source\RawDefs\PEnum.cs</Link>
</Compile>
<Compile Include="..\Luban.Job.Common\Source\Types\TArray.cs">
<Link>Source\Types\TArray.cs</Link>
</Compile>
<Compile Include="..\Luban.Job.Common\Source\Types\TBean.cs">
<Link>Source\Types\TBean.cs</Link>
</Compile>
<Compile Include="..\Luban.Job.Common\Source\Types\TBool.cs">
<Link>Source\Types\TBool.cs</Link>
</Compile>
<Compile Include="..\Luban.Job.Common\Source\Types\TByte.cs">
<Link>Source\Types\TByte.cs</Link>
</Compile>
<Compile Include="..\Luban.Job.Common\Source\Types\TBytes.cs">
<Link>Source\Types\TBytes.cs</Link>
</Compile>
<Compile Include="..\Luban.Job.Common\Source\Types\TDateTime.cs">
<Link>Source\Types\TDateTime.cs</Link>
</Compile>
<Compile Include="..\Luban.Job.Common\Source\Types\TDouble.cs">
<Link>Source\Types\TDouble.cs</Link>
</Compile>
<Compile Include="..\Luban.Job.Common\Source\Types\TEnum.cs">
<Link>Source\Types\TEnum.cs</Link>
</Compile>
<Compile Include="..\Luban.Job.Common\Source\Types\TFint.cs">
<Link>Source\Types\TFint.cs</Link>
</Compile>
<Compile Include="..\Luban.Job.Common\Source\Types\TFloat.cs">
<Link>Source\Types\TFloat.cs</Link>
</Compile>
<Compile Include="..\Luban.Job.Common\Source\Types\TFlong.cs">
<Link>Source\Types\TFlong.cs</Link>
</Compile>
<Compile Include="..\Luban.Job.Common\Source\Types\TFshort.cs">
<Link>Source\Types\TFshort.cs</Link>
</Compile>
<Compile Include="..\Luban.Job.Common\Source\Types\TInt.cs">
<Link>Source\Types\TInt.cs</Link>
</Compile>
<Compile Include="..\Luban.Job.Common\Source\Types\TList.cs">
<Link>Source\Types\TList.cs</Link>
</Compile>
<Compile Include="..\Luban.Job.Common\Source\Types\TLong.cs">
<Link>Source\Types\TLong.cs</Link>
</Compile>
<Compile Include="..\Luban.Job.Common\Source\Types\TMap.cs">
<Link>Source\Types\TMap.cs</Link>
</Compile>
<Compile Include="..\Luban.Job.Common\Source\Types\TSet.cs">
<Link>Source\Types\TSet.cs</Link>
</Compile>
<Compile Include="..\Luban.Job.Common\Source\Types\TShort.cs">
<Link>Source\Types\TShort.cs</Link>
</Compile>
<Compile Include="..\Luban.Job.Common\Source\Types\TString.cs">
<Link>Source\Types\TString.cs</Link>
</Compile>
<Compile Include="..\Luban.Job.Common\Source\Types\TText.cs">
<Link>Source\Types\TText.cs</Link>
</Compile>
<Compile Include="..\Luban.Job.Common\Source\Types\TType.cs">
<Link>Source\Types\TType.cs</Link>
</Compile>
<Compile Include="..\Luban.Job.Common\Source\Types\TVector2.cs">
<Link>Source\Types\TVector2.cs</Link>
</Compile>
<Compile Include="..\Luban.Job.Common\Source\Types\TVector3.cs">
<Link>Source\Types\TVector3.cs</Link>
</Compile>
<Compile Include="..\Luban.Job.Common\Source\Types\TVector4.cs">
<Link>Source\Types\TVector4.cs</Link>
</Compile>
<Compile Include="..\Luban.Job.Common\Source\TypeVisitors\AllFalseVisitor.cs">
<Link>Source\TypeVisitors\AllFalseVisitor.cs</Link>
</Compile>
<Compile Include="..\Luban.Job.Common\Source\TypeVisitors\AllTrueVisitor.cs">
<Link>Source\TypeVisitors\AllTrueVisitor.cs</Link>
</Compile>
<Compile Include="..\Luban.Job.Common\Source\TypeVisitors\DecoratorFuncVisitor.cs">
<Link>Source\TypeVisitors\DecoratorFuncVisitor.cs</Link>
</Compile>
<Compile Include="..\Luban.Job.Common\Source\TypeVisitors\ITypeActionVisitor.cs">
<Link>Source\TypeVisitors\ITypeActionVisitor.cs</Link>
</Compile>
<Compile Include="..\Luban.Job.Common\Source\TypeVisitors\ITypeFuncVisitor.cs">
<Link>Source\TypeVisitors\ITypeFuncVisitor.cs</Link>
</Compile>
<Compile Include="..\Luban.Job.Common\Source\Utils\DefUtil.cs">
<Link>Source\Utils\DefUtil.cs</Link>
</Compile>
<Compile Include="..\Luban.Server.Common\Source\IAgent.cs">
<Link>Source\IAgent.cs</Link>
</Compile>
<Compile Include="AssistantTab.cs">
<SubType>Component</SubType>
</Compile>
<Compile Include="AssistantTab.Designer.cs">
<DependentUpon>AssistantTab.cs</DependentUpon>
</Compile>
<Compile Include="Properties\AssemblyInfo.cs">
<SubType>Code</SubType>
</Compile>
<EmbeddedResource Include="AssistantTab.resx">
<DependentUpon>AssistantTab.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Properties\Resources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
@ -168,6 +526,9 @@
<AutoGen>True</AutoGen>
<DependentUpon>Resources.resx</DependentUpon>
</Compile>
<None Include="app.config" />
<None Include="LubanAssistant_TemporaryKey.pfx" />
<None Include="packages.config" />
<None Include="Properties\Settings.settings">
<Generator>SettingsSingleFileGenerator</Generator>
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
@ -175,7 +536,37 @@
<Compile Include="Properties\Settings.Designer.cs">
<AutoGen>True</AutoGen>
<DependentUpon>Settings.settings</DependentUpon>
<DesignTimeSharedInput>True</DesignTimeSharedInput>
</Compile>
<Compile Include="Source\AtomicLong.cs" />
<Compile Include="Source\CacheFileUtil.cs" />
<Compile Include="Source\Collections\CollectionExtension.cs" />
<Compile Include="Source\Collections\CollectionUtil.cs" />
<Compile Include="Source\Common\HashUtil.cs" />
<Compile Include="Source\Common\MathUtil.cs" />
<Compile Include="Source\Common\SerializationUtil.cs" />
<Compile Include="Source\Common\StringUtil.cs" />
<Compile Include="Source\Common\TimeUtil.cs" />
<Compile Include="Source\Common\ValueUtil.cs" />
<Compile Include="Source\DataSources\DataSourceFactory.cs" />
<Compile Include="Source\Datas\DText.cs" />
<Compile Include="Source\Datas\DType.cs" />
<Compile Include="Source\Defs\CfgDefLoader.cs" />
<Compile Include="Source\Defs\DefAssembly.cs" />
<Compile Include="Source\Defs\DefField.cs" />
<Compile Include="Source\Defs\DefTypeBase.cs" />
<Compile Include="Source\FileInfo.cs" />
<Compile Include="Source\GetImportFileOrDirectory.cs" />
<Compile Include="Source\LocalAgent.cs" />
<Compile Include="Source\QueryFilesExists.cs" />
<Compile Include="Source\Serialization\BeanBase.cs" />
<Compile Include="Source\Serialization\ByteBuf.cs" />
<Compile Include="Source\Serialization\EUnmarshalError.cs" />
<Compile Include="Source\Serialization\FieldTag.cs" />
<Compile Include="Source\Serialization\ISerializable.cs" />
<Compile Include="Source\Serialization\ITypeId.cs" />
<Compile Include="Source\Serialization\SerializationException.cs" />
<Compile Include="Source\Utils\DataLoaderUtil.cs" />
<Compile Include="ThisAddIn.cs">
<SubType>Code</SubType>
</Compile>
@ -187,10 +578,22 @@
</Compile>
<AppDesigner Include="Properties\" />
</ItemGroup>
<ItemGroup>
<Folder Include="TypeVisitors\" />
</ItemGroup>
<PropertyGroup>
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">10.0</VisualStudioVersion>
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
</PropertyGroup>
<PropertyGroup>
<SignManifests>true</SignManifests>
</PropertyGroup>
<PropertyGroup>
<ManifestKeyFile>LubanAssistant_TemporaryKey.pfx</ManifestKeyFile>
</PropertyGroup>
<PropertyGroup>
<ManifestCertificateThumbprint>DB8575295993B72B55091F842E5704CA3A263CD5</ManifestCertificateThumbprint>
</PropertyGroup>
<!-- Include the build rules for a C# project. -->
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- Include additional build rules for an Office application add-in. -->
@ -206,4 +609,12 @@
</FlavorProperties>
</VisualStudio>
</ProjectExtensions>
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>这台计算机上缺少此项目引用的 NuGet 程序包。使用“NuGet 程序包还原”可下载这些程序包。有关更多信息,请参见 http://go.microsoft.com/fwlink/?LinkID=322105。缺少的文件是 {0}。</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('..\packages\Scriban.4.1.0\build\Scriban.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Scriban.4.1.0\build\Scriban.props'))" />
<Error Condition="!Exists('..\packages\Scriban.4.1.0\build\Scriban.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Scriban.4.1.0\build\Scriban.targets'))" />
</Target>
<Import Project="..\packages\Scriban.4.1.0\build\Scriban.targets" Condition="Exists('..\packages\Scriban.4.1.0\build\Scriban.targets')" />
</Project>

View File

@ -1,10 +1,10 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
// 此代码由工具生成。
// 运行时版本:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// 对此文件的更改可能会导致不正确的行为,并且如果
// 重新生成代码,这些更改将会丢失。
// </auto-generated>
//------------------------------------------------------------------------------
@ -12,7 +12,7 @@ namespace LubanAssistant.Properties {
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "16.0.0.0")]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "16.10.0.0")]
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
@ -22,5 +22,17 @@ namespace LubanAssistant.Properties {
return defaultInstance;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("")]
public string rootDefineFile {
get {
return ((string)(this["rootDefineFile"]));
}
set {
this["rootDefineFile"] = value;
}
}
}
}

View File

@ -1,7 +1,9 @@
<?xml version='1.0' encoding='utf-8'?>
<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)">
<Profiles>
<Profile Name="(Default)" />
</Profiles>
<Settings />
</SettingsFile>
<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)" GeneratedClassNamespace="LubanAssistant.Properties" GeneratedClassName="Settings">
<Profiles />
<Settings>
<Setting Name="rootDefineFile" Type="System.String" Scope="User">
<Value Profile="(Default)" />
</Setting>
</Settings>
</SettingsFile>

View File

@ -0,0 +1,36 @@
using System.Threading;
namespace Bright.Threading
{
public class AtomicLong
{
private long _value;
public AtomicLong(long initValue = 0)
{
_value = initValue;
}
public long IncrementAndGet()
{
return Interlocked.Add(ref _value, 1);
}
public long AddAndGet(long step)
{
return Interlocked.Add(ref _value, step);
}
public long GetAndAdd(long step)
{
return Interlocked.Add(ref _value, step);
}
public long Value { get => Interlocked.Read(ref _value); set => Interlocked.Exchange(ref _value, value); }
public override string ToString()
{
return _value.ToString();
}
}
}

View File

@ -0,0 +1,56 @@
using Luban.Common.Protos;
using Luban.Common.Utils;
using Luban.Server.Common;
using System;
using System.Threading.Tasks;
namespace Luban.Job.Common.Utils
{
public static class CacheFileUtil
{
private static readonly NLog.Logger s_logger = NLog.LogManager.GetCurrentClassLogger();
public static string GenStringOrBytesMd5AndAddCache(string fileName, object content)
{
switch (content)
{
case string s: return GenMd5AndAddCache(fileName, s);
case byte[] bs: return GenMd5AndAddCache(fileName, bs);
default: throw new System.NotSupportedException();
}
}
public static string GenMd5AndAddCache(string fileName, string content, bool withUtf8Bom = false)
{
content = content.Replace("\r\n", "\n");
byte[] bytes;
if (!withUtf8Bom)
{
bytes = System.Text.Encoding.UTF8.GetBytes(content);
}
else
{
//bytes = new byte[System.Text.Encoding.UTF8.GetByteCount(content) + 3 /* bom header */];
//bytes[0] = 0xef;
//bytes[1] = 0xbb;
//bytes[2] = 0xbf;
//System.Text.Encoding.UTF8.GetBytes(content, bytes.AsSpan(3));
throw new System.NotSupportedException();
}
var md5 = FileUtil.CalcMD5(bytes);
#if !LUBAN_ASSISTANT
CacheManager.Ins.AddCache(fileName, md5, bytes);
#endif
return md5;
}
public static string GenMd5AndAddCache(string fileName, byte[] bytes)
{
var md5 = FileUtil.CalcMD5(bytes);
#if !LUBAN_ASSISTANT
CacheManager.Ins.AddCache(fileName, md5, bytes);
#endif
return md5;
}
}
}

View File

@ -0,0 +1,260 @@
using System;
using System.Collections.Generic;
namespace Bright.Collections
{
public static class CollectionExtension
{
public static void AddRange<T>(this IList<T> dst, IEnumerable<T> src)
{
foreach (var x in src)
{
dst.Add(x);
}
}
public static bool TryAdd<TK, TV>(this IDictionary<TK, TV> map, TK key, TV value)
{
if (map.ContainsKey(key))
{
return false;
}
map.Add(key, value);
return true;
}
public static TV GetValueOrDefault<TK, TV>(this IDictionary<TK, TV> map, TK key, TV defaultValue = default)
{
return map.TryGetValue(key, out var value) ? value : defaultValue;
}
public static TV GetOrAdd<TK, TV>(this IDictionary<TK, TV> map, TK key, Func<TK, TV> creator)
{
if (map.TryGetValue(key, out var value))
{
return value;
}
else
{
TV newValue = creator(key);
map.Add(key, newValue);
return newValue;
}
}
public static TV GetOrAdd<TK, TV>(this IDictionary<TK, TV> map, TK key) where TV : new()
{
if (map.TryGetValue(key, out var value))
{
return value;
}
else
{
TV newValue = new TV();
map.Add(key, newValue);
return newValue;
}
}
public static TV Get<TK, TV>(this IDictionary<TK, TV> map, TK key) where TV : class
{
return map.TryGetValue(key, out var value) ? value : null;
}
public static bool Contains<TK, TV>(this IDictionary<TK, TV> map, TK key, TV value)
{
return map.Contains(new KeyValuePair<TK, TV>(key, value));
}
public static void PutAll<TK, TV>(this IDictionary<TK, TV> dst, IDictionary<TK, TV> src)
{
foreach (var e in src)
{
dst[e.Key] = e.Value;
}
}
public static bool IsEmpty<TE>(this ICollection<TE> c)
{
return c.Count == 0;
}
public static void Merge(this IDictionary<int, float> dst, IDictionary<int, float> src)
{
foreach (var e in src)
{
if (dst.TryGetValue(e.Key, out var v))
{
dst[e.Key] = v + e.Value;
}
else
{
dst[e.Key] = e.Value;
}
}
}
public static void Replace(this IDictionary<int, float> dst, IDictionary<int, float> src)
{
dst.Clear();
dst.PutAll(src);
}
public static int AddValue<T>(this IDictionary<T, int> dst, T key, int add)
{
if (dst.TryGetValue(key, out var value))
{
return dst[key] = value + add;
}
else
{
return dst[key] = add;
}
}
public static long AddValue<T>(this IDictionary<T, long> dst, T key, long add)
{
if (dst.TryGetValue(key, out var value))
{
return dst[key] = value + add;
}
else
{
return dst[key] = add;
}
}
public static int IncrementValue<T>(this IDictionary<T, int> dst, T key)
{
if (dst.TryGetValue(key, out var value))
{
return dst[key] = value + 1;
}
else
{
return dst[key] = 1;
}
}
public static long IncrementValue<T>(this IDictionary<T, long> dst, T key)
{
if (dst.TryGetValue(key, out var value))
{
return dst[key] = value + 1;
}
else
{
return dst[key] = 1;
}
}
public static bool ContainsAll<T>(this IList<T> a, IList<T> b)
{
foreach (var x in b)
{
if (!a.Contains(x))
{
return false;
}
}
return true;
}
public static void RemoveAll<T>(this IList<T> a, IList<T> b)
{
foreach (var x in b)
{
a.Remove(x);
}
}
public static bool DicEquals<TK, TV>(this IDictionary<TK, TV> a, IDictionary<TK, TV> b)
{
if (a.Count != b.Count)
{
return false;
}
foreach (var e in a)
{
if (!(b.TryGetValue(e.Key, out var v) && v.Equals(e.Value)))
{
return false;
}
}
return true;
}
public static void AddAll<TK, TV>(this Dictionary<TK, TV> data, Dictionary<TK, TV> b)
{
foreach (var e in b)
{
data[e.Key] = e.Value;
}
}
public static Dictionary<TK, TV> Plus<TK, TV>(this Dictionary<TK, TV> data, TK key, TV value)
{
var newMap = new Dictionary<TK, TV>(data)
{
[key] = value
};
return newMap;
}
public static T[] CopySubArray<T>(this T[] data, int index, int length)
{
T[] result = new T[length];
Array.Copy(data, index, result, 0, length);
return result;
}
/// <summary>
/// 返回第一个满足条件的元素的index
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="arr"></param>
/// <param name="predic"></param>
/// <returns>返回第一个满足条件的元素的index,如果没找到,返回 -1</returns>
public static int IndexOfFirst<T>(IEnumerable<T> arr, Func<T, bool> predic)
{
int i = 0;
foreach (var x in arr)
{
if (predic(x))
{
return i;
}
i++;
}
return -1;
}
/// <summary>
/// 返回最后一个满足条件的元素的index
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="arr"></param>
/// <param name="predic"></param>
/// <returns>返回最后一个满足条件的元素的index,如果没找到,返回 -1</returns>
public static int IndexOfLast<T>(IEnumerable<T> arr, Func<T, bool> predic)
{
int i = -1;
foreach (var x in arr)
{
if (predic(x))
{
++i;
}
else
{
return i;
}
}
return -1;
}
}
}

View File

@ -0,0 +1,76 @@
using System.Collections.Generic;
using System.Text;
namespace Bright.Collections
{
public static class EmptyDictionary<TK, TV>
{
public static Dictionary<TK, TV> Empty { get; } = new Dictionary<TK, TV>();
}
public static class CollectionUtil
{
public static Dictionary<TK, TV> SingletonMap<TK, TV>(TK key, TV value)
{
var newMap = new Dictionary<TK, TV>
{
{ key, value }
};
return newMap;
}
public static string ToString<TK, TV>(IDictionary<TK, TV> m)
{
var sb = new StringBuilder();
sb.Append('{');
foreach (var e in m)
{
sb.Append(e.Key).Append(':').Append(e.Value).Append(',');
}
sb.Append('}');
return sb.ToString();
}
public static void Replace<TK, TV>(IDictionary<TK, TV> dest, IDictionary<TK, TV> src)
{
dest.Clear();
foreach (var entry in src)
{
dest.Add(entry.Key, entry.Value);
}
}
public static void MergeIntValueDic<TK>(IDictionary<TK, int> dest, IDictionary<TK, int> src)
{
foreach (var entry in src)
{
if (dest.ContainsKey(entry.Key))
{
dest[entry.Key] = dest[entry.Key] + entry.Value;
}
else
{
dest.Add(entry.Key, entry.Value);
}
}
}
public static void MergeFloatValueDic<TK>(IDictionary<TK, float> dest, IDictionary<TK, float> src)
{
foreach (var entry in src)
{
if (dest.ContainsKey(entry.Key))
{
dest[entry.Key] = dest[entry.Key] + entry.Value;
}
else
{
dest.Add(entry.Key, entry.Value);
}
}
}
}
}

View File

@ -0,0 +1,91 @@
using System;
namespace Bright.Common
{
/// <summary>
/// 从 System.Collections.HashTable 源码抄来
/// </summary>
public static class HashUtil
{
private static readonly int[] primes = {
3, 7, 11, 17, 23, 29, 37, 47, 59, 71, 89, 107, 131, 163, 197, 239, 293, 353, 431, 521, 631, 761, 919,
1103, 1327, 1597, 1931, 2333, 2801, 3371, 4049, 4861, 5839, 7013, 8419, 10103, 12143, 14591,
17519, 21023, 25229, 30293, 36353, 43627, 52361, 62851, 75431, 90523, 108631, 130363, 156437,
187751, 225307, 270371, 324449, 389357, 467237, 560689, 672827, 807403, 968897, 1162687, 1395263,
1674319, 2009191, 2411033, 2893249, 3471899, 4166287, 4999559, 5999471, 7199369};
private const int HashPrime = 101;
private const int MaxPrimeArrayLength = 0x7FEFFFFD;
public static int GetPrime(int min)
{
if (min < 0)
throw new ArgumentException();
for (int i = 0; i < primes.Length; i++)
{
int prime = primes[i];
if (prime >= min) return prime;
}
//outside of our predefined table.
//compute the hard way.
for (int i = (min | 1); i < int.MaxValue; i += 2)
{
if (IsPrime(i) && ((i - 1) % HashPrime != 0))
return i;
}
return min;
}
public static bool IsPrime(int candidate)
{
if ((candidate & 1) != 0)
{
int limit = (int)Math.Sqrt(candidate);
for (int divisor = 3; divisor <= limit; divisor += 2)
{
if ((candidate % divisor) == 0)
return false;
}
return true;
}
return (candidate == 2);
}
public static int GetMinPrime()
{
return primes[0];
}
// Returns size of hashtable to grow to.
public static int ExpandPrime(int oldSize)
{
int newSize = 2 * oldSize;
// Allow the hashtables to grow to maximum possible size (~2G elements) before encoutering capacity overflow.
// Note that this check works even when _items.Length overflowed thanks to the (uint) cast
if ((uint)newSize > MaxPrimeArrayLength && MaxPrimeArrayLength > oldSize)
{
return MaxPrimeArrayLength;
}
return GetPrime(newSize);
}
public static int CalcHash(int x)
{
int hash = 17;
return hash * 23 + x;
}
public static int CalcHash(int x, int y)
{
int hash = 17;
hash = hash * 23 + x;
return hash * 23 + y;
}
}
}

View File

@ -0,0 +1,106 @@
namespace Bright.Common
{
public static class MathUtil
{
/// <summary>
/// 确保返回 x + y 的正确值, 如果溢出 抛出异常
/// </summary>
/// <param name="x"></param>
/// <param name="y"></param>
/// <returns></returns>
public static int AddExactly(int x, int y)
{
return checked(x + y);
}
/// <summary>
/// 确保返回 x + y 的正确值, 如果溢出 抛出异常
/// </summary>
/// <param name="x"></param>
/// <param name="y"></param>
/// <returns></returns>
public static long AddExactly(long x, long y)
{
return checked(x + y);
}
/// <summary>
/// 确保返回 x - y 的正确值, 如果溢出 抛出异常
/// </summary>
/// <param name="x"></param>
/// <param name="y"></param>
/// <returns></returns>
public static int SubExcatly(int x, int y)
{
return checked(x - y);
}
/// <summary>
/// 确保返回 x - y 的正确值, 如果溢出 抛出异常
/// </summary>
/// <param name="x"></param>
/// <param name="y"></param>
/// <returns></returns>
public static long SubExactly(long x, long y)
{
return checked(x - y);
}
/// <summary>
/// 确保返回 x * y 的正确值, 如果溢出 抛出异常
/// </summary>
/// <param name="x"></param>
/// <param name="y"></param>
/// <returns></returns>
public static int MultifyExactly(int x, int y)
{
return checked(x * y);
}
/// <summary>
/// 确保返回 x * y 的正确值, 如果溢出 抛出异常
/// </summary>
/// <param name="x"></param>
/// <param name="y"></param>
/// <returns></returns>
public static long MultifyExactly(long x, long y)
{
return checked(x * y);
}
/// <summary>
/// 取 >= x/y 的最小整数
/// </summary>
/// <param name="x">除数</param>
/// <param name="y">被除数</param>
/// <returns></returns>
public static int Ceil(int x, int y)
{
return (x + y - 1) / y;
}
/// <summary>
/// 取 >= x/y 的最小整数
/// </summary>
/// <param name="x">除数</param>
/// <param name="y">被除数</param>
/// <returns></returns>
public static long Ceil(long x, long y)
{
return (x + y - 1) / y;
}
/// <summary>
/// 返回 [min, max] 之间的数
/// </summary>
/// <param name="value"></param>
/// <param name="min"></param>
/// <param name="max"></param>
/// <returns></returns>
public static int Clamp(int value, int min, int max)
{
return value < min ? min : (value > max ? max : value);
}
}
}

View File

@ -0,0 +1,214 @@
using System.Collections.Generic;
using System.Numerics;
using Bright.Serialization;
namespace Bright.Common
{
public static class SerializationUtil
{
public static void Serialize<T>(ByteBuf os, List<T> list) where T : ISerializable
{
os.WriteSize(list.Count);
foreach (var e in list)
{
e.Serialize(os);
}
}
public static void Deserialize<T>(ByteBuf os, List<T> list) where T : ISerializable, new()
{
int n = os.ReadSize();
for (int i = 0; i < n; i++)
{
T e = new T();
e.Deserialize(os);
list.Add(e);
}
}
public static void Serialize(ByteBuf os, List<string> list)
{
os.WriteSize(list.Count);
foreach (var e in list)
{
os.WriteString(e);
}
}
public static void Deserialize(ByteBuf os, List<string> list)
{
int n = os.ReadSize();
for (int i = 0; i < n; i++)
{
list.Add(os.ReadString());
}
}
public static unsafe int FloatToIntBits(float f)
{
return *((int*)&f);
}
public static void SerializeBool(ByteBuf buf, bool x)
{
buf.WriteBool(x);
}
public static bool DeserializeBool(ByteBuf buf)
{
return buf.ReadBool();
}
public static void SerializeByte(ByteBuf buf, byte x)
{
buf.WriteByte(x);
}
public static byte DeserializeByte(ByteBuf buf)
{
return buf.ReadByte();
}
public static void SerializeShort(ByteBuf buf, short x)
{
buf.WriteShort(x);
}
public static short DeserializeShort(ByteBuf buf)
{
return buf.ReadShort();
}
public static void SerializeFshort(ByteBuf buf, short x)
{
buf.WriteFshort(x);
}
public static short DeserializeFshort(ByteBuf buf)
{
return buf.ReadFshort();
}
public static void SerializeInt(ByteBuf buf, int x)
{
buf.WriteInt(x);
}
public static int DeserializeInt(ByteBuf buf)
{
return buf.ReadInt();
}
public static void SerializeFint(ByteBuf buf, int x)
{
buf.WriteFint(x);
}
public static int DeserializeFint(ByteBuf buf)
{
return buf.ReadFint();
}
public static void SerializeLong(ByteBuf buf, long x)
{
buf.WriteLong(x);
}
public static long DeserializeLong(ByteBuf buf)
{
return buf.ReadLong();
}
public static void SerializeFlong(ByteBuf buf, long x)
{
buf.WriteFlong(x);
}
public static long DeserializeFlong(ByteBuf buf)
{
return buf.ReadFlong();
}
public static void SerializeFloat(ByteBuf buf, float x)
{
buf.WriteFloat(x);
}
public static float DeserializeFloat(ByteBuf buf)
{
return buf.ReadFloat();
}
public static void SerializeDouble(ByteBuf buf, double x)
{
buf.WriteDouble(x);
}
public static double DeserializeDouble(ByteBuf buf)
{
return buf.ReadDouble();
}
public static void SerializeString(ByteBuf buf, string x)
{
buf.WriteString(x);
}
public static string DeserializeString(ByteBuf buf)
{
return buf.ReadString();
}
public static void SerializeBytes(ByteBuf buf, byte[] x)
{
buf.WriteBytes(x);
}
public static byte[] DeserializeBytes(ByteBuf buf)
{
return buf.ReadBytes();
}
public static void SerializeVector2(ByteBuf buf, Vector2 x)
{
buf.WriteVector2(x);
}
public static Vector2 DeserializeVector2(ByteBuf buf)
{
return buf.ReadVector2();
}
public static void SerializeVector3(ByteBuf buf, Vector3 x)
{
buf.WriteVector3(x);
}
public static Vector3 DeserializeVector3(ByteBuf buf)
{
return buf.ReadVector3();
}
public static void SerializeVector4(ByteBuf buf, Vector4 x)
{
buf.WriteVector4(x);
}
public static Vector4 DeserializeVector4(ByteBuf buf)
{
return buf.ReadVector4();
}
public static void SerializeBean<T>(ByteBuf buf, T x) where T : BeanBase
{
x.Serialize(buf);
}
public static T DeserializeBean<T>(ByteBuf buf) where T : BeanBase, new()
{
var x = new T();
x.Deserialize(buf);
return x;
}
}
}

View File

@ -0,0 +1,52 @@
using System.Collections.Generic;
using System.Text;
namespace Bright.Common
{
public static class StringUtil
{
public static string ToStr(object o)
{
return ToStr(o, new StringBuilder());
}
public static string ToStr(object o, StringBuilder sb)
{
foreach (var p in o.GetType().GetFields())
{
sb.Append($"{p.Name} = {p.GetValue(o)},");
}
foreach (var p in o.GetType().GetProperties())
{
sb.Append($"{p.Name} = {p.GetValue(o)},");
}
return sb.ToString();
}
public static string ArrayToString<T>(T[] arr)
{
return "[" + string.Join(",", arr) + "]";
}
public static string CollectionToString<T>(IEnumerable<T> arr)
{
return "[" + string.Join(",", arr) + "]";
}
public static string CollectionToString<TK, TV>(IDictionary<TK, TV> dic)
{
var sb = new StringBuilder('{');
foreach (var e in dic)
{
sb.Append(e.Key).Append(':');
sb.Append(e.Value).Append(',');
}
sb.Append('}');
return sb.ToString();
}
}
}

View File

@ -0,0 +1,156 @@
using System;
using System.Threading;
namespace Bright.Time
{
public static class TimeUtil
{
public static readonly long TIMEZONE_OFFSET_MILLS = (long)TimeZoneInfo.Local.GetUtcOffset(DateTimeOffset.FromUnixTimeSeconds(0)).TotalMilliseconds;
public static readonly int TIMEZONE_OFFSET = (int)TimeZoneInfo.Local.GetUtcOffset(DateTimeOffset.FromUnixTimeSeconds(0)).TotalSeconds;
public const long DAY_MILLISECONDS = 86400000;
public const int DAY_SECONDS = 86400;
public const int HOUR_SECONDS = 3600;
public const int MINUTE_SECONDS = 60;
public const int WEEKDAY_OF_19700101 = 3;
public const long HOUR_MILLISECONDS = 3600000;
public const long MINUTE_MILLISECONDS = 60000;
public const long WEEK_MILLISECONDS = DAY_MILLISECONDS * 7;
public static bool IsSameDay(int time1, int time2)
{
return (time1 + TIMEZONE_OFFSET) / DAY_SECONDS == (time2 + TIMEZONE_OFFSET) / DAY_SECONDS;
}
#if DEBUG
private static long s_millisTimeOffsetForTest;
/// <summary>
/// 用于调整服务器内时间,只对测试版本生效
/// </summary>
public static long MillisTimeOffsetForTest
{
get
{
return Interlocked.Read(ref s_millisTimeOffsetForTest);
}
set
{
Interlocked.Exchange(ref s_millisTimeOffsetForTest, value);
}
}
public static long NowMillis => DateTimeOffset.Now.ToUnixTimeMilliseconds() + s_millisTimeOffsetForTest;
public static int Now => (int)(DateTimeOffset.Now.ToUnixTimeSeconds() + s_millisTimeOffsetForTest / 1000);
#else
public static long NowMillis => DateTimeOffset.Now.ToUnixTimeMilliseconds();
public static int Now => (int)DateTimeOffset.Now.ToUnixTimeSeconds();
#endif
public static bool IsSameWeek(int time1, int time2)
{
return GetMondayZeroTimeOfThisWeek(time1) == GetMondayZeroTimeOfThisWeek(time2);
}
public static int TodayZeroTime()
{
return TodayZeroTime(Now);
}
public static int TodayZeroTime(int time)
{
return (time + TIMEZONE_OFFSET) / DAY_SECONDS * DAY_SECONDS - TIMEZONE_OFFSET;
}
public static int TomorrowZeroTime()
{
return TomorrowZeroTime(Now);
}
public static int TomorrowZeroTime(int time)
{
return TodayZeroTime(time) + DAY_SECONDS;
}
public static int AnotherDayZeroTime(int time, int offsetDayNum)
{
return TodayZeroTime(time) + DAY_SECONDS * offsetDayNum;
}
public static bool IsContinuesDay(int time1, int time2)
{
return (time1 + TIMEZONE_OFFSET) / DAY_SECONDS + 1 == (time2 + TIMEZONE_OFFSET) / DAY_SECONDS;
}
public static int DayOffset(int time1, int time2)
{
int a = (time1 + TIMEZONE_OFFSET) / DAY_SECONDS;
int b = (time2 + TIMEZONE_OFFSET) / DAY_SECONDS;
return Math.Abs(a - b);
}
public static int GetSecondsFromTodayZeroTime(int time)
{
return time - TodayZeroTime(time);
}
public static int GetHourOfToday(int time)
{
return (time + TIMEZONE_OFFSET) % DAY_SECONDS / HOUR_SECONDS;
}
public static int GetMinuteOfToday(int time)
{
long interval = time - TodayZeroTime(time);
long left = interval % HOUR_SECONDS;
return (int)(left / MINUTE_SECONDS);
}
public static long GetSecondsOfDay(int hour, int minute)
{
return hour * HOUR_SECONDS + minute * MINUTE_SECONDS;
}
public static int GetWeekDay(int time)
{
return ((time + TIMEZONE_OFFSET) / DAY_SECONDS + WEEKDAY_OF_19700101) % 7;
}
public static int GetMondayZeroTimeOfNextWeek(int time)
{
return TodayZeroTime(time) + DAY_SECONDS * (7 - GetWeekDay(time));
}
public static int GetMondayZeroTimeOfNextWeek()
{
return GetMondayZeroTimeOfNextWeek(Now);
}
public static int GetMondayZeroTimeOfThisWeek(int time)
{
return TodayZeroTime(time) - DAY_SECONDS * GetWeekDay(time);
}
/**
* weekday 0 - 6
*/
public static long GetSecondsOfWeek(int weekday, int hour, int minute, int second)
{
return (weekday * 86400 + hour * 3600 + minute * 60 + second) * 1000L;
}
public static long ToMills(float seconds)
{
return (long)((double)seconds * 1000);
}
}
}

View File

@ -0,0 +1,22 @@
namespace Bright.Common
{
public static class ValueUtil
{
public static void Swap<T>(ref T a, ref T b)
{
T temp = a;
a = b;
b = temp;
}
public static void LockAndSwap<T>(object locker, ref T a, ref T b)
{
lock (locker)
{
T temp = a;
a = b;
b = temp;
}
}
}
}

View File

@ -0,0 +1,43 @@
using System;
using System.IO;
namespace Luban.Job.Cfg.DataSources
{
static class DataSourceFactory
{
public static readonly string[] validDataSourceSuffixes = new string[]
{
".xlsx",
".xls",
".csv",
".xml",
".lua",
".json",
".yml",
".bin",
};
public static AbstractDataSource Create(string url, string sheetName, Stream stream)
{
try
{
string ext = url.Contains(".") ? Path.GetExtension(url)?.Substring(1) : url;
AbstractDataSource source;
switch (ext)
{
case "csv":
case "xls":
case "xlsx": source = new Excel.ExcelDataSource(); break;
case "json": source = new Json.JsonDataSource(); break;
default: throw new Exception($"不支持的文件类型:{url}");
}
source.Load(url, sheetName, stream);
return source;
}
catch (Exception e)
{
throw new Exception($"文件{url} 加载失败", e);
}
}
}
}

View File

@ -0,0 +1,54 @@
using Luban.Job.Cfg.DataVisitors;
namespace Luban.Job.Cfg.Datas
{
public class DText : DType
{
public const string KEY_NAME = "key";
public const string TEXT_NAME = "text";
public string Key { get; }
private readonly string _rawValue;
public string RawValue => _rawValue;
public override string TypeName => "text";
public DText(string key, string x)
{
Key = key;
_rawValue = x;
}
public override void Apply<T>(IDataActionVisitor<T> visitor, T x)
{
visitor.Accept(this, x);
}
public override void Apply<T1, T2>(IDataActionVisitor<T1, T2> visitor, T1 x, T2 y)
{
visitor.Accept(this, x, y);
}
public override TR Apply<TR>(IDataFuncVisitor<TR> visitor)
{
return visitor.Accept(this);
}
public override TR Apply<T, TR>(IDataFuncVisitor<T, TR> visitor, T x)
{
return visitor.Accept(this, x);
}
public override bool Equals(object obj)
{
return obj is DText o && o._rawValue == this._rawValue && o.Key == this.Key;
}
public override int GetHashCode()
{
return _rawValue.GetHashCode();
}
}
}

View File

@ -0,0 +1,28 @@
using Luban.Job.Cfg.DataVisitors;
namespace Luban.Job.Cfg.Datas
{
public abstract class DType
{
public abstract void Apply<T>(IDataActionVisitor<T> visitor, T x);
public abstract void Apply<T1, T2>(IDataActionVisitor<T1, T2> visitor, T1 x, T2 y);
public abstract TR Apply<TR>(IDataFuncVisitor<TR> visitor);
public abstract TR Apply<T, TR>(IDataFuncVisitor<T, TR> visitor, T x);
public abstract string TypeName { get; }
}
public abstract class DType<T> : DType
{
public T Value { get; }
protected DType(T value)
{
Value = value;
}
}
}

View File

@ -0,0 +1,471 @@
using Bright.Collections;
using Luban.Common.Utils;
using Luban.Job.Cfg.Datas;
using Luban.Job.Cfg.DataSources.Excel;
using Luban.Job.Cfg.RawDefs;
using Luban.Job.Cfg.Utils;
using Luban.Job.Common.Defs;
using Luban.Job.Common.RawDefs;
using Luban.Job.Common.Types;
using Luban.Job.Common.Utils;
using Luban.Server.Common;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using System.Xml.Linq;
namespace Luban.Job.Cfg.Defs
{
class CfgDefLoader : CommonDefLoader
{
private static readonly NLog.Logger s_logger = NLog.LogManager.GetCurrentClassLogger();
private readonly List<string> _importExcelTableFiles = new();
private readonly List<string> _importExcelEnumFiles = new();
private readonly List<string> _importExcelBeanFiles = new();
private readonly List<Patch> _patches = new();
private readonly List<Table> _cfgTables = new List<Table>();
private readonly List<Service> _cfgServices = new List<Service>();
private readonly List<Group> _cfgGroups = new List<Group>();
private readonly List<string> _defaultGroups = new List<string>();
public CfgDefLoader(IAgent agent) : base(agent)
{
RegisterRootDefineHandler("importexcel", AddImportExcel);
RegisterRootDefineHandler("patch", AddPatch);
RegisterRootDefineHandler("service", AddService);
RegisterRootDefineHandler("group", AddGroup);
RegisterModuleDefineHandler("table", AddTable);
IsBeanFieldMustDefineId = false;
}
public Defines BuildDefines()
{
return new Defines()
{
TopModule = TopModule,
Patches = _patches,
Enums = _enums,
Beans = _beans,
Tables = _cfgTables,
Services = _cfgServices,
Groups = _cfgGroups,
};
}
private static readonly List<string> _excelImportRequireAttrs = new List<string> { "name", "type" };
private void AddImportExcel(XElement e)
{
ValidAttrKeys(RootXml, e, null, _excelImportRequireAttrs);
var importName = XmlUtil.GetRequiredAttribute(e, "name");
if (string.IsNullOrWhiteSpace(importName))
{
throw new Exception("importexcel 属性name不能为空");
}
var type = XmlUtil.GetRequiredAttribute(e, "type");
if (string.IsNullOrWhiteSpace(type))
{
throw new Exception($"importexcel name:'{importName}' type属性不能为空");
}
switch (type)
{
case "table": this._importExcelTableFiles.Add(importName); break;
case "enum": this._importExcelEnumFiles.Add(importName); break;
case "bean": this._importExcelBeanFiles.Add(importName); break;
default: throw new Exception($"importexcel name:'{importName}' type:'{type}' 不合法. 有效值为 table|enum|bean");
}
}
private static readonly List<string> _patchRequireAttrs = new List<string> { "name" };
private void AddPatch(XElement e)
{
ValidAttrKeys(RootXml, e, null, _patchRequireAttrs);
var patchName = e.Attribute("name").Value;
if (string.IsNullOrWhiteSpace(patchName))
{
throw new Exception("patch 属性name不能为空");
}
if (this._patches.Any(b => b.Name == patchName))
{
throw new Exception($"patch '{patchName}' 重复");
}
_patches.Add(new Patch(patchName));
}
private static readonly List<string> _groupOptionalAttrs = new List<string> { "default" };
private static readonly List<string> _groupRequireAttrs = new List<string> { "name" };
private void AddGroup(XElement e)
{
ValidAttrKeys(RootXml, e, _groupOptionalAttrs, _groupRequireAttrs);
List<string> groupNames = CreateGroups(e.Attribute("name").Value);
foreach (var g in groupNames)
{
if (_cfgGroups.Any(cg => cg.Names.Contains(g)))
{
throw new Exception($"group名:'{g}' 重复");
}
}
if (XmlUtil.GetOptionBoolAttribute(e, "default"))
{
this._defaultGroups.AddRange(groupNames);
}
_cfgGroups.Add(new Group() { Names = groupNames });
}
private void FillValueValidator(CfgField f, string attrValue, string validatorName)
{
if (!string.IsNullOrWhiteSpace(attrValue))
{
var validator = new Validator() { Type = validatorName, Rule = attrValue };
f.Validators.Add(validator);
f.ValueValidators.Add(validator);
}
}
private void FillValidators(string defineFile, string key, string attr, List<Validator> result)
{
if (!string.IsNullOrWhiteSpace(attr))
{
#if !LUBAN_ASSISTANT
foreach (var validatorStr in attr.Split('#', StringSplitOptions.RemoveEmptyEntries))
#else
foreach (var validatorStr in attr.Split('#'))
#endif
{
var sepIndex = validatorStr.IndexOf(':');
if (sepIndex <= 0)
{
throw new Exception($"定义文件:{defineFile} key:'{key}' attr:'{attr}' 不是合法的 validator 定义 (key1:value1#key2:value2 ...)");
}
#if !LUBAN_ASSISTANT
result.Add(new Validator() { Type = validatorStr[..sepIndex], Rule = validatorStr[(sepIndex + 1)..] });
#else
result.Add(new Validator() { Type = validatorStr.Substring(0, sepIndex), Rule = validatorStr.Substring(sepIndex + 1, validatorStr.Length - sepIndex - 1) });
#endif
}
}
}
private readonly List<string> _serviceAttrs = new List<string> { "name", "manager", "group" };
private void AddService(XElement e)
{
var name = XmlUtil.GetRequiredAttribute(e, "name");
var manager = XmlUtil.GetRequiredAttribute(e, "manager");
List<string> groups = CreateGroups(XmlUtil.GetOptionalAttribute(e, "group"));
var refs = new List<string>();
s_logger.Trace("service name:{name} manager:{manager}", name, manager);
ValidAttrKeys(RootXml, e, _serviceAttrs, _serviceAttrs);
foreach (XElement ele in e.Elements())
{
string tagName = ele.Name.LocalName;
s_logger.Trace("service {service_name} tag: {name} {value}", name, tagName, ele);
switch (tagName)
{
case "ref":
{
refs.Add(XmlUtil.GetRequiredAttribute(ele, "name"));
break;
}
default:
{
throw new Exception($"service:'{name}' tag:'{tagName}' 非法");
}
}
}
if (!ValidGroup(groups, out var invalidGroup))
{
throw new Exception($"service:'{name}' group:'{invalidGroup}' 不存在");
}
_cfgServices.Add(new Service() { Name = name, Manager = manager, Groups = groups, Refs = refs });
}
private readonly Dictionary<string, Table> _name2CfgTable = new Dictionary<string, Table>();
private static List<string> CreateGroups(string s)
{
return s.Split(',', ';').Select(x => x.Trim()).Where(x => !string.IsNullOrWhiteSpace(x)).ToList();
}
private bool ValidGroup(List<string> groups, out string invalidGroup)
{
foreach (var g in groups)
{
if (!this._cfgGroups.Any(cg => cg.Names.Contains(g)))
{
invalidGroup = g;
return false;
}
}
invalidGroup = null;
return true;
}
private ETableMode ConvertMode(string defineFile, string tableName, string modeStr, string indexStr)
{
ETableMode mode;
switch (modeStr)
{
case "one":
{
if (!string.IsNullOrWhiteSpace(indexStr))
{
throw new Exception($"定义文件:{defineFile} table:'{tableName}' mode=one 是单例表不支持定义index属性");
}
mode = ETableMode.ONE;
break;
}
case "map":
{
//if ((string.IsNullOrWhiteSpace(indexStr) || indexStr.Split(',').Length != 1))
//{
// throw new Exception($"定义文件:{CurImportFile} table:{tableName} 是单键表必须在index属性里指定1个key");
//}
mode = ETableMode.MAP;
break;
}
case "":
{
mode = ETableMode.MAP;
break;
}
default:
{
throw new ArgumentException($"不支持的 mode:{modeStr}");
}
}
return mode;
}
private readonly List<string> _tableOptionalAttrs = new List<string> { "index", "mode", "group", "patch_input", "comment", "define_from_file" };
private readonly List<string> _tableRequireAttrs = new List<string> { "name", "value", "input" };
private void AddTable(string defineFile, XElement e)
{
ValidAttrKeys(defineFile, e, _tableOptionalAttrs, _tableRequireAttrs);
string name = XmlUtil.GetRequiredAttribute(e, "name");
string module = CurNamespace;
string valueType = XmlUtil.GetRequiredAttribute(e, "value");
bool defineFromFile = XmlUtil.GetOptionBoolAttribute(e, "define_from_file");
string index = XmlUtil.GetOptionalAttribute(e, "index");
string group = XmlUtil.GetOptionalAttribute(e, "group");
string comment = XmlUtil.GetOptionalAttribute(e, "comment");
string input = XmlUtil.GetRequiredAttribute(e, "input");
string patchInput = XmlUtil.GetOptionalAttribute(e, "patch_input");
string mode = XmlUtil.GetOptionalAttribute(e, "mode");
string tags = XmlUtil.GetOptionalAttribute(e, "tags");
AddTable(defineFile, name, module, valueType, index, mode, group, comment, defineFromFile, input, patchInput, tags);
}
private void AddTable(string defineFile, string name, string module, string valueType, string index, string mode, string group,
string comment, bool defineFromExcel, string input, string patchInput, string tags)
{
var p = new Table()
{
Name = name,
Namespace = module,
ValueType = valueType,
LoadDefineFromFile = defineFromExcel,
Index = index,
Groups = CreateGroups(group),
Comment = comment,
Mode = ConvertMode(defineFile, name, mode, index),
Tags = tags,
};
if (p.Groups.Count == 0)
{
p.Groups = this._defaultGroups;
}
else if (!ValidGroup(p.Groups, out var invalidGroup))
{
throw new Exception($"定义文件:{defineFile} table:'{p.Name}' group:'{invalidGroup}' 不存在");
}
p.InputFiles.AddRange(input.Split(',').Select(s => s.Trim()).Where(s => !string.IsNullOrWhiteSpace(s)));
if (!string.IsNullOrWhiteSpace(patchInput))
{
foreach (var subPatchStr in patchInput.Split('|').Select(s => s.Trim()).Where(s => !string.IsNullOrWhiteSpace(s)))
{
var nameAndDirs = subPatchStr.Split(':');
if (nameAndDirs.Length != 2)
{
throw new Exception($"定义文件:{defineFile} table:'{p.Name}' patch_input:'{subPatchStr}' 定义不合法");
}
var patchDirs = nameAndDirs[1].Split(',', ';').ToList();
if (!p.PatchInputFiles.TryAdd(nameAndDirs[0], patchDirs))
{
throw new Exception($"定义文件:{defineFile} table:'{p.Name}' patch_input:'{subPatchStr}' 子patch:'{nameAndDirs[0]}' 重复");
}
}
}
_cfgTables.Add(p);
}
private static readonly List<string> _fieldOptionalAttrs = new()
{
"index",
"sep",
"validator",
"key_validator",
"value_validator",
"ref",
"path",
"range",
"multi_rows",
"group",
"res",
"convert",
"comment",
"tags",
"default",
"orientation",
};
private static readonly List<string> _fieldRequireAttrs = new List<string> { "name", "type" };
protected override Field CreateField(string defineFile, XElement e)
{
ValidAttrKeys(defineFile, e, _fieldOptionalAttrs, _fieldRequireAttrs);
return CreateField(defineFile, XmlUtil.GetRequiredAttribute(e, "name"),
XmlUtil.GetRequiredAttribute(e, "type"),
XmlUtil.GetOptionalAttribute(e, "index"),
XmlUtil.GetOptionalAttribute(e, "sep"),
XmlUtil.GetOptionBoolAttribute(e, "multi_rows"),
XmlUtil.GetOptionalAttribute(e, "group"),
XmlUtil.GetOptionalAttribute(e, "res"),
XmlUtil.GetOptionalAttribute(e, "convert"),
XmlUtil.GetOptionalAttribute(e, "comment"),
XmlUtil.GetOptionalAttribute(e, "ref"),
XmlUtil.GetOptionalAttribute(e, "path"),
XmlUtil.GetOptionalAttribute(e, "range"),
XmlUtil.GetOptionalAttribute(e, "key_validator"),
XmlUtil.GetOptionalAttribute(e, "value_validator"),
XmlUtil.GetOptionalAttribute(e, "validator"),
XmlUtil.GetOptionalAttribute(e, "tags"),
false,
DefUtil.ParseOrientation(XmlUtil.GetOptionalAttribute(e, "orientation"))
);
}
private Field CreateField(string defileFile, string name, string type, string index, string sep, bool isMultiRow, string group, string resource, string converter,
string comment, string refs, string path, string range, string keyValidator, string valueValidator, string validator, string tags,
bool ignoreNameValidation, bool isRowOrient)
{
var f = new CfgField()
{
Name = name,
Index = index,
Sep = sep,
IsMultiRow = isMultiRow,
Groups = CreateGroups(group),
Resource = resource,
Converter = converter,
Comment = comment,
Tags = tags,
IgnoreNameValidation = ignoreNameValidation,
IsRowOrient = isRowOrient,
};
// 字段与table的默认组不一样。
// table 默认只属于default=1的组
// 字段默认属于所有组
if (f.Groups.Count == 0)
{
}
else if (!ValidGroup(f.Groups, out var invalidGroup))
{
throw new Exception($"定义文件:{defileFile} field:'{name}' group:'{invalidGroup}' 不存在");
}
f.Type = type;
FillValueValidator(f, refs, "ref");
FillValueValidator(f, path, "path"); // (ue4|unity|normal|regex);xxx;xxx
FillValueValidator(f, range, "range");
FillValidators(defileFile, "key_validator", keyValidator, f.KeyValidators);
FillValidators(defileFile, "value_validator", valueValidator, f.ValueValidators);
FillValidators(defileFile, "validator", validator, f.Validators);
return f;
}
private static readonly List<string> _beanOptinsAttrs = new List<string> { "value_type", "alias", "sep", "comment", "tags" };
private static readonly List<string> _beanRequireAttrs = new List<string> { "name" };
protected override void AddBean(string defineFile, XElement e, string parent)
{
ValidAttrKeys(defineFile, e, _beanOptinsAttrs, _beanRequireAttrs);
var b = new CfgBean()
{
Name = XmlUtil.GetRequiredAttribute(e, "name"),
Namespace = CurNamespace,
Parent = parent.Length > 0 ? parent : "",
TypeId = 0,
IsSerializeCompatible = true,
IsValueType = XmlUtil.GetOptionBoolAttribute(e, "value_type"),
Alias = XmlUtil.GetOptionalAttribute(e, "alias"),
Sep = XmlUtil.GetOptionalAttribute(e, "sep"),
Comment = XmlUtil.GetOptionalAttribute(e, "comment"),
Tags = XmlUtil.GetOptionalAttribute(e, "tags"),
};
var childBeans = new List<XElement>();
bool defineAnyChildBean = false;
foreach (XElement fe in e.Elements())
{
switch (fe.Name.LocalName)
{
case "var":
{
if (defineAnyChildBean)
{
throw new LoadDefException($"定义文件:{defineFile} 类型:{b.FullName} 的多态子bean必须在所有成员字段 <var> 之前定义");
}
b.Fields.Add(CreateField(defineFile, fe)); ;
break;
}
case "bean":
{
defineAnyChildBean = true;
childBeans.Add(fe);
break;
}
default:
{
throw new LoadDefException($"定义文件:{defineFile} 类型:{b.FullName} 不支持 tag:{fe.Name}");
}
}
}
s_logger.Trace("add bean:{@bean}", b);
_beans.Add(b);
var fullname = b.FullName;
foreach (var cb in childBeans)
{
AddBean(defineFile, cb, fullname);
}
}
}
}

View File

@ -0,0 +1,290 @@
using Bright.Collections;
using Luban.Job.Cfg.Datas;
using Luban.Job.Cfg.RawDefs;
using Luban.Job.Cfg.TypeVisitors;
using Luban.Job.Common.Defs;
using Luban.Server.Common;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
namespace Luban.Job.Cfg.Defs
{
public class TableDataInfo
{
public List<Record> MainRecords { get; }
public List<Record> PatchRecords { get; }
public List<Record> FinalRecords { get; set; }
public Dictionary<DType, Record> FinalRecordMap { get; set; }
public TableDataInfo(List<Record> mainRecords, List<Record> patchRecords)
{
MainRecords = mainRecords;
PatchRecords = patchRecords;
}
}
public class DefAssembly : DefAssemblyBase
{
private static readonly NLog.Logger s_logger = NLog.LogManager.GetCurrentClassLogger();
public new static DefAssembly LocalAssebmly { get => (DefAssembly)DefAssemblyBase.LocalAssebmly; set => DefAssemblyBase.LocalAssebmly = value; }
public Service CfgTargetService { get; private set; }
private readonly string _patchName;
private readonly List<string> _excludeTags;
public Patch TargetPatch { get; private set; }
public TimeZoneInfo TimeZone { get; }
public DefAssembly(string patchName, TimeZoneInfo timezone, List<string> excludeTags, IAgent agent)
{
this._patchName = patchName;
this.TimeZone = timezone;
this._excludeTags = excludeTags;
this.Agent = agent;
}
public bool NeedExport(List<string> groups)
{
if (groups.Count == 0)
{
return true;
}
return groups.Any(g => CfgTargetService.Groups.Contains(g));
}
private readonly List<Patch> _patches = new List<Patch>();
private readonly List<Service> _cfgServices = new List<Service>();
private readonly ConcurrentDictionary<string, TableDataInfo> _recordsByTables = new();
public Dictionary<string, DefTable> CfgTables { get; } = new Dictionary<string, DefTable>();
public Patch GetPatch(string name)
{
return _patches.Find(b => b.Name == name);
}
public void AddCfgTable(DefTable table)
{
if (!CfgTables.TryAdd(table.FullName, table))
{
throw new Exception($"table:'{table.FullName}' duplicated");
}
}
public DefTable GetCfgTable(string name)
{
return CfgTables.TryGetValue(name, out var t) ? t : null;
}
public void AddDataTable(DefTable table, List<Record> mainRecords, List<Record> patchRecords)
{
_recordsByTables[table.FullName] = new TableDataInfo(mainRecords, patchRecords);
}
public List<Record> GetTableAllDataList(DefTable table)
{
return _recordsByTables[table.FullName].FinalRecords;
}
public List<Record> GetTableExportDataList(DefTable table)
{
var tableDataInfo = _recordsByTables[table.FullName];
if (_excludeTags.Count == 0)
{
return tableDataInfo.FinalRecords;
}
else
{
var finalRecords = tableDataInfo.FinalRecords.Where(r => r.IsNotFiltered(_excludeTags)).ToList();
if (table.IsOneValueTable && finalRecords.Count != 1)
{
throw new Exception($"配置表 {table.FullName} 是单值表 mode=one,但数据个数:{finalRecords.Count} != 1");
}
return finalRecords;
}
}
public TableDataInfo GetTableDataInfo(DefTable table)
{
return _recordsByTables[table.FullName];
}
public List<DefTable> GetExportTables()
{
return Types.Values.Where(t => t is DefTable ct && ct.NeedExport).Select(t => (DefTable)t).ToList();
}
public List<DefTypeBase> GetExportTypes()
{
var refTypes = new Dictionary<string, DefTypeBase>();
var targetService = CfgTargetService;
foreach (var refType in targetService.Refs)
{
if (!this.Types.ContainsKey(refType))
{
throw new Exception($"service:'{targetService.Name}' ref:'{refType}' 类型不存在");
}
if (!refTypes.TryAdd(refType, this.Types[refType]))
{
throw new Exception($"service:'{targetService.Name}' ref:'{refType}' 重复引用");
}
}
foreach (var e in this.Types)
{
if (!refTypes.ContainsKey(e.Key) && (e.Value is DefEnum))
{
refTypes.Add(e.Key, e.Value);
}
}
foreach (var table in GetExportTables())
{
refTypes[table.FullName] = table;
table.ValueTType.Apply(RefTypeVisitor.Ins, refTypes);
}
return refTypes.Values.ToList();
}
public void Load(string outputService, Defines defines)
{
SupportDatetimeType = true;
TopModule = defines.TopModule;
CfgTargetService = defines.Services.Find(s => s.Name == outputService);
if (CfgTargetService == null)
{
throw new ArgumentException($"service:{outputService} not exists");
}
if (!string.IsNullOrWhiteSpace(_patchName))
{
TargetPatch = defines.Patches.Find(b => b.Name == _patchName);
if (TargetPatch == null)
{
throw new Exception($"patch '{_patchName}' not in valid patch set");
}
}
this._patches.AddRange(defines.Patches);
foreach (var e in defines.Enums)
{
AddType(new DefEnum(e));
}
foreach (var b in defines.Beans)
{
AddType(new DefBean((CfgBean)b));
}
foreach (var p in defines.Tables)
{
var table = new DefTable(p);
AddType(table);
AddCfgTable(table);
}
_cfgServices.AddRange(defines.Services);
foreach (var type in Types.Values)
{
type.AssemblyBase = this;
}
foreach (var type in Types.Values)
{
try
{
s_logger.Trace("precompile type:{0} begin", type.FullName);
type.PreCompile();
s_logger.Trace("precompile type:{0} end", type.FullName);
}
catch (Exception)
{
this.Agent.Error("precompile type:{0} error", type.FullName);
throw;
}
}
foreach (var type in Types.Values)
{
try
{
s_logger.Trace("compile type:{0} begin", type.FullName);
type.Compile();
s_logger.Trace("compile type:{0} end", type.FullName);
}
catch (Exception)
{
this.Agent.Error("compile type:{0} error", type.FullName);
s_logger.Error("compile type:{0} error", type.FullName);
throw;
}
}
foreach (var type in Types.Values)
{
try
{
s_logger.Trace("post compile type:{0} begin", type.FullName);
type.PostCompile();
s_logger.Trace("post compile type:{0} end", type.FullName);
}
catch (Exception)
{
this.Agent.Error("post compile type:{0} error", type.FullName);
s_logger.Error("post compile type:{0} error", type.FullName);
throw;
}
}
// 丑陋. 怎么写更好?
// 递归 设置DefBean及DefField 的 IsMultiRow
MarkMultiRows();
}
public void MarkMultiRows()
{
var multiRowBeans = new HashSet<DefBean>();
for (bool anyMark = true; anyMark;)
{
anyMark = false;
foreach (var type in this.Types.Values)
{
if (type is DefBean beanType && !beanType.IsMultiRow)
{
bool isMultiRows;
if (beanType.IsNotAbstractType)
{
isMultiRows = beanType.HierarchyFields.Any(f => ((DefField)f).ComputeIsMultiRow());
}
else
{
isMultiRows = beanType.HierarchyNotAbstractChildren.Any(c => ((DefBean)c).IsMultiRow);
}
if (isMultiRows)
{
beanType.IsMultiRow = true;
//s_logger.Info("bean:{bean} is multi row", beanType.FullName);
anyMark = true;
}
}
}
}
}
}
}

View File

@ -0,0 +1,181 @@
using Luban.Common.Utils;
using Luban.Job.Cfg.DataCreators;
using Luban.Job.Cfg.Datas;
using Luban.Job.Cfg.RawDefs;
using Luban.Job.Common.Defs;
using Luban.Job.Common.Types;
using Luban.Job.Common.TypeVisitors;
using System;
using System.Collections.Generic;
using System.Linq;
namespace Luban.Job.Cfg.Defs
{
public class DefField : DefFieldBase
{
public DefAssembly Assembly => (DefAssembly)HostType.AssemblyBase;
public bool RawIsMultiRow { get; }
public bool IsMultiRow { get; private set; }
public bool ComputeIsMultiRow()
{
if (IsMultiRow)
{
return true;
}
switch (CType)
{
case TBean b: { return IsMultiRow = ((DefBean)b.Bean).IsMultiRow; }
case TList b: { return IsMultiRow = b.ElementType is TBean b2 && ((DefBean)b2.Bean).IsMultiRow; }
case TArray b: { return IsMultiRow = b.ElementType is TBean b2 && ((DefBean)b2.Bean).IsMultiRow; }
case TMap b: { return IsMultiRow = b.ValueType is TBean b2 && ((DefBean)b2.Bean).IsMultiRow; }
default: return false;
}
}
public string Index { get; }
public List<string> Groups { get; }
public DefField IndexField { get; private set; }
public string Sep { get; set; }
// 如果没有指定sep
// 如果是bean,且指定了sep则使用此值
// 如果是vectorN,使用 ,
public string ActualSep => string.IsNullOrWhiteSpace(Sep) ? (CType is TBean bean ? ((DefBean)bean.Bean).Sep : "") : Sep;
public bool NeedExport => Assembly.NeedExport(this.Groups);
public TEnum Remapper { get; private set; }
public CfgField RawDefine { get; }
public string GetTextKeyName(string name) => name + TText.L10N_FIELD_SUFFIX;
public bool GenTextKey => this.CType is TText;
public string DefaultValue { get; }
public DType DefalutDtypeValue { get; private set; }
public bool IsRowOrient { get; }
public DefField(DefTypeBase host, CfgField f, int idOffset) : base(host, f, idOffset)
{
Index = f.Index;
Sep = f.Sep;
this.IsMultiRow = this.RawIsMultiRow = f.IsMultiRow;
this.Groups = f.Groups;
this.RawDefine = f;
this.DefaultValue = f.DefaultValue;
this.IsRowOrient = f.IsRowOrient;
}
public override void Compile()
{
base.Compile();
if (!string.IsNullOrWhiteSpace(this.DefaultValue))
{
this.DefalutDtypeValue = CType.Apply(StringDataCreator.Ins, this.DefaultValue);
}
switch (CType)
{
case TArray t:
{
if (t.ElementType is TBean e && !e.IsDynamic && e.Bean.HierarchyFields.Count == 0)
{
throw new Exception($"container element type:'{e.Bean.FullName}' can't be empty bean");
}
if (t.ElementType is TText)
{
throw new Exception($"bean:{HostType.FullName} field:{Name} container element type can't text");
}
break;
}
case TList t:
{
if (t.ElementType is TBean e && !e.IsDynamic && e.Bean.HierarchyFields.Count == 0)
{
throw new Exception($"container element type:'{e.Bean.FullName}' can't be empty bean");
}
if (t.ElementType is TText)
{
throw new Exception($"bean:{HostType.FullName} field:{Name} container element type can't text");
}
break;
}
case TSet t:
{
if (t.ElementType is TText)
{
throw new Exception($"bean:{HostType.FullName} field:{Name} container element type can't text");
}
break;
}
case TMap t:
{
if (t.KeyType is TText)
{
throw new Exception($"bean:{HostType.FullName} field:{Name} container key type can't text");
}
if (t.ValueType is TText)
{
throw new Exception($"bean:{HostType.FullName} field:{Name} container value type can't text");
}
break;
}
}
if (IsMultiRow && !CType.IsCollection && !CType.IsBean)
{
throw new Exception($"只有容器类型才支持 multi_line 属性");
}
if (string.IsNullOrEmpty(Sep) && CType is TBean bean)
{
Sep = bean.GetBeanAs<DefBean>().Sep;
}
if (!string.IsNullOrEmpty(Index))
{
if ((CType is TArray tarray) && (tarray.ElementType is TBean b))
{
if ((IndexField = b.GetBeanAs<DefBean>().GetField(Index)) == null)
{
throw new Exception($"type:'{HostType.FullName}' field:'{Name}' index:'{Index}'. index not exist");
}
}
else if ((CType is TList tlist) && (tlist.ElementType is TBean tb))
{
if ((IndexField = tb.GetBeanAs<DefBean>().GetField(Index)) == null)
{
throw new Exception($"type:'{HostType.FullName}' field:'{Name}' index:'{Index}'. index not exist");
}
}
else
{
throw new Exception($"type:'{HostType.FullName}' field:'{Name}' index:'{Index}'. only array:bean or list:bean support index");
}
}
if (!string.IsNullOrEmpty(this.RawDefine.Converter))
{
this.Remapper = AssemblyBase.GetDefTType(HostType.Namespace, this.RawDefine.Converter, this.IsNullable) as TEnum;
if (this.Remapper == null)
{
throw new Exception($"type:'{HostType.FullName}' field:'{Name}' converter:'{this.RawDefine.Converter}' not exists");
}
}
}
}
}

View File

@ -0,0 +1,69 @@
using Luban.Common.Utils;
using Luban.Server.Common;
using System.Collections.Generic;
namespace Luban.Job.Common.Defs
{
public abstract class DefTypeBase
{
public DefAssemblyBase AssemblyBase { get; set; }
public int Id { get; protected set; }
public string TopModule => AssemblyBase.TopModule;
public IAgent Agent => AssemblyBase.Agent;
public string Name { get; set; }
public string Namespace { get; set; }
public string FullName => TypeUtil.MakeFullName(Namespace, Name);
public string NamespaceWithTopModule => TypeUtil.MakeNamespace(AssemblyBase.TopModule, Namespace);
public string FullNameWithTopModule => TypeUtil.MakeFullName(AssemblyBase.TopModule, FullName);
public string JavaFullName => TypeUtil.MakeFullName(Namespace, Name);
public string GoFullName => TypeUtil.MakeGoFullName(Namespace, Name);
public string GoPkgName => TypeUtil.MakeGoPkgName(Namespace);
public string CppNamespaceBegin => TypeUtil.MakeCppNamespaceBegin(Namespace);
public string CppNamespaceEnd => TypeUtil.MakeCppNamespaceEnd(Namespace);
public string CppFullNameWithTopModule => TypeUtil.MakeCppFullName(AssemblyBase.TopModule, FullName);
public string TypescriptNamespaceBegin => TypeUtil.MakeTypescriptNamespaceBegin(Namespace);
public string TypescriptNamespaceEnd => TypeUtil.MakeTypescriptNamespaceEnd(Namespace);
public string CppFullName => TypeUtil.MakeCppFullName(Namespace, Name);
public string PyFullName => TypeUtil.MakePyFullName(Namespace, Name);
public string RustFullName => TypeUtil.MakeRustFullName(Namespace, Name);
public string Comment { get; protected set; }
public Dictionary<string, string> Tags { get; protected set; }
public bool HasTag(string attrName)
{
return Tags != null && Tags.ContainsKey(attrName);
}
public string GetTag(string attrName)
{
return Tags != null && Tags.TryGetValue(attrName, out var value) ? value : null;
}
public virtual void PreCompile() { }
public abstract void Compile();
public virtual void PostCompile() { }
}
}

View File

@ -0,0 +1,28 @@
using Bright.Serialization;
namespace Luban.Common.Protos
{
public class FileInfo : BeanBase
{
public string FilePath { get; set; }
public string MD5 { get; set; }
public override void Serialize(ByteBuf os)
{
os.WriteString(FilePath);
os.WriteString(MD5);
}
public override void Deserialize(ByteBuf os)
{
FilePath = os.ReadString();
MD5 = os.ReadString();
}
public override int GetTypeId()
{
throw new System.NotImplementedException();
}
}
}

View File

@ -0,0 +1,63 @@
using Bright.Serialization;
using System;
using System.Collections.Generic;
namespace Luban.Common.Protos
{
public class GetImportFileOrDirectoryArg : BeanBase
{
public string FileOrDirName { get; set; }
public List<string> InclusiveSuffixs { get; set; } = new List<string>();
public override int GetTypeId()
{
return 0;
}
public override void Serialize(ByteBuf os)
{
os.WriteString(FileOrDirName);
Bright.Common.SerializationUtil.Serialize(os, InclusiveSuffixs);
}
public override void Deserialize(ByteBuf os)
{
FileOrDirName = os.ReadString();
Bright.Common.SerializationUtil.Deserialize(os, InclusiveSuffixs);
}
}
public class GetImportFileOrDirectoryRes : BeanBase
{
public EErrorCode Err { get; set; }
public bool IsFile { get; set; }
public string Md5 { get; set; }
//public byte[] Content { get; set; }
public List<FileInfo> SubFiles { get; set; }
public override int GetTypeId()
{
return 0;
}
public override void Serialize(ByteBuf os)
{
os.WriteInt((int)Err);
os.WriteBool(IsFile);
os.WriteString(Md5);
Bright.Common.SerializationUtil.Serialize(os, SubFiles);
}
public override void Deserialize(ByteBuf os)
{
Err = (EErrorCode)os.ReadInt();
IsFile = os.ReadBool();
Md5 = os.ReadString();
Bright.Common.SerializationUtil.Deserialize(os, SubFiles = new List<FileInfo>());
}
}
}

View File

@ -0,0 +1,122 @@

using Bright.Time;
using Luban.Common.Protos;
using Luban.Common.Utils;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using System.Xml.Linq;
namespace Luban.Server.Common
{
public class LocalAgent : IAgent
{
private static readonly NLog.Logger s_logger = NLog.LogManager.GetCurrentClassLogger();
public LocalAgent()
{
}
public Task<byte[]> ReadAllBytesAsync(string file)
{
return FileUtil.ReadAllBytesAsync(file);
}
public async Task<byte[]> GetFromCacheOrReadAllBytesAsync(string file, string md5)
{
var content = await ReadAllBytesAsync(file).ConfigureAwait(false);
return content;
}
public async Task<GetImportFileOrDirectoryRes> GetFileOrDirectoryAsync(string file, params string[] searchPatterns)
{
long t1 = TimeUtil.NowMillis;
var re = new GetImportFileOrDirectoryRes()
{
SubFiles = new List<Luban.Common.Protos.FileInfo>(),
};
var suffixes = new List<string>(searchPatterns.Select(s => s.Trim()).Where(s => !string.IsNullOrWhiteSpace(s)));
try
{
if (Directory.Exists(file))
{
re.Err = 0;
re.IsFile = false;
foreach (var subFile in Directory.GetFiles(file, "*", SearchOption.AllDirectories))
{
if (FileUtil.IsValidInputFile(subFile) && (suffixes.Count == 0 || suffixes.Any(s => subFile.EndsWith(s))))
{
var md5 = FileUtil.CalcMD5(await FileUtil.ReadAllBytesAsync(subFile));
re.SubFiles.Add(new Luban.Common.Protos.FileInfo() { FilePath = FileUtil.Standardize(subFile), MD5 = md5 });
}
}
}
else if (File.Exists(file))
{
re.IsFile = true;
re.Md5 = FileUtil.CalcMD5(await FileUtil.ReadAllBytesAsync(file));
}
else
{
re.Err = Luban.Common.EErrorCode.FILE_OR_DIR_NOT_EXISTS;
}
}
catch (Exception e)
{
re.Err = Luban.Common.EErrorCode.READ_FILE_FAIL;
s_logger.Error(e);
}
s_logger.Trace(" GetImportFileOrDirectory file:{file} err:{err} cost:{time}", file, re.Err, TimeUtil.NowMillis - t1);
return re;
}
public Task<QueryFilesExistsRes> QueryFileExistsAsync(QueryFilesExistsArg arg)
{
var re = new QueryFilesExistsRes() { Exists = new List<bool>(arg.Files.Count) };
foreach (var f in arg.Files)
{
re.Exists.Add(File.Exists(Path.Combine(arg.Root, f)));
}
return Task.FromResult(re);
}
public async Task<XElement> OpenXmlAsync(string xmlFile)
{
try
{
s_logger.Trace("open {xml}", xmlFile);
return XElement.Load(new MemoryStream(await ReadAllBytesAsync(xmlFile)));
}
catch (Exception e)
{
throw new Exception($"打开定义文件:{xmlFile} 失败 --> {e.Message}");
}
}
#region log
public void Error(string fmt, params object[] objs)
{
Log("error", string.Format(fmt, objs));
}
public void Info(string fmt, params object[] objs)
{
Log("info", string.Format(fmt, objs));
}
private void Log(string level, string content)
{
//Session.Send(new PushLog() { Level = level, LogContent = content });
}
#endregion
}
}

View File

@ -0,0 +1,58 @@
using Bright.Serialization;
using System;
using System.Collections.Generic;
namespace Luban.Common.Protos
{
public class QueryFilesExistsArg : BeanBase
{
public string Root { get; set; }
public List<string> Files { get; set; }
public override int GetTypeId()
{
return 0;
}
public override void Serialize(ByteBuf os)
{
os.WriteString(Root);
Bright.Common.SerializationUtil.Serialize(os, Files);
}
public override void Deserialize(ByteBuf os)
{
Root = os.ReadString();
Bright.Common.SerializationUtil.Deserialize(os, Files = new List<string>());
}
}
public class QueryFilesExistsRes : BeanBase
{
public List<bool> Exists { get; set; }
public override int GetTypeId()
{
return 0;
}
public override void Serialize(ByteBuf os)
{
os.WriteSize(Exists.Count);
foreach (var v in Exists)
{
os.WriteBool(v);
}
}
public override void Deserialize(ByteBuf os)
{
int n = os.ReadSize();
Exists = new List<bool>();
for (int i = 0; i < n; i++)
{
Exists.Add(os.ReadBool());
}
}
}
}

View File

@ -0,0 +1,11 @@
namespace Bright.Serialization
{
public abstract class BeanBase : ITypeId, ISerializable
{
public abstract int GetTypeId();
public abstract void Serialize(ByteBuf os);
public abstract void Deserialize(ByteBuf os);
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,10 @@
namespace Bright.Serialization
{
public enum EDeserializeError
{
OK,
NOT_ENOUGH,
EXCEED_SIZE,
// UNMARSHAL_ERR,
}
}

View File

@ -0,0 +1,42 @@
namespace Bright.Serialization
{
// 把 int,long,string,bool 调整到最小
// 这样 marshal compatible write(field_id << tag_shift | tag_id) < 2^7 能在一个字节
// 内序列化, 优化序列化最终大小
#pragma warning disable CA1720 // 标识符包含类型名称
public static class FieldTag
{
public const int
INT = 0,
LONG = 1,
STRING = 2,
BOOL = 3,
BYTE = 4,
SHORT = 5,
FSHORT = 6,
FINT = 7,
FLONG = 8,
FLOAT = 9,
DOUBLE = 10,
BYTES = 11,
ARRAY = 12,
LIST = 13,
SET = 14,
MAP = 15,
BEAN = 16,
TEXT = 17,
VECTOR2 = 18,
VECTOR3 = 19,
VECTOR4 = 20,
DYNAMIC_BEAN = 21,
NOT_USE = 22;
public const int TAG_SHIFT = 5;
public const int TAG_MASK = (1 << TAG_SHIFT) - 1;
}
#pragma warning restore CA1720 // 标识符包含类型名称
}

View File

@ -0,0 +1,13 @@
namespace Bright.Serialization
{
/// <summary>
/// 非兼容binary序列化
/// </summary>
public interface ISerializable
{
void Serialize(ByteBuf os);
void Deserialize(ByteBuf os);
}
}

View File

@ -0,0 +1,7 @@
namespace Bright.Serialization
{
public interface ITypeId
{
int GetTypeId();
}
}

View File

@ -0,0 +1,24 @@
#define CPU_SUPPORT_MEMORY_NOT_ALIGN //CPU 是否支持读取非对齐内存
using System;
/// <summary>
/// TODO
/// 1. 整理代码
/// 2. 优化序列化 (像这样 data[endPos + 1] = (byte)(x >> 8) 挨个字节赋值总感觉很低效,能优化吗)
/// </summary>
namespace Bright.Serialization
{
public class SerializationException : Exception
{
public SerializationException() { }
public SerializationException(string msg) : base(msg) { }
public SerializationException(string message, Exception innerException) : base(message, innerException)
{
}
}
}

View File

@ -0,0 +1,223 @@
using Bright.Time;
using Luban.Common.Utils;
using Luban.Job.Cfg.DataCreators;
using Luban.Job.Cfg.Datas;
using Luban.Job.Cfg.DataSources;
using Luban.Job.Cfg.Defs;
using Luban.Job.Common.Types;
using Luban.Job.Common.Utils;
using Luban.Server.Common;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
namespace Luban.Job.Cfg.Utils
{
public static class DataLoaderUtil
{
private static readonly NLog.Logger s_logger = NLog.LogManager.GetCurrentClassLogger();
public class InputFileInfo
{
public string MD5 { get; set; }
public string OriginFile { get; set; }
public string ActualFile { get; set; }
public string SheetName { get; set; }
}
public static async Task<List<InputFileInfo>> CollectInputFilesAsync(IAgent agent, IEnumerable<string> files, string dataDir)
{
var collectTasks = new List<Task<List<InputFileInfo>>>();
foreach (var file in files)
{
(var actualFile, var sheetName) = FileUtil.SplitFileAndSheetName(FileUtil.Standardize(file));
var actualFullPath = FileUtil.Combine(dataDir, actualFile);
var originFullPath = FileUtil.Combine(dataDir, file);
//s_logger.Info("== get input file:{file} actualFile:{actual}", file, actualFile);
collectTasks.Add(Task.Run(async () =>
{
var fileOrDirContent = await agent.GetFileOrDirectoryAsync(actualFullPath, DataSourceFactory.validDataSourceSuffixes);
if (fileOrDirContent.IsFile)
{
return new List<InputFileInfo> { new InputFileInfo() { OriginFile = file, ActualFile = actualFullPath, SheetName = sheetName, MD5 = fileOrDirContent.Md5 } };
}
else
{
return fileOrDirContent.SubFiles.Select(f => new InputFileInfo() { OriginFile = f.FilePath, ActualFile = f.FilePath, MD5 = f.MD5 }).ToList();
}
}));
}
var allFiles = new List<InputFileInfo>();
foreach (var t in collectTasks)
{
allFiles.AddRange(await t);
}
return allFiles;
}
//private async Task<List<InputFileInfo>> CollectInputFilesAsync(RemoteAgent agent, DefTable table, string dataDir)
//{
// var collectTasks = new List<Task<List<InputFileInfo>>>();
// foreach (var file in table.InputFiles)
// return CollectInputFilesAsync(agent, table.InputFiles, dataDir)
//}
public static async Task GenerateLoadRecordFromFileTasksAsync(IAgent agent, DefTable table, string dataDir, List<string> inputFiles2, List<Task<List<Record>>> tasks)
{
var inputFileInfos = await CollectInputFilesAsync(agent, inputFiles2, dataDir);
// check cache (table, exporttestdata) -> (list<InputFileInfo>, List<DType>)
// (md5, sheetName,exportTestData) -> (value_type, List<DType>)
foreach (var file in inputFileInfos)
{
var actualFile = file.ActualFile;
//s_logger.Info("== get input file:{file} actualFile:{actual}", file, actualFile);
tasks.Add(Task.Run(async () =>
{
var res = LoadCfgRecords(table.ValueTType,
file.OriginFile,
file.SheetName,
await agent.GetFromCacheOrReadAllBytesAsync(file.ActualFile, file.MD5),
FileUtil.IsExcelFile(file.ActualFile));
return res;
}));
}
}
public static async Task LoadTableAsync(IAgent agent, DefTable table, string dataDir, string patchName, string patchDataDir)
{
var mainLoadTasks = new List<Task<List<Record>>>();
var mainGenerateTask = GenerateLoadRecordFromFileTasksAsync(agent, table, dataDir, table.InputFiles, mainLoadTasks);
var patchLoadTasks = new List<Task<List<Record>>>();
Task patchGenerateTask = null;
if (!string.IsNullOrWhiteSpace(patchName))
{
var patchInputFiles = table.GetPatchInputFiles(patchName);
if (patchInputFiles != null)
{
patchGenerateTask = GenerateLoadRecordFromFileTasksAsync(agent, table, patchDataDir, patchInputFiles, patchLoadTasks);
}
}
await mainGenerateTask;
var mainRecords = new List<Record>(256);
foreach (var task in mainLoadTasks)
{
mainRecords.AddRange(await task);
}
s_logger.Trace("== load main records. count:{count}", mainRecords.Count);
List<Record> patchRecords = null;
if (patchGenerateTask != null)
{
patchRecords = new List<Record>(64);
await patchGenerateTask;
foreach (var task in patchLoadTasks)
{
patchRecords.AddRange(await task);
}
s_logger.Trace("== load patch records. count:{count}", patchRecords.Count);
}
table.Assembly.AddDataTable(table, mainRecords, patchRecords);
s_logger.Trace("table:{name} record num:{num}", table.FullName, mainRecords.Count);
}
public static async Task LoadCfgDataAsync(IAgent agent, DefAssembly ass, string dataDir, string patchName, string patchDataDir)
{
var ctx = agent;
List<DefTable> exportTables = ass.Types.Values.Where(t => t is DefTable ct && ct.NeedExport).Select(t => (DefTable)t).ToList();
var genDataTasks = new List<Task>();
var outputDataFiles = new ConcurrentBag<FileInfo>();
long genDataStartTime = TimeUtil.NowMillis;
foreach (DefTable c in exportTables)
{
var table = c;
genDataTasks.Add(Task.Run(async () =>
{
long beginTime = TimeUtil.NowMillis;
await LoadTableAsync(agent, table, dataDir, patchName, patchDataDir);
long endTime = TimeUtil.NowMillis;
if (endTime - beginTime > 100)
{
ctx.Info("====== load {0} cost {1} ms ======", table.FullName, (endTime - beginTime));
}
}));
}
await Task.WhenAll(genDataTasks.ToArray());
}
public static List<Record> LoadCfgRecords(TBean recordType, string originFile, string sheetName, byte[] content, bool multiRecord)
{
// (md5,sheet,multiRecord,exportTestData) -> (valuetype, List<(datas)>)
var dataSource = DataSourceFactory.Create(originFile, sheetName, new MemoryStream(content));
try
{
if (multiRecord)
{
return dataSource.ReadMulti(recordType);
}
else
{
Record record = dataSource.ReadOne(recordType);
return record != null ? new List<Record> { record } : new List<Record>();
}
}
catch (DataCreateException dce)
{
if (string.IsNullOrWhiteSpace(dce.OriginDataLocation))
{
dce.OriginDataLocation = originFile;
}
throw;
}
catch (Exception e)
{
throw new Exception($"配置文件:{originFile} 生成失败.", e);
}
}
#if !LUBAN_ASSISTANT
public static async Task LoadTextTablesAsync(IAgent agent, DefAssembly ass, string baseDir, string textTableFiles)
{
var tasks = new List<Task<byte[]>>();
var files = textTableFiles.Split(',');
foreach (var file in await CollectInputFilesAsync(agent, files, baseDir))
{
tasks.Add(agent.GetFromCacheOrReadAllBytesAsync(file.ActualFile, file.MD5));
}
var textTable = ass.ExportTextTable;
for (int i = 0; i < tasks.Count; i++)
{
var bytes = await tasks[i];
try
{
textTable.LoadFromFile(files[i], bytes);
}
catch (Exception e)
{
throw new Exception($"load text table file:{files[i]} fail", e);
}
}
}
#endif
}
}

View File

@ -6,6 +6,7 @@ using System.Xml.Linq;
using Excel = Microsoft.Office.Interop.Excel;
using Office = Microsoft.Office.Core;
using Microsoft.Office.Tools.Excel;
using Microsoft.Office.Tools.Ribbon;
namespace LubanAssistant
{
@ -19,6 +20,17 @@ namespace LubanAssistant
{
}
//protected override Microsoft.Office.Core.IRibbonExtensibility CreateRibbonExtensibilityObject()
//{
// return new ToolTab();
//}
protected override IRibbonExtension[] CreateRibbonObjects()
{
return new IRibbonExtension[] { new AssistantTab() };
}
#region VSTO 生成的代码
/// <summary>
@ -30,7 +42,7 @@ namespace LubanAssistant
this.Startup += new System.EventHandler(ThisAddIn_Startup);
this.Shutdown += new System.EventHandler(ThisAddIn_Shutdown);
}
#endregion
}
}

View File

@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<configSections>
<sectionGroup name="userSettings" type="System.Configuration.UserSettingsGroup, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<section name="LubanAssistant.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" allowExeDefinition="MachineToLocalUser" requirePermission="false" />
</sectionGroup>
</configSections>
<userSettings>
<LubanAssistant.Properties.Settings>
<setting name="rootDefineFile" serializeAs="String">
<value />
</setting>
</LubanAssistant.Properties.Settings>
</userSettings>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="System.Runtime.CompilerServices.Unsafe" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-5.0.0.0" newVersion="5.0.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Threading.Tasks.Extensions" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.2.0.1" newVersion="4.2.0.1" />
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>

View File

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="CommandLineParser" version="2.8.0" targetFramework="net472" />
<package id="ExcelDataReader" version="3.6.0" targetFramework="net472" />
<package id="Microsoft.Bcl.AsyncInterfaces" version="5.0.0" targetFramework="net472" />
<package id="Microsoft.CSharp" version="4.7.0" targetFramework="net472" />
<package id="NeoLua" version="1.3.13" targetFramework="net472" />
<package id="NLog" version="4.7.11" targetFramework="net472" />
<package id="Scriban" version="4.1.0" targetFramework="net472" />
<package id="System.Buffers" version="4.5.1" targetFramework="net472" />
<package id="System.Memory" version="4.5.4" targetFramework="net472" />
<package id="System.Numerics.Vectors" version="4.5.0" targetFramework="net472" />
<package id="System.Runtime.CompilerServices.Unsafe" version="5.0.0" targetFramework="net472" />
<package id="System.Runtime.Numerics" version="4.3.0" targetFramework="net472" />
<package id="System.Text.Encodings.Web" version="5.0.1" targetFramework="net472" />
<package id="System.Text.Json" version="5.0.2" targetFramework="net472" />
<package id="System.Threading.Tasks.Extensions" version="4.5.4" targetFramework="net472" />
<package id="System.ValueTuple" version="4.5.0" targetFramework="net472" />
<package id="YamlDotNet" version="11.2.1" targetFramework="net472" />
</packages>