Skip to main content
Version: Next

Best Practices

Naming Conventions

  • table.name recommends the TbXxxYyy class style, which is easy to distinguish between tables and ordinary bean types
  • bean.var.name recommends the xx_yy_zz style. When generating, it will automatically generate a suitable variable name according to the target language, such as XxYyZz under c#; xxYyZz under java.

Adjust the naming convention of the generated code

The default is to generate the name according to the recommended style of each language, for example, xxxx_yyyy is XxxxYyyy under c#. Sometimes you want to tweak this naming style. For example, using the original form, you can achieve this with the parameter --naming_convention:bean_member none .

For more information, please refer to the documentation in Command Tool

Flexible selection of xml and excel definitions

  • For those with high aesthetic requirements, those who are used to handwriting table definitions like protobuf can complete the table definition in xml
  • Pragmatism, convenient for planning and editing, table definition can be completely completed in excel
  • The above two can be mixed appropriately

If you use xml definition, it is recommended that each module corresponds to an xml file, and has an independent module name, which is convenient for management and search.

Luban.Server or Luban.ClientServer

Luban.Server needs to be deployed, which may be troublesome for novices, but the advantage is that the generation time can be greatly shortened by using the cache. In addition, when updating Luban, you don’t need to update tools. It is recommended to deploy Luban.Server for projects with conditions (use docker to deploy In fact, it is very simple with just one line of command, see Command Line.

For small and medium-sized projects, Luban.ClientServer can also be used directly to save trouble.

Modularity

It is strongly recommended to manage the configuration by module, each module has a directory, and put all the configurations of the module under this directory.

When defining tables and structures, it is also recommended to add a suitable module name, such as item.TbItem, item.ItemInfo, instead of an empty module.

export format

It is recommended to use the json version of the corresponding language during the development period, so that the server or client will not be republished frequently due to changes in the configuration format

Elegantly configure data with complex structures in excel

Cooperate with multi-line record + multi-level field column name + sep mechanism (field sep, and type sep mechanism), flexibly choose column limitation mode and streaming mode, and configure complex data concisely. If you have any difficulties, you can consult in the group.

Use OOP type inheritance to define complex GamePlay data in the game

Flexible use of OOP type inheritance to define complex GamePlay data such as skills, BUFF, AI, copies, etc. Choose excel or json data to fill in as appropriate these complex data. Never use the traditional type + param1, param2, param3 combination to express complex data structures, which is not friendly to planning and programming, and it is difficult to check for errors.

Use githooks to check the legality of the data before planning to submit the planning configuration

Refer to githubs-demo

Luban.Client and Luban.ClientServer provide watch generation mechanism. Use the parameter -w dir1,dir2,.. to automatically regenerate when the corresponding directory changes. For example, an example script is as follows, which automatically triggers a rebuild when the definition or configuration directory changes.

%GEN_CLIENT% -h %LUBAN_SERVER_IP% -j cfg -w %CONF_ROOT%\Datas,%CONF_ROOT%\Defines --^
-d %DEFINE_FILE%^
--input_data_dir %CONF_ROOT%\Datas ^
--output_code_dir TsScripts/src/Gen/Cfg ^
--output_data_dir Assets\StreamingAssets\ConfigData^
--gen_types code_typescript_json,data_json^
-s client

planning check configuration script recommends adding --generateonly parameter

Note that this parameter is a parameter of Luban.Client and must be added before -- . After adding this parameter, Luban.Server will still generate data, but Luban.Client will not download the generated results. The time can be shortened further.

A sample script is as follows

%LUBAN_CLIENT% -j cfg --generateonly -- ^
--input_data_dir %DATA_DIR^ ^
--...
--...

##refgroup

If many fields ref the same batch of tables, you can use refgroup for easy reference.

The data generated by the editor uses the json data format

It is recommended to save the complex configuration data generated by the editor as json data, and place a file for each record point in the directory. Set table.input to that directory. Luban supports generating codes that record loading and saving from json, don't write this serialization yourself!

Use tags to identify test and development data

Use tag to mark those test and development period data, and use --output:exclude_tags tag1,tag2,... to filter these data when it is officially released. Don't change it yourself!

Use tag unchecked to identify unchecked records

Some data is temporarily produced in batches, and many reference values are illegal, but they are not used by the program for the time being, and a large number of warnings are printed due to ref failure during generation. You can add unchecked tags to these records, and luban will not check these data.

Use datetime to represent time

Use datetime to mark the time, pay attention to use it with the time zone parameter.

Polymorphic type usage occasions

  • Recommended for occasions with variable types, especially GamePlay data, such as skills, AI, tasks, copies, etc.
  • Simple ones can be configured in excel, and more complex ones, especially skills that need to be edited in an independent skill editor, are recommended to save data in json format

Use polymorphic types in code

Assume the following polymorphic types:

public abstract class Shape : BeanBase
{
// xxxx
}

public class Triangle : Shape
{
float a;
float b;
float c;
}

public class Circle : Shape
{
float radius;
}

public class Rectangle : Shape
{
float width;
float height;
}

Suppose there is a Shape field shape in the configuration. In the actual logic code, it should be handled differently according to its actual type. There are three common ways of writing. When the number of types is small, all three methods can be selected according to personal preference. When the number of types is large, it is recommended to follow method 3, which is more efficient.

method 1

     if (shape is Circle c)
{
// xxx
}
else if(shape is Triangle t)
{
// xxx
}
else if(shape is Rectangle r)
{
// xxx
}

Method 2

switch(shape)
{
case Circle c:
{
// xxx;
break;
}
case Triangle t:
{
// xxx
break;
}
case Rectangle r:
{
// xxx;
break;
}
}

Method 3

switch(shape. GetTypeId())
{
case Circle::__ID__:
{
Circle c = (Circle)shape;
// xxx;
break;
}
case Triangle::__ID__:
{
Triangle t = (Triangle)shape;
// xxx
break;
}
case Rectangle::__ID__:
{
Rectangle r = (Rectangle)shape;
// xxx;
break;
}
}