ref[csharp]: refactor generate csharp protocol

This commit is contained in:
godotg committed 2024-05-22 15:40:36 +08:00
1 parent 770679af26
commit 5ab61d6562
20 files changed
+396 -218

No files matched your search

@@ -92,7 +92,7 @@ public class PacketService implements IPacketService {
var protocolLocation = netConfig.getProtocolLocation();
var generateOperation = new GenerateOperation();
generateOperation.setOneProtocol(netConfig.isOneProtocol());
generateOperation.setMergeProtocol(netConfig.isOneProtocol());
generateOperation.setFoldProtocol(netConfig.isFoldProtocol());
generateOperation.setProtocolPath(netConfig.getProtocolPath());
generateOperation.setProtocolParam(netConfig.getProtocolParam());
@@ -34,10 +34,10 @@ public class GenerateOperation {
public static final GenerateOperation NO_OPERATION = new GenerateOperation();
/**
* EN: All protocol files are generated in a single protocol file.
* CN: 所有的协议文件生成在一个协议文件里
* EN: Generate one protocol file under a package
* CN: 将一个包下的协议文件生成在一个协议文件里
*/
private boolean oneProtocol;
private boolean mergeProtocol;
/**
* EN: Fold the protocol. The generated protocol file will maintain the same directory structure as the Java source file.
@@ -72,12 +72,12 @@ public class GenerateOperation {
this.protocolPath = protocolPath;
}
public boolean isOneProtocol() {
return oneProtocol;
public boolean isMergeProtocol() {
return mergeProtocol;
}
public void setOneProtocol(boolean oneProtocol) {
this.oneProtocol = oneProtocol;
public void setMergeProtocol(boolean mergeProtocol) {
this.mergeProtocol = mergeProtocol;
}
public boolean isFoldProtocol() {
@@ -19,7 +19,6 @@ import com.zfoo.protocol.registration.ProtocolAnalysis;
import com.zfoo.protocol.registration.ProtocolRegistration;
import com.zfoo.protocol.serializer.CodeLanguage;
import com.zfoo.protocol.serializer.cpp.GenerateCppUtils;
import com.zfoo.protocol.serializer.csharp.GenerateCsUtils;
import com.zfoo.protocol.serializer.es.GenerateEsUtils;
import com.zfoo.protocol.serializer.gdscript.GenerateGdUtils;
import com.zfoo.protocol.serializer.go.GenerateGoUtils;
@@ -28,6 +27,7 @@ import com.zfoo.protocol.serializer.lua.GenerateLuaUtils;
import com.zfoo.protocol.serializer.python.GeneratePyUtils;
import com.zfoo.protocol.serializer.typescript.GenerateTsUtils;
import com.zfoo.protocol.util.FileUtils;
import com.zfoo.protocol.util.ReflectionUtils;
import com.zfoo.protocol.util.StringUtils;
import java.io.IOException;
@@ -116,25 +116,21 @@ public abstract class GenerateProtocolFile {
allGenerateProtocols.addAll(insideGenerateProtocols);
// 通过协议号,从小到大排序
var allSortedGenerateProtocols = allGenerateProtocols.stream()
var generateProtocols = allGenerateProtocols.stream()
.sorted((a, b) -> a.protocolId() - b.protocolId())
.toList();
// 解析协议的文档注释
GenerateProtocolNote.initProtocolNote(allSortedGenerateProtocols);
GenerateProtocolNote.initProtocolNote(generateProtocols);
// 计算协议生成的路径
if (generateOperation.isFoldProtocol()) {
GenerateProtocolPath.initProtocolPath(allSortedGenerateProtocols);
}
GenerateProtocolPath.initProtocolPath(generateProtocols);
// 生成C++协议
var generateLanguages = generateOperation.getGenerateLanguages();
if (generateLanguages.contains(CodeLanguage.Cpp)) {
GenerateCppUtils.init(generateOperation);
GenerateCppUtils.createProtocolManager(allSortedGenerateProtocols);
for (var protocolRegistration : allSortedGenerateProtocols) {
GenerateCppUtils.createProtocolManager(generateProtocols);
for (var protocolRegistration : generateProtocols) {
GenerateCppUtils.createCppProtocolFile((ProtocolRegistration) protocolRegistration);
}
}
@@ -142,57 +138,49 @@ public abstract class GenerateProtocolFile {
// 生成Golang协议
if (generateLanguages.contains(CodeLanguage.Go)) {
GenerateGoUtils.init(generateOperation);
GenerateGoUtils.createProtocolManager(allSortedGenerateProtocols);
for (var protocolRegistration : allSortedGenerateProtocols) {
GenerateGoUtils.createProtocolManager(generateProtocols);
for (var protocolRegistration : generateProtocols) {
GenerateGoUtils.createGoProtocolFile((ProtocolRegistration) protocolRegistration);
}
}
// 生成C#协议
if (generateLanguages.contains(CodeLanguage.CSharp)) {
GenerateCsUtils.init(generateOperation);
GenerateCsUtils.createProtocolManager(allSortedGenerateProtocols);
for (var protocolRegistration : allSortedGenerateProtocols) {
GenerateCsUtils.createCsProtocolFile((ProtocolRegistration) protocolRegistration);
}
}
// 生成Javascript协议
if (generateLanguages.contains(CodeLanguage.JavaScript)) {
GenerateJsUtils.init(generateOperation);
for (var protocolRegistration : allSortedGenerateProtocols) {
for (var protocolRegistration : generateProtocols) {
GenerateJsUtils.createJsProtocolFile((ProtocolRegistration) protocolRegistration);
}
GenerateJsUtils.createProtocolManager(allSortedGenerateProtocols);
GenerateJsUtils.createProtocolManager(generateProtocols);
}
// 生成Javascript协议
if (generateLanguages.contains(CodeLanguage.ES)) {
GenerateEsUtils.init(generateOperation);
for (var protocolRegistration : allSortedGenerateProtocols) {
for (var protocolRegistration : generateProtocols) {
GenerateEsUtils.createEsProtocolFile((ProtocolRegistration) protocolRegistration);
}
GenerateEsUtils.createProtocolManager(allSortedGenerateProtocols);
GenerateEsUtils.createProtocolManager(generateProtocols);
}
// 生成TypeScript协议
if (generateLanguages.contains(CodeLanguage.TypeScript)) {
GenerateTsUtils.init(generateOperation);
for (var protocolRegistration : allSortedGenerateProtocols) {
for (var protocolRegistration : generateProtocols) {
GenerateTsUtils.createTsProtocolFile((ProtocolRegistration) protocolRegistration);
}
GenerateTsUtils.createProtocolManager(allSortedGenerateProtocols);
GenerateTsUtils.createProtocolManager(generateProtocols);
}
// 生成Lua协议
if (generateLanguages.contains(CodeLanguage.Lua)) {
GenerateLuaUtils.init(generateOperation);
if (generateOperation.isOneProtocol()) {
GenerateLuaUtils.createProtocolManagerInOneFile(allSortedGenerateProtocols);
GenerateLuaUtils.createLuaProtocolsInOneFile(allSortedGenerateProtocols);
if (generateOperation.isMergeProtocol()) {
GenerateLuaUtils.createProtocolManagerInOneFile(generateProtocols);
GenerateLuaUtils.createLuaProtocolsInOneFile(generateProtocols);
} else {
GenerateLuaUtils.createProtocolManager(allSortedGenerateProtocols);
for (var protocolRegistration : allSortedGenerateProtocols) {
GenerateLuaUtils.createProtocolManager(generateProtocols);
for (var protocolRegistration : generateProtocols) {
GenerateLuaUtils.createLuaProtocolFile((ProtocolRegistration) protocolRegistration);
}
}
@@ -201,8 +189,8 @@ public abstract class GenerateProtocolFile {
// 生成GdScript协议
if (generateLanguages.contains(CodeLanguage.GdScript)) {
GenerateGdUtils.init(generateOperation);
GenerateGdUtils.createProtocolManager(allSortedGenerateProtocols);
for (var protocolRegistration : allSortedGenerateProtocols) {
GenerateGdUtils.createProtocolManager(generateProtocols);
for (var protocolRegistration : generateProtocols) {
GenerateGdUtils.createGdProtocolFile((ProtocolRegistration) protocolRegistration);
}
}
@@ -210,12 +198,23 @@ public abstract class GenerateProtocolFile {
// 生成Python协议
if (generateLanguages.contains(CodeLanguage.Python)) {
GeneratePyUtils.init(generateOperation);
GeneratePyUtils.createProtocolManager(allSortedGenerateProtocols);
for (var protocolRegistration : allSortedGenerateProtocols) {
GeneratePyUtils.createProtocolManager(generateProtocols);
for (var protocolRegistration : generateProtocols) {
GeneratePyUtils.createPyProtocolFile((ProtocolRegistration) protocolRegistration);
}
}
for (var language : generateOperation.getGenerateLanguages()) {
var codeGenerate = ReflectionUtils.newInstance(language.codeGenerateClass);
codeGenerate.init(generateOperation);
if (generateOperation.isMergeProtocol()) {
codeGenerate.mergerProtocol(generateProtocols);
} else if (generateOperation.isFoldProtocol()) {
codeGenerate.foldProtocol(generateProtocols);
} else {
codeGenerate.defaultProtocol(generateProtocols);
}
}
// 预留参数,以后可能会用,比如给Lua修改一个后缀名称
var protocolParam = generateOperation.getProtocolParam();
@@ -57,6 +57,15 @@ public abstract class GenerateProtocolNote {
protocolNoteMap = null;
}
public static String protocol_note(short protocolId, CodeLanguage codeLanguage) {
var protocolNote = protocolNoteMap.get(protocolId);
var classNote = protocolNote.getKey();
if (StringUtils.isBlank(classNote)) {
return StringUtils.EMPTY;
}
return formatNote(codeLanguage, classNote);
}
public static String classNote(short protocolId, CodeLanguage language, String tab, int deep) {
var protocolNote = protocolNoteMap.get(protocolId);
var classNote = protocolNote.getKey();
@@ -88,7 +97,7 @@ public abstract class GenerateProtocolNote {
return notes;
}
private static String formatNote(CodeLanguage language, String fieldNote) {
private static String formatNote(CodeLanguage language, String note) {
switch (language) {
case Cpp:
case Go:
@@ -97,20 +106,20 @@ public abstract class GenerateProtocolNote {
case TypeScript:
case CSharp:
case Protobuf:
fieldNote = StringUtils.format("// {}", fieldNote);
note = StringUtils.format("// {}", note);
break;
case Lua:
fieldNote = StringUtils.format("-- {}", fieldNote);
note = StringUtils.format("-- {}", note);
break;
case Python:
case GdScript:
fieldNote = StringUtils.format("# {}", fieldNote);
note = StringUtils.format("# {}", note);
break;
case Enhance:
default:
throw new RunException("unrecognized enum type [{}]", language);
}
return fieldNote;
return note;
}
public static void initProtocolNote(List<IProtocolRegistration> protocolRegistrations) {
@@ -134,16 +134,22 @@ public abstract class GenerateProtocolPath {
return builder.toString();
}
public static Map<String, Set<Short>> getOneProtocolPathMap() {
var oneProtocolMap = new HashMap<String, Set<Short>>();
for(var entry : protocolPathMap.entrySet()) {
var protocolId = entry.getKey();
var path = entry.getValue();
oneProtocolMap.computeIfAbsent(path, it -> new HashSet<>()).add(protocolId);
}
return oneProtocolMap;
}
/**
* 解析协议的路径
*
* @param protocolRegistrations 需要解析的路径
*/
public static void initProtocolPath(List<IProtocolRegistration> protocolRegistrations) {
AssertionUtils.notNull(protocolPathMap
, "[{}]The initialization has been completed. Get Protocol Path cannot be called after the initialization is completed."
, GenerateProtocolPath.class.getSimpleName());
// 将需要生成的协议的路径添加到多叉树中
var protocolPathTree = new GeneralTree<IProtocolRegistration>();
protocolRegistrations.forEach(it -> protocolPathTree.addNode(it.protocolConstructor().getDeclaringClass().getCanonicalName(), it));
@@ -156,23 +162,23 @@ public abstract class GenerateProtocolPath {
var queue = new LinkedList<>(rootTreeNode.getChildren());
while (!queue.isEmpty()) {
var childTreeNode = queue.poll();
var childChildren = childTreeNode.getChildren();
var treeNode = queue.poll();
var childChildren = treeNode.getChildren();
// 如果子节点为空,则以当前节点为路径
if (CollectionUtils.isEmpty(childChildren)) {
toProtocolPath(childTreeNode);
toProtocolPath(treeNode);
continue;
}
// 如果子节点的协议数据有一个不为空的,则以当前节点为路径
if (childChildren.stream().anyMatch(it -> it.getData() != null)) {
toProtocolPath(childTreeNode);
toProtocolPath(treeNode);
continue;
}
// 继续深度便利子节点的路径
for (var subClassId : childTreeNode.getChildren()) {
queue.offer(subClassId);
for (var child : childChildren) {
queue.offer(child);
}
}
}
@@ -26,7 +26,6 @@ import com.zfoo.protocol.generate.GenerateProtocolNote;
import com.zfoo.protocol.generate.GenerateProtocolPath;
import com.zfoo.protocol.registration.field.*;
import com.zfoo.protocol.serializer.cpp.GenerateCppUtils;
import com.zfoo.protocol.serializer.csharp.GenerateCsUtils;
import com.zfoo.protocol.serializer.gdscript.GenerateGdUtils;
import com.zfoo.protocol.serializer.go.GenerateGoUtils;
import com.zfoo.protocol.serializer.javascript.GenerateJsUtils;
@@ -403,7 +402,6 @@ public class ProtocolAnalysis {
GenerateProtocolFile.clear();
GenerateCppUtils.clear();
GenerateGoUtils.clear();
GenerateCsUtils.clear();
GenerateJsUtils.clear();
GenerateTsUtils.clear();
GenerateLuaUtils.clear();
@@ -12,6 +12,8 @@
package com.zfoo.protocol.serializer;
import com.zfoo.protocol.serializer.csharp.CodeGenerateCsharp;
/**
* @author godotg
*/
@@ -20,32 +22,34 @@ public enum CodeLanguage {
/**
* Javassist字节码增强
*/
Enhance(1),
Enhance(1, null),
Cpp(1 << 1),
Cpp(1 << 1, null),
Go(1 << 2),
Go(1 << 2, null),
JavaScript(1 << 3),
JavaScript(1 << 3, null),
ES(1 << 4),
ES(1 << 4, null),
TypeScript(1 << 5),
TypeScript(1 << 5, null),
Lua(1 << 10),
Lua(1 << 10, null),
CSharp(1 << 11),
CSharp(1 << 11, CodeGenerateCsharp.class),
GdScript(1 << 12),
GdScript(1 << 12, null),
Python(1 << 13),
Python(1 << 13, null),
Protobuf(1 << 30);
Protobuf(1 << 30, null);
public final int id;
public final Class<? extends ICodeGenerate> codeGenerateClass;
private CodeLanguage(int id) {
private CodeLanguage(int id, Class<? extends ICodeGenerate> codeGenerateClass) {
this.id = id;
this.codeGenerateClass = codeGenerateClass;
}
}
@@ -0,0 +1,86 @@
/*
* Copyright (C) 2020 The zfoo Authors
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and limitations under the License.
*/
package com.zfoo.protocol.serializer;
import com.zfoo.protocol.util.FileUtils;
import com.zfoo.protocol.util.StringUtils;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Map;
/**
* @author godotg
*/
public enum CodeTemplatePlaceholder {
protocol_class("${protocol_class}"),
protocol_registration("${protocol_registration}"),
protocol_manager_registrations("${protocol_manager_registrations}"),
protocol_note("${protocol_note}"),
protocol_name("${protocol_name}"),
protocol_id("${protocol_id}"),
protocol_field_definition("${protocol_field_definition}"),
protocol_write_serialization("${protocol_write_serialization}"),
protocol_read_deserialization("${protocol_read_deserialization}"),
;
public final String placeholder;
private CodeTemplatePlaceholder(String placeholder) {
this.placeholder = placeholder;
}
public static String formatTemplate(String template, Map<CodeTemplatePlaceholder, String> placeholderMap) {
var lines = template.split(FileUtils.LS_REGEX);
var formatLines = new ArrayList<String>();
for (var line : lines) {
var lineTrim = StringUtils.trim(line);
var startPlaceholderOptional = Arrays.stream(CodeTemplatePlaceholder.values())
.filter(it -> lineTrim.startsWith(it.placeholder))
.findAny();
var formatLine = line;
if (startPlaceholderOptional.isPresent()) {
var startPlaceholder = startPlaceholderOptional.get();
// calculate the tab length
var startSpace = StringUtils.substringBeforeFirst(line, startPlaceholder.placeholder);
var startPlaceholderValue = placeholderMap.get(startPlaceholder);
var startPlaceholderValueLines = Arrays.stream(startPlaceholderValue.split(FileUtils.LS_REGEX)).map(it -> startSpace + it).toList();
// add tab length to start placeholder
var newStartPlaceholderValue = StringUtils.joinWith(FileUtils.LS, startPlaceholderValueLines.toArray());
formatLine = newStartPlaceholderValue + StringUtils.substringAfterFirst(line, startPlaceholder.placeholder);
}
for (var codeTemplatePlaceholder : CodeTemplatePlaceholder.values()) {
if (formatLine.contains(codeTemplatePlaceholder.placeholder)) {
formatLine = formatLine.replace(codeTemplatePlaceholder.placeholder, placeholderMap.get(codeTemplatePlaceholder));
}
}
formatLines.add(formatLine);
}
return StringUtils.joinWith(FileUtils.LS, formatLines.toArray());
}
}
@@ -0,0 +1,22 @@
package com.zfoo.protocol.serializer;
import com.zfoo.protocol.generate.GenerateOperation;
import com.zfoo.protocol.registration.IProtocolRegistration;
import java.io.IOException;
import java.util.List;
/**
* @author godotg
*/
public interface ICodeGenerate {
void init(GenerateOperation generateOperation);
void mergerProtocol(List<IProtocolRegistration> registrations) throws IOException;
void foldProtocol(List<IProtocolRegistration> registrations) throws IOException;
void defaultProtocol(List<IProtocolRegistration> registrations) throws IOException;
}
@@ -13,16 +13,18 @@
package com.zfoo.protocol.serializer.csharp;
import com.zfoo.protocol.ProtocolManager;
import com.zfoo.protocol.anno.Compatible;
import com.zfoo.protocol.generate.GenerateOperation;
import com.zfoo.protocol.generate.GenerateProtocolFile;
import com.zfoo.protocol.generate.GenerateProtocolNote;
import com.zfoo.protocol.generate.GenerateProtocolPath;
import com.zfoo.protocol.model.Pair;
import com.zfoo.protocol.registration.IProtocolRegistration;
import com.zfoo.protocol.registration.ProtocolRegistration;
import com.zfoo.protocol.registration.field.IFieldRegistration;
import com.zfoo.protocol.serializer.CodeLanguage;
import com.zfoo.protocol.serializer.CodeTemplatePlaceholder;
import com.zfoo.protocol.serializer.ICodeGenerate;
import com.zfoo.protocol.serializer.reflect.*;
import com.zfoo.protocol.util.ClassUtils;
import com.zfoo.protocol.util.FileUtils;
@@ -33,35 +35,34 @@ import org.slf4j.LoggerFactory;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static com.zfoo.protocol.util.FileUtils.LS;
import static com.zfoo.protocol.util.StringUtils.TAB;
/**
* @author godotg
*/
public abstract class GenerateCsUtils {
private static final Logger logger = LoggerFactory.getLogger(GenerateCsUtils.class);
public class CodeGenerateCsharp implements ICodeGenerate {
private static final Logger logger = LoggerFactory.getLogger(CodeGenerateCsharp.class);
// custom configuration
public static String protocolOutputRootPath = "zfoocs";
private static String protocolOutputPath = StringUtils.EMPTY;
private static Map<ISerializer, ICsSerializer> csSerializerMap;
private static final Map<ISerializer, ICsSerializer> csSerializerMap = new HashMap<>();
public static ICsSerializer csSerializer(ISerializer serializer) {
return csSerializerMap.get(serializer);
}
public static void init(GenerateOperation generateOperation) {
@Override
public void init(GenerateOperation generateOperation) {
protocolOutputPath = FileUtils.joinPath(generateOperation.getProtocolPath(), protocolOutputRootPath);
FileUtils.deleteFile(new File(protocolOutputPath));
csSerializerMap = new HashMap<>();
csSerializerMap.put(BooleanSerializer.INSTANCE, new CsBooleanSerializer());
csSerializerMap.put(ByteSerializer.INSTANCE, new CsByteSerializer());
csSerializerMap.put(ShortSerializer.INSTANCE, new CsShortSerializer());
@@ -77,16 +78,82 @@ public abstract class GenerateCsUtils {
csSerializerMap.put(ObjectProtocolSerializer.INSTANCE, new CsObjectProtocolSerializer());
}
public static void clear() {
csSerializerMap = null;
protocolOutputRootPath = null;
protocolOutputPath = null;
@Override
public void mergerProtocol(List<IProtocolRegistration> registrations) throws IOException {
createProtocolManagerFile(registrations);
var oneProtocolPathMap = GenerateProtocolPath.getOneProtocolPathMap();
for (var entry : oneProtocolPathMap.entrySet()) {
var path = entry.getKey();
var protocolIds = entry.getValue().stream().sorted().toList();
var protocolBuilder = new StringBuilder();
var protocolRegistrationBuilder = new StringBuilder();
for (var protocolId : protocolIds) {
GenerateProtocolFile.index.set(0);
var registration = (ProtocolRegistration) ProtocolManager.getProtocol(protocolId);
var protocolClazzName = registration.protocolConstructor().getDeclaringClass().getSimpleName();
// protocol
var protocolClassTemplate = ClassUtils.getFileFromClassPathToString("csharp/ProtocolClassTemplate.cs");
var placeholderMap = Map.of(
CodeTemplatePlaceholder.protocol_note, GenerateProtocolNote.protocol_note(protocolId, CodeLanguage.CSharp)
, CodeTemplatePlaceholder.protocol_name, protocolClazzName
, CodeTemplatePlaceholder.protocol_id, String.valueOf(protocolId)
, CodeTemplatePlaceholder.protocol_field_definition, protocol_field_definition(registration)
, CodeTemplatePlaceholder.protocol_write_serialization, protocol_write_serialization(registration)
, CodeTemplatePlaceholder.protocol_read_deserialization, protocol_read_deserialization(registration)
);
var formatProtocolClassTemplate = CodeTemplatePlaceholder.formatTemplate(protocolClassTemplate, placeholderMap);
protocolBuilder.append(formatProtocolClassTemplate).append(LS);
// registration
var protocolRegistrationTemplate = ClassUtils.getFileFromClassPathToString("csharp/ProtocolRegistrationTemplate.cs");
var formatProtocolRegistrationTemplate = CodeTemplatePlaceholder.formatTemplate(protocolRegistrationTemplate, placeholderMap);
protocolRegistrationBuilder.append(formatProtocolRegistrationTemplate);
}
var protocolTemplate = ClassUtils.getFileFromClassPathToString("csharp/ProtocolTemplate.cs");
var formatProtocolTemplate = CodeTemplatePlaceholder.formatTemplate(protocolTemplate, Map.of(
CodeTemplatePlaceholder.protocol_class, protocolBuilder.toString()
, CodeTemplatePlaceholder.protocol_registration, protocolRegistrationBuilder.toString()
));
var outputPath = StringUtils.format("{}/{}.cs", protocolOutputPath, StringUtils.capitalize(path));
var file = new File(outputPath);
FileUtils.writeStringToFile(file, formatProtocolTemplate, true);
logger.info("Generated C# protocol file:[{}] is in path:[{}]", file.getName(), file.getAbsolutePath());
}
}
/**
* 生成协议依赖的工具类
*/
public static void createProtocolManager(List<IProtocolRegistration> protocolList) throws IOException {
@Override
public void foldProtocol(List<IProtocolRegistration> registrations) throws IOException {
createProtocolManagerFile(registrations);
for (var registration : registrations) {
var protocolId = registration.protocolId();
var protocolClazzName = registration.protocolConstructor().getDeclaringClass().getSimpleName();
var formatProtocolTemplate = protocolTemplate((ProtocolRegistration) registration);
var outputPath = StringUtils.format("{}/{}/{}.cs", protocolOutputPath, GenerateProtocolPath.getCapitalizeProtocolPath(protocolId), protocolClazzName);
var file = new File(outputPath);
FileUtils.writeStringToFile(file, formatProtocolTemplate, true);
logger.info("Generated C# protocol file:[{}] is in path:[{}]", file.getName(), file.getAbsolutePath());
}
}
@Override
public void defaultProtocol(List<IProtocolRegistration> registrations) throws IOException {
createProtocolManagerFile(registrations);
for (var registration : registrations) {
var protocolClazzName = registration.protocolConstructor().getDeclaringClass().getSimpleName();
var formatProtocolTemplate = protocolTemplate((ProtocolRegistration) registration);
var outputPath = StringUtils.format("{}/{}.cs", protocolOutputPath, protocolClazzName);
var file = new File(outputPath);
FileUtils.writeStringToFile(file, formatProtocolTemplate, true);
logger.info("Generated C# protocol file:[{}] is in path:[{}]", file.getName(), file.getAbsolutePath());
}
}
private void createProtocolManagerFile(List<IProtocolRegistration> registrations) throws IOException {
var list = List.of("csharp/IProtocolRegistration.cs"
, "csharp/Buffer/ByteBuffer.cs"
, "csharp/Buffer/LittleEndianByteBuffer.cs"
@@ -98,53 +165,56 @@ public abstract class GenerateCsUtils {
FileUtils.writeInputStreamToFile(createFile, fileInputStream);
}
var protocolManagerTemplate = ClassUtils.getFileFromClassPathToString("csharp/ProtocolManagerTemplate.cs");
var csBuilder = new StringBuilder();
var initList = new ArrayList<String>();
for (var protocol : protocolList) {
var protocolId = protocol.protocolId();
var protocolName = protocol.protocolConstructor().getDeclaringClass().getSimpleName();
var path = GenerateProtocolPath.protocolAbsolutePath(protocolId, CodeLanguage.GdScript);
csBuilder.append(TAB + TAB + TAB).append(StringUtils.format("protocols[{}] = new {}Registration();", protocolId, protocolName, path)).append(LS);
csBuilder.append(TAB + TAB + TAB).append(StringUtils.format("protocolIdMap[typeof({})] = {};", protocolName, protocolId, path)).append(LS);
}
var initProtocols = StringUtils.joinWith(StringUtils.COMMA + LS, initList.toArray());
protocolManagerTemplate = StringUtils.format(protocolManagerTemplate, csBuilder.toString().trim(), initProtocols);
var template = ClassUtils.getFileFromClassPathToString("csharp/ProtocolManagerTemplate.cs");
var placeholderMap = Map.of(CodeTemplatePlaceholder.protocol_manager_registrations, protocol_manager_registrations(registrations));
var formatTemplate = CodeTemplatePlaceholder.formatTemplate(template, placeholderMap);
var file = new File(StringUtils.format("{}/{}", protocolOutputPath, "ProtocolManager.cs"));
FileUtils.writeStringToFile(file, protocolManagerTemplate, true);
FileUtils.writeStringToFile(file, formatTemplate, true);
logger.info("Generated C# protocol manager file:[{}] is in path:[{}]", file.getName(), file.getAbsolutePath());
}
/**
* 生成协议类
*/
public static void createCsProtocolFile(ProtocolRegistration registration) {
private String protocolTemplate(ProtocolRegistration registration) {
GenerateProtocolFile.index.set(0);
var protocolId = registration.protocolId();
var registrationConstructor = registration.getConstructor();
var protocolClazzName = registrationConstructor.getDeclaringClass().getSimpleName();
var protocolClazzName = registration.getConstructor().getDeclaringClass().getSimpleName();
var protocolClassTemplate = ClassUtils.getFileFromClassPathToString("csharp/ProtocolClassTemplate.cs");
var protocolRegistrationTemplate = ClassUtils.getFileFromClassPathToString("csharp/ProtocolRegistrationTemplate.cs");
var protocolTemplate = ClassUtils.getFileFromClassPathToString("csharp/ProtocolTemplate.cs");
var classNote = GenerateProtocolNote.classNote(protocolId, CodeLanguage.CSharp, TAB, 1);
var fieldDefinition = fieldDefinition(registration);
var writeObject = writeObject(registration);
var readObject = readObject(registration);
protocolTemplate = StringUtils.format(protocolTemplate, classNote, protocolClazzName, fieldDefinition.trim()
, protocolClazzName, protocolId, protocolClazzName, protocolClazzName, writeObject.trim()
, protocolClazzName, protocolClazzName, readObject.trim());
var outputPath = StringUtils.format("{}/{}/{}.cs"
, protocolOutputPath
, GenerateProtocolPath.getCapitalizeProtocolPath(protocolId)
, protocolClazzName);
var file = new File(outputPath);
FileUtils.writeStringToFile(file, protocolTemplate, true);
logger.info("Generated C# protocol file:[{}] is in path:[{}]", file.getName(), file.getAbsolutePath());
var placeholderMap = Map.of(
CodeTemplatePlaceholder.protocol_note, GenerateProtocolNote.protocol_note(protocolId, CodeLanguage.CSharp)
, CodeTemplatePlaceholder.protocol_name, protocolClazzName
, CodeTemplatePlaceholder.protocol_id, String.valueOf(protocolId)
, CodeTemplatePlaceholder.protocol_field_definition, protocol_field_definition(registration)
, CodeTemplatePlaceholder.protocol_write_serialization, protocol_write_serialization(registration)
, CodeTemplatePlaceholder.protocol_read_deserialization, protocol_read_deserialization(registration)
);
var formatProtocolClassTemplate = CodeTemplatePlaceholder.formatTemplate(protocolClassTemplate, placeholderMap);
var formatProtocolRegistrationTemplate = CodeTemplatePlaceholder.formatTemplate(protocolRegistrationTemplate, placeholderMap);
var formatProtocolTemplate = CodeTemplatePlaceholder.formatTemplate(protocolTemplate, Map.of(
CodeTemplatePlaceholder.protocol_class, formatProtocolClassTemplate
, CodeTemplatePlaceholder.protocol_registration, formatProtocolRegistrationTemplate
));
return formatProtocolTemplate;
}
private static String fieldDefinition(ProtocolRegistration registration) {
private String protocol_manager_registrations(List<IProtocolRegistration> protocolList) {
var csBuilder = new StringBuilder();
for (var protocol : protocolList) {
var protocolId = protocol.protocolId();
var protocolName = protocol.protocolConstructor().getDeclaringClass().getSimpleName();
var path = GenerateProtocolPath.protocolAbsolutePath(protocolId, CodeLanguage.CSharp);
csBuilder.append(StringUtils.format("protocols[{}] = new {}Registration();", protocolId, protocolName, path)).append(LS);
csBuilder.append(StringUtils.format("protocolIdMap[typeof({})] = {};", protocolName, protocolId, path)).append(LS);
}
return csBuilder.toString();
}
private String protocol_field_definition(ProtocolRegistration registration) {
var protocolId = registration.getId();
var fields = registration.getFields();
var fieldRegistrations = registration.getFieldRegistrations();
@@ -158,55 +228,38 @@ public abstract class GenerateCsUtils {
var propertyFullName = StringUtils.format("public {} {};", propertyType, fieldName);
// 生成注释
var fieldNotes = GenerateProtocolNote.fieldNotes(protocolId, fieldName, CodeLanguage.CSharp);
for(var fieldNote : fieldNotes) {
csBuilder.append(TAB + TAB).append(fieldNote).append(LS);
for (var fieldNote : fieldNotes) {
csBuilder.append(fieldNote).append(LS);
}
csBuilder.append(TAB + TAB).append(propertyFullName).append(LS);
csBuilder.append(propertyFullName).append(LS);
}
return csBuilder.toString();
}
private static Pair<String, String> valueOfMethod(ProtocolRegistration registration) {
var fields = registration.getFields();
var filedList = new ArrayList<Pair<String, String>>();
for (var field : fields) {
var propertyType = toCsClassName(field.getGenericType().getTypeName());
var propertyName = field.getName();
filedList.add(new Pair<>(propertyType, propertyName));
}
// ValueOf()方法
var valueOfParams = filedList.stream().map(it -> StringUtils.format("{} {}", it.getKey(), it.getValue())).toList();
var valueOfParamsStr = StringUtils.joinWith(StringUtils.COMMA + " ", valueOfParams.toArray());
var csBuilder = new StringBuilder();
filedList.forEach(it -> csBuilder.append(TAB + TAB + TAB).append(StringUtils.format("packet.{} = {};", it.getValue(), it.getValue())).append(LS));
return new Pair<>(valueOfParamsStr, csBuilder.toString());
}
private static String writeObject(ProtocolRegistration registration) {
private String protocol_write_serialization(ProtocolRegistration registration) {
var fields = registration.getFields();
var fieldRegistrations = registration.getFieldRegistrations();
var csBuilder = new StringBuilder();
if (registration.isCompatible()) {
csBuilder.append("int beforeWriteIndex = buffer.WriteOffset();").append(LS);
csBuilder.append(TAB + TAB + TAB).append(StringUtils.format("buffer.WriteInt({});", registration.getPredictionLength())).append(LS);
csBuilder.append(StringUtils.format("buffer.WriteInt({});", registration.getPredictionLength())).append(LS);
} else {
csBuilder.append(TAB + TAB + TAB).append("buffer.WriteInt(-1);").append(LS);
csBuilder.append("buffer.WriteInt(-1);").append(LS);
}
for (var i = 0; i < fields.length; i++) {
var field = fields[i];
var fieldRegistration = fieldRegistrations[i];
csSerializer(fieldRegistration.serializer()).writeObject(csBuilder, "message." + field.getName(), 3, field, fieldRegistration);
csSerializer(fieldRegistration.serializer()).writeObject(csBuilder, "message." + field.getName(), 0, field, fieldRegistration);
}
if (registration.isCompatible()) {
csBuilder.append(TAB + TAB + TAB).append(StringUtils.format("buffer.AdjustPadding({}, beforeWriteIndex);", registration.getPredictionLength())).append(LS);
csBuilder.append(StringUtils.format("buffer.AdjustPadding({}, beforeWriteIndex);", registration.getPredictionLength())).append(LS);
}
return csBuilder.toString();
}
private static String readObject(ProtocolRegistration registration) {
private String protocol_read_deserialization(ProtocolRegistration registration) {
var fields = registration.getFields();
var fieldRegistrations = registration.getFieldRegistrations();
var csBuilder = new StringBuilder();
@@ -215,14 +268,14 @@ public abstract class GenerateCsUtils {
var fieldRegistration = fieldRegistrations[i];
if (field.isAnnotationPresent(Compatible.class)) {
csBuilder.append(TAB + TAB + TAB).append("if (buffer.CompatibleRead(beforeReadIndex, length)) {").append(LS);
var compatibleReadObject = csSerializer(fieldRegistration.serializer()).readObject(csBuilder, 4, field, fieldRegistration);
csBuilder.append(TAB + TAB + TAB + TAB).append(StringUtils.format("packet.{} = {};", field.getName(), compatibleReadObject)).append(LS);
csBuilder.append(TAB + TAB + TAB).append("}").append(LS);
csBuilder.append("if (buffer.CompatibleRead(beforeReadIndex, length)) {").append(LS);
var compatibleReadObject = csSerializer(fieldRegistration.serializer()).readObject(csBuilder, 1, field, fieldRegistration);
csBuilder.append(StringUtils.format("packet.{} = {};", field.getName(), compatibleReadObject)).append(LS);
csBuilder.append("}").append(LS);
continue;
}
var readObject = csSerializer(fieldRegistration.serializer()).readObject(csBuilder, 3, field, fieldRegistration);
csBuilder.append(TAB + TAB + TAB).append(StringUtils.format("packet.{} = {};", field.getName(), readObject)).append(LS);
var readObject = csSerializer(fieldRegistration.serializer()).readObject(csBuilder, 0, field, fieldRegistration);
csBuilder.append(StringUtils.format("packet.{} = {};", field.getName(), readObject)).append(LS);
}
return csBuilder.toString();
}
@@ -331,4 +384,5 @@ public abstract class GenerateCsUtils {
return typeName;
}
}
@@ -64,9 +64,9 @@ public class CsArraySerializer implements ICsSerializer {
GenerateProtocolFile.addTab(builder, deep + 2);
String element = "element" + GenerateProtocolFile.index.getAndIncrement();
builder.append(StringUtils.format("{} {} = {}[{}];", GenerateCsUtils.toCsClassName(arrayField.getType().getSimpleName()), element, objectStr, i)).append(LS);
builder.append(StringUtils.format("{} {} = {}[{}];", CodeGenerateCsharp.toCsClassName(arrayField.getType().getSimpleName()), element, objectStr, i)).append(LS);
GenerateCsUtils.csSerializer(arrayField.getArrayElementRegistration().serializer())
CodeGenerateCsharp.csSerializer(arrayField.getArrayElementRegistration().serializer())
.writeObject(builder, element, deep + 2, field, arrayField.getArrayElementRegistration());
GenerateProtocolFile.addTab(builder, deep + 1);
@@ -87,7 +87,7 @@ public class CsArraySerializer implements ICsSerializer {
var arrayField = (ArrayField) fieldRegistration;
var result = "result" + GenerateProtocolFile.index.getAndIncrement();
var typeName = GenerateCsUtils.toCsClassName(arrayField.getType().getSimpleName());
var typeName = CodeGenerateCsharp.toCsClassName(arrayField.getType().getSimpleName());
var i = "index" + GenerateProtocolFile.index.getAndIncrement();
var size = "size" + GenerateProtocolFile.index.getAndIncrement();
@@ -105,7 +105,7 @@ public class CsArraySerializer implements ICsSerializer {
builder.append(StringUtils.format("for (int {} = 0; {} < {}; {}++)", i, i, size, i)).append(LS);
GenerateProtocolFile.addTab(builder, deep + 1);
builder.append("{").append(LS);
var readObject = GenerateCsUtils.csSerializer(arrayField.getArrayElementRegistration().serializer())
var readObject = CodeGenerateCsharp.csSerializer(arrayField.getArrayElementRegistration().serializer())
.readObject(builder, deep + 2, field, arrayField.getArrayElementRegistration());
GenerateProtocolFile.addTab(builder, deep + 2);
builder.append(StringUtils.format("{}[{}] = {};", result, i, readObject));
@@ -67,7 +67,7 @@ public class CsListSerializer implements ICsSerializer {
String element = "element" + GenerateProtocolFile.index.getAndIncrement();
builder.append(StringUtils.format("var {} = {}[{}];", element, objectStr, i)).append(LS);
GenerateCsUtils.csSerializer(listField.getListElementRegistration().serializer())
CodeGenerateCsharp.csSerializer(listField.getListElementRegistration().serializer())
.writeObject(builder, element, deep + 2, field, listField.getListElementRegistration());
GenerateProtocolFile.addTab(builder, deep + 1);
@@ -87,7 +87,7 @@ public class CsListSerializer implements ICsSerializer {
var listField = (ListField) fieldRegistration;
var result = "result" + GenerateProtocolFile.index.getAndIncrement();
var typeName = GenerateCsUtils.toCsClassName(listField.getType().toString());
var typeName = CodeGenerateCsharp.toCsClassName(listField.getType().toString());
var i = "index" + GenerateProtocolFile.index.getAndIncrement();
var size = "size" + GenerateProtocolFile.index.getAndIncrement();
@@ -105,7 +105,7 @@ public class CsListSerializer implements ICsSerializer {
builder.append(StringUtils.format("for (int {} = 0; {} < {}; {}++)", i, i, size, i)).append(LS);
GenerateProtocolFile.addTab(builder, deep + 1);
builder.append("{").append(LS);
var readObject = GenerateCsUtils.csSerializer(listField.getListElementRegistration().serializer())
var readObject = CodeGenerateCsharp.csSerializer(listField.getListElementRegistration().serializer())
.readObject(builder, deep + 2, field, listField.getListElementRegistration());
GenerateProtocolFile.addTab(builder, deep + 2);
builder.append(StringUtils.format("{}.Add({});", result, readObject)).append(LS);
@@ -72,9 +72,9 @@ public class CsMapSerializer implements ICsSerializer {
GenerateProtocolFile.addTab(builder, deep + 2);
builder.append(StringUtils.format("var {} = {}.Value;", value, i)).append(LS);
GenerateCsUtils.csSerializer(mapField.getMapKeyRegistration().serializer())
CodeGenerateCsharp.csSerializer(mapField.getMapKeyRegistration().serializer())
.writeObject(builder, key, deep + 2, field, mapField.getMapKeyRegistration());
GenerateCsUtils.csSerializer(mapField.getMapValueRegistration().serializer())
CodeGenerateCsharp.csSerializer(mapField.getMapValueRegistration().serializer())
.writeObject(builder, value, deep + 2, field, mapField.getMapValueRegistration());
GenerateProtocolFile.addTab(builder, deep + 1);
builder.append("}").append(LS);
@@ -94,7 +94,7 @@ public class CsMapSerializer implements ICsSerializer {
MapField mapField = (MapField) fieldRegistration;
String result = "result" + GenerateProtocolFile.index.getAndIncrement();
var typeName = GenerateCsUtils.toCsClassName(mapField.getType().toString());
var typeName = CodeGenerateCsharp.toCsClassName(mapField.getType().toString());
String size = "size" + GenerateProtocolFile.index.getAndIncrement();
builder.append(StringUtils.format("int {} = buffer.ReadInt();", size)).append(LS);
@@ -114,11 +114,11 @@ public class CsMapSerializer implements ICsSerializer {
GenerateProtocolFile.addTab(builder, deep + 1);
builder.append("{").append(LS);
String keyObject = GenerateCsUtils.csSerializer(mapField.getMapKeyRegistration().serializer())
String keyObject = CodeGenerateCsharp.csSerializer(mapField.getMapKeyRegistration().serializer())
.readObject(builder, deep + 2, field, mapField.getMapKeyRegistration());
String valueObject = GenerateCsUtils.csSerializer(mapField.getMapValueRegistration().serializer())
String valueObject = CodeGenerateCsharp.csSerializer(mapField.getMapValueRegistration().serializer())
.readObject(builder, deep + 2, field, mapField.getMapValueRegistration());
GenerateProtocolFile.addTab(builder, deep + 2);
@@ -60,7 +60,7 @@ public class CsSetSerializer implements ICsSerializer {
GenerateProtocolFile.addTab(builder, deep + 1);
builder.append("{").append(LS);
GenerateCsUtils.csSerializer(setField.getSetElementRegistration().serializer())
CodeGenerateCsharp.csSerializer(setField.getSetElementRegistration().serializer())
.writeObject(builder, element, deep + 2, field, setField.getSetElementRegistration());
GenerateProtocolFile.addTab(builder, deep + 1);
@@ -80,7 +80,7 @@ public class CsSetSerializer implements ICsSerializer {
SetField setField = (SetField) fieldRegistration;
var result = "result" + GenerateProtocolFile.index.getAndIncrement();
var typeName = GenerateCsUtils.toCsClassName(setField.getType().toString());
var typeName = CodeGenerateCsharp.toCsClassName(setField.getType().toString());
var i = "index" + GenerateProtocolFile.index.getAndIncrement();
var size = "size" + GenerateProtocolFile.index.getAndIncrement();
@@ -100,7 +100,7 @@ public class CsSetSerializer implements ICsSerializer {
GenerateProtocolFile.addTab(builder, deep + 1);
builder.append("{").append(LS);
var readObject = GenerateCsUtils.csSerializer(setField.getSetElementRegistration().serializer())
var readObject = CodeGenerateCsharp.csSerializer(setField.getSetElementRegistration().serializer())
.readObject(builder, deep + 2, field, setField.getSetElementRegistration());
GenerateProtocolFile.addTab(builder, deep + 2);
builder.append(StringUtils.format("{}.Add({});", result, readObject)).append(LS);
@@ -21,7 +21,7 @@ import com.zfoo.protocol.generate.GenerateProtocolPath;
import com.zfoo.protocol.registration.IProtocolRegistration;
import com.zfoo.protocol.registration.ProtocolRegistration;
import com.zfoo.protocol.serializer.CodeLanguage;
import com.zfoo.protocol.serializer.csharp.GenerateCsUtils;
import com.zfoo.protocol.serializer.csharp.CodeGenerateCsharp;
import com.zfoo.protocol.serializer.reflect.*;
import com.zfoo.protocol.util.ClassUtils;
import com.zfoo.protocol.util.FileUtils;
@@ -248,7 +248,7 @@ public abstract class GenerateLuaUtils {
} else {
luaBuilder.append(TAB + TAB).append(StringUtils.format("{} = {},", fieldName, fieldDefaultValue));
}
var typeNote = GenerateCsUtils.toCsClassName(field.getGenericType().getTypeName());
var typeNote = CodeGenerateCsharp.toCsClassName(field.getGenericType().getTypeName());
// 生成类型的注释
luaBuilder.append(" -- ").append(typeNote).append(LS);
}
@@ -21,7 +21,7 @@ import com.zfoo.protocol.generate.GenerateProtocolPath;
import com.zfoo.protocol.registration.IProtocolRegistration;
import com.zfoo.protocol.registration.ProtocolRegistration;
import com.zfoo.protocol.serializer.CodeLanguage;
import com.zfoo.protocol.serializer.csharp.GenerateCsUtils;
import com.zfoo.protocol.serializer.csharp.CodeGenerateCsharp;
import com.zfoo.protocol.serializer.reflect.*;
import com.zfoo.protocol.util.ClassUtils;
import com.zfoo.protocol.util.FileUtils;
@@ -150,7 +150,7 @@ public abstract class GeneratePyUtils {
var fieldDefaultValue = pySerializer(fieldRegistration.serializer()).fieldDefaultValue(field, fieldRegistration);
// 生成类型的注释
pyBuilder.append(StringUtils.format("{}{} = {}", TAB, fieldName, fieldDefaultValue));
pyBuilder.append(StringUtils.format(" # {}", GenerateCsUtils.toCsClassName(field.getGenericType().getTypeName())));
pyBuilder.append(StringUtils.format(" # {}", CodeGenerateCsharp.toCsClassName(field.getGenericType().getTypeName())));
pyBuilder.append(LS);
}
return pyBuilder.toString();
@@ -0,0 +1,5 @@
${protocol_note}
public class ${protocol_name}
{
${protocol_field_definition}
}
@@ -20,7 +20,7 @@ namespace zfoocs
return;
}
initialized = true;
{}
${protocol_manager_registrations}
}
public static short GetProtocolId(Type type)
@@ -0,0 +1,35 @@
public class ${protocol_name}Registration : IProtocolRegistration
{
public short ProtocolId()
{
return ${protocol_id};
}
public void Write(ByteBuffer buffer, object packet)
{
if (packet == null)
{
buffer.WriteInt(0);
return;
}
${protocol_name} message = (${protocol_name}) packet;
${protocol_write_serialization}
}
public object Read(ByteBuffer buffer)
{
int length = buffer.ReadInt();
if (length == 0)
{
return null;
}
int beforeReadIndex = buffer.ReadOffset();
${protocol_name} packet = new ${protocol_name}();
${protocol_read_deserialization}
if (length > 0)
{
buffer.SetReadOffset(beforeReadIndex + length);
}
return packet;
}
}
@@ -1,48 +1,8 @@
using System;
using System.Collections.Generic;
namespace zfoocs
{
{}
public class {}
{
{}
}
${protocol_class}
public class {}Registration : IProtocolRegistration
{
public short ProtocolId()
{
return {};
}
public void Write(ByteBuffer buffer, object packet)
{
if (packet == null)
{
buffer.WriteInt(0);
return;
}
{} message = ({}) packet;
{}
}
public object Read(ByteBuffer buffer)
{
int length = buffer.ReadInt();
if (length == 0)
{
return null;
}
int beforeReadIndex = buffer.ReadOffset();
{} packet = new {}();
{}
if (length > 0)
{
buffer.SetReadOffset(beforeReadIndex + length);
}
return packet;
}
}
${protocol_registration}
}