From aa40b366161c38d95ccbd41f75b8600ab9bb9e57 Mon Sep 17 00:00:00 2001 From: godotg Date: Thu, 30 May 2024 15:12:13 +0800 Subject: [PATCH] ref[gdscript]: refactor generate gdscript protocol --- .../generate/GenerateProtocolFile.java | 10 - .../registration/ProtocolAnalysis.java | 2 - .../protocol/serializer/CodeLanguage.java | 3 +- .../serializer/CodeTemplatePlaceholder.java | 4 + .../serializer/cpp/CodeGenerateCpp.java | 8 +- .../ecmascript/CodeGenerateEcmaScript.java | 12 +- .../gdscript/CodeGenerateGdScript.java | 368 ++++++++++++++++++ .../gdscript/GdArraySerializer.java | 6 +- .../serializer/gdscript/GdListSerializer.java | 6 +- .../serializer/gdscript/GdMapSerializer.java | 8 +- .../serializer/gdscript/GdSetSerializer.java | 6 +- .../serializer/gdscript/GenerateGdUtils.java | 263 ------------- .../typescript/CodeGenerateTypeScript.java | 8 +- .../gdscript/ProtocolClassTemplate.gd | 29 ++ .../gdscript/ProtocolManagerTemplate.gd | 4 +- .../resources/gdscript/ProtocolTemplate.gd | 18 +- .../resources/gdscript/ProtocolsTemplate.gd | 1 + 17 files changed, 442 insertions(+), 314 deletions(-) create mode 100644 protocol/src/main/java/com/zfoo/protocol/serializer/gdscript/CodeGenerateGdScript.java delete mode 100644 protocol/src/main/java/com/zfoo/protocol/serializer/gdscript/GenerateGdUtils.java create mode 100644 protocol/src/main/resources/gdscript/ProtocolClassTemplate.gd create mode 100644 protocol/src/main/resources/gdscript/ProtocolsTemplate.gd diff --git a/protocol/src/main/java/com/zfoo/protocol/generate/GenerateProtocolFile.java b/protocol/src/main/java/com/zfoo/protocol/generate/GenerateProtocolFile.java index 35652f6d..634e4ef8 100644 --- a/protocol/src/main/java/com/zfoo/protocol/generate/GenerateProtocolFile.java +++ b/protocol/src/main/java/com/zfoo/protocol/generate/GenerateProtocolFile.java @@ -19,7 +19,6 @@ import com.zfoo.protocol.registration.IProtocolRegistration; import com.zfoo.protocol.registration.ProtocolAnalysis; import com.zfoo.protocol.registration.ProtocolRegistration; import com.zfoo.protocol.serializer.CodeLanguage; -import com.zfoo.protocol.serializer.gdscript.GenerateGdUtils; import com.zfoo.protocol.serializer.go.GenerateGoUtils; import com.zfoo.protocol.util.FileUtils; import com.zfoo.protocol.util.ReflectionUtils; @@ -125,15 +124,6 @@ public abstract class GenerateProtocolFile { } } - // 生成GdScript协议 - if (generateLanguages.contains(CodeLanguage.GdScript)) { - GenerateGdUtils.init(generateOperation); - GenerateGdUtils.createProtocolManager(generateProtocols); - for (var protocolRegistration : generateProtocols) { - GenerateGdUtils.createGdProtocolFile((ProtocolRegistration) protocolRegistration); - } - } - for (var language : generateOperation.getGenerateLanguages()) { if (language.codeGenerateClass == null) { continue; diff --git a/protocol/src/main/java/com/zfoo/protocol/registration/ProtocolAnalysis.java b/protocol/src/main/java/com/zfoo/protocol/registration/ProtocolAnalysis.java index 5d920066..eec907ca 100644 --- a/protocol/src/main/java/com/zfoo/protocol/registration/ProtocolAnalysis.java +++ b/protocol/src/main/java/com/zfoo/protocol/registration/ProtocolAnalysis.java @@ -25,7 +25,6 @@ import com.zfoo.protocol.generate.GenerateProtocolFile; import com.zfoo.protocol.generate.GenerateProtocolNote; import com.zfoo.protocol.generate.GenerateProtocolPath; import com.zfoo.protocol.registration.field.*; -import com.zfoo.protocol.serializer.gdscript.GenerateGdUtils; import com.zfoo.protocol.serializer.go.GenerateGoUtils; import com.zfoo.protocol.serializer.reflect.*; import com.zfoo.protocol.util.*; @@ -395,7 +394,6 @@ public class ProtocolAnalysis { GenerateProtocolNote.clear(); GenerateProtocolPath.clear(); GenerateGoUtils.clear(); - GenerateGdUtils.clear(); } public static List getFields(Class clazz) { diff --git a/protocol/src/main/java/com/zfoo/protocol/serializer/CodeLanguage.java b/protocol/src/main/java/com/zfoo/protocol/serializer/CodeLanguage.java index 6d83c30d..981039fb 100644 --- a/protocol/src/main/java/com/zfoo/protocol/serializer/CodeLanguage.java +++ b/protocol/src/main/java/com/zfoo/protocol/serializer/CodeLanguage.java @@ -15,6 +15,7 @@ package com.zfoo.protocol.serializer; import com.zfoo.protocol.serializer.cpp.CodeGenerateCpp; import com.zfoo.protocol.serializer.csharp.CodeGenerateCsharp; import com.zfoo.protocol.serializer.ecmascript.CodeGenerateEcmaScript; +import com.zfoo.protocol.serializer.gdscript.CodeGenerateGdScript; import com.zfoo.protocol.serializer.javascript.CodeGenerateJavaScript; import com.zfoo.protocol.serializer.lua.CodeGenerateLua; import com.zfoo.protocol.serializer.python.CodeGeneratePython; @@ -44,7 +45,7 @@ public enum CodeLanguage { CSharp(1 << 11, CodeGenerateCsharp.class), - GdScript(1 << 12, null), + GdScript(1 << 12, CodeGenerateGdScript.class), Python(1 << 13, CodeGeneratePython.class), diff --git a/protocol/src/main/java/com/zfoo/protocol/serializer/CodeTemplatePlaceholder.java b/protocol/src/main/java/com/zfoo/protocol/serializer/CodeTemplatePlaceholder.java index 3526ccde..fb962b47 100644 --- a/protocol/src/main/java/com/zfoo/protocol/serializer/CodeTemplatePlaceholder.java +++ b/protocol/src/main/java/com/zfoo/protocol/serializer/CodeTemplatePlaceholder.java @@ -45,6 +45,10 @@ public enum CodeTemplatePlaceholder { protocol_read_deserialization("${protocol_read_deserialization}"), + protocol_json("${protocol_json}"), + + protocol_to_string("${protocol_to_string}"), + ; public final String placeholder; diff --git a/protocol/src/main/java/com/zfoo/protocol/serializer/cpp/CodeGenerateCpp.java b/protocol/src/main/java/com/zfoo/protocol/serializer/cpp/CodeGenerateCpp.java index 01487621..87042a03 100644 --- a/protocol/src/main/java/com/zfoo/protocol/serializer/cpp/CodeGenerateCpp.java +++ b/protocol/src/main/java/com/zfoo/protocol/serializer/cpp/CodeGenerateCpp.java @@ -246,8 +246,8 @@ public class CodeGenerateCpp implements ICodeGenerate { var subProtocols = ProtocolAnalysis.getAllSubProtocolIds(protocolId); var cppBuilder = new StringBuilder(); for (var subProtocolId : subProtocols) { - var protocolClassName = EnhanceObjectProtocolSerializer.getProtocolClassSimpleName(subProtocolId); - var subProtocolPath = StringUtils.format("#include \"{}/{}/{}.h\"", protocolOutputRootPath, GenerateProtocolPath.capitalizeProtocolPathFold(subProtocolId), protocolClassName); + var protocolName = EnhanceObjectProtocolSerializer.getProtocolClassSimpleName(subProtocolId); + var subProtocolPath = StringUtils.format("#include \"{}/{}/{}.h\"", protocolOutputRootPath, GenerateProtocolPath.capitalizeProtocolPathFold(subProtocolId), protocolName); cppBuilder.append(subProtocolPath).append(LS); } return cppBuilder.toString(); @@ -258,8 +258,8 @@ public class CodeGenerateCpp implements ICodeGenerate { var subProtocols = ProtocolAnalysis.getAllSubProtocolIds(protocolId); var cppBuilder = new StringBuilder(); for (var subProtocolId : subProtocols) { - var protocolClassName = EnhanceObjectProtocolSerializer.getProtocolClassSimpleName(subProtocolId); - var subProtocolPath = StringUtils.format("#include \"{}/{}.h\"", protocolOutputRootPath, protocolClassName); + var protocolName = EnhanceObjectProtocolSerializer.getProtocolClassSimpleName(subProtocolId); + var subProtocolPath = StringUtils.format("#include \"{}/{}.h\"", protocolOutputRootPath, protocolName); cppBuilder.append(subProtocolPath).append(LS); } return cppBuilder.toString(); diff --git a/protocol/src/main/java/com/zfoo/protocol/serializer/ecmascript/CodeGenerateEcmaScript.java b/protocol/src/main/java/com/zfoo/protocol/serializer/ecmascript/CodeGenerateEcmaScript.java index b86cdac5..c16b47aa 100644 --- a/protocol/src/main/java/com/zfoo/protocol/serializer/ecmascript/CodeGenerateEcmaScript.java +++ b/protocol/src/main/java/com/zfoo/protocol/serializer/ecmascript/CodeGenerateEcmaScript.java @@ -94,7 +94,7 @@ public class CodeGenerateEcmaScript implements ICodeGenerate { var formatProtocolManagerTemplate = CodeTemplatePlaceholder.formatTemplate(protocolManagerTemplate, placeholderMap); var protocolManagerFile = new File(StringUtils.format("{}/{}", protocolOutputPath, "ProtocolManager.mjs")); FileUtils.writeStringToFile(protocolManagerFile, formatProtocolManagerTemplate, true); - logger.info("Generated ES protocol manager file:[{}] is in path:[{}]", protocolManagerFile.getName(), protocolManagerFile.getAbsolutePath()); + logger.info("Generated EcmaScript protocol manager file:[{}] is in path:[{}]", protocolManagerFile.getName(), protocolManagerFile.getAbsolutePath()); var protocol_class = new StringBuilder(); @@ -114,7 +114,7 @@ public class CodeGenerateEcmaScript implements ICodeGenerate { var outputPath = StringUtils.format("{}/Protocols.mjs", protocolOutputPath); var file = new File(outputPath); FileUtils.writeStringToFile(file, formatProtocolTemplate, true); - logger.info("Generated ES protocol file:[{}] is in path:[{}]", file.getName(), file.getAbsolutePath()); + logger.info("Generated EcmaScript protocol file:[{}] is in path:[{}]", file.getName(), file.getAbsolutePath()); } @Override @@ -137,7 +137,7 @@ public class CodeGenerateEcmaScript implements ICodeGenerate { var formatProtocolManagerTemplate = CodeTemplatePlaceholder.formatTemplate(protocolManagerTemplate, placeholderMap); var protocolManagerFile = new File(StringUtils.format("{}/{}", protocolOutputPath, "ProtocolManager.mjs")); FileUtils.writeStringToFile(protocolManagerFile, formatProtocolManagerTemplate, true); - logger.info("Generated ES protocol manager file:[{}] is in path:[{}]", protocolManagerFile.getName(), protocolManagerFile.getAbsolutePath()); + logger.info("Generated EcmaScript protocol manager file:[{}] is in path:[{}]", protocolManagerFile.getName(), protocolManagerFile.getAbsolutePath()); for (var registration : registrations) { @@ -147,7 +147,7 @@ public class CodeGenerateEcmaScript implements ICodeGenerate { var outputPath = StringUtils.format("{}/{}/{}.mjs", protocolOutputPath, GenerateProtocolPath.protocolPathSlash(protocol_id), protocol_name); var file = new File(outputPath); FileUtils.writeStringToFile(file, formatProtocolTemplate, true); - logger.info("Generated ES protocol file:[{}] is in path:[{}]", file.getName(), file.getAbsolutePath()); + logger.info("Generated EcmaScript protocol file:[{}] is in path:[{}]", file.getName(), file.getAbsolutePath()); } } @@ -171,7 +171,7 @@ public class CodeGenerateEcmaScript implements ICodeGenerate { var formatProtocolManagerTemplate = CodeTemplatePlaceholder.formatTemplate(protocolManagerTemplate, placeholderMap); var protocolManagerFile = new File(StringUtils.format("{}/{}", protocolOutputPath, "ProtocolManager.mjs")); FileUtils.writeStringToFile(protocolManagerFile, formatProtocolManagerTemplate, true); - logger.info("Generated ES protocol manager file:[{}] is in path:[{}]", protocolManagerFile.getName(), protocolManagerFile.getAbsolutePath()); + logger.info("Generated EcmaScript protocol manager file:[{}] is in path:[{}]", protocolManagerFile.getName(), protocolManagerFile.getAbsolutePath()); for (var registration : registrations) { @@ -181,7 +181,7 @@ public class CodeGenerateEcmaScript implements ICodeGenerate { var outputPath = StringUtils.format("{}/{}.mjs", protocolOutputPath, protocol_name, protocol_name); var file = new File(outputPath); FileUtils.writeStringToFile(file, formatProtocolTemplate, true); - logger.info("Generated ES protocol file:[{}] is in path:[{}]", file.getName(), file.getAbsolutePath()); + logger.info("Generated EcmaScript protocol file:[{}] is in path:[{}]", file.getName(), file.getAbsolutePath()); } } diff --git a/protocol/src/main/java/com/zfoo/protocol/serializer/gdscript/CodeGenerateGdScript.java b/protocol/src/main/java/com/zfoo/protocol/serializer/gdscript/CodeGenerateGdScript.java new file mode 100644 index 00000000..cf297e8f --- /dev/null +++ b/protocol/src/main/java/com/zfoo/protocol/serializer/gdscript/CodeGenerateGdScript.java @@ -0,0 +1,368 @@ +/* + * 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.gdscript; + +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.registration.ProtocolAnalysis; +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.enhance.EnhanceObjectProtocolSerializer; +import com.zfoo.protocol.serializer.reflect.*; +import com.zfoo.protocol.serializer.typescript.CodeGenerateTypeScript; +import com.zfoo.protocol.util.ClassUtils; +import com.zfoo.protocol.util.FileUtils; +import com.zfoo.protocol.util.ReflectionUtils; +import com.zfoo.protocol.util.StringUtils; +import org.slf4j.Logger; +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_ASCII; + +/** + * @author godotg + */ +public class CodeGenerateGdScript implements ICodeGenerate { + private static final Logger logger = LoggerFactory.getLogger(CodeGenerateGdScript.class); + + // custom configuration + public static String protocolOutputRootPath = "zfoogd"; + private static String protocolOutputPath = StringUtils.EMPTY; + + private static Map gdSerializerMap = new HashMap<>(); + + public static IGdSerializer gdSerializer(ISerializer serializer) { + return gdSerializerMap.get(serializer); + } + + @Override + public void init(GenerateOperation generateOperation) { + protocolOutputPath = FileUtils.joinPath(generateOperation.getProtocolPath(), protocolOutputRootPath); + FileUtils.deleteFile(new File(protocolOutputPath)); + + gdSerializerMap.put(BooleanSerializer.INSTANCE, new GdBooleanSerializer()); + gdSerializerMap.put(ByteSerializer.INSTANCE, new GdByteSerializer()); + gdSerializerMap.put(ShortSerializer.INSTANCE, new GdShortSerializer()); + gdSerializerMap.put(IntSerializer.INSTANCE, new GdIntSerializer()); + gdSerializerMap.put(LongSerializer.INSTANCE, new GdLongSerializer()); + gdSerializerMap.put(FloatSerializer.INSTANCE, new GdFloatSerializer()); + gdSerializerMap.put(DoubleSerializer.INSTANCE, new GdDoubleSerializer()); + gdSerializerMap.put(StringSerializer.INSTANCE, new GdStringSerializer()); + gdSerializerMap.put(ArraySerializer.INSTANCE, new GdArraySerializer()); + gdSerializerMap.put(ListSerializer.INSTANCE, new GdListSerializer()); + gdSerializerMap.put(SetSerializer.INSTANCE, new GdSetSerializer()); + gdSerializerMap.put(MapSerializer.INSTANCE, new GdMapSerializer()); + gdSerializerMap.put(ObjectProtocolSerializer.INSTANCE, new GdObjectProtocolSerializer()); + } + + @Override + public void mergerProtocol(List registrations) throws IOException { + createTemplateFile(); + + + // 生成ProtocolManager.gd文件 + var protocolManagerTemplate = ClassUtils.getFileFromClassPathToString("gdscript/ProtocolManagerTemplate.gd"); + var protocol_imports = new StringBuilder(); + var protocol_manager_registrations = new StringBuilder(); + protocol_imports.append(StringUtils.format("const Protocols = preload(\"res://{}/Protocols.gd\")", protocolOutputRootPath)).append(LS); + for (var registration : registrations) { + var protocol_id = registration.protocolId(); + var protocol_name = registration.protocolConstructor().getDeclaringClass().getSimpleName(); + protocol_manager_registrations.append(StringUtils.format("{}{}: Protocols.{},", TAB_ASCII, protocol_id, protocol_name)).append(LS); + } + var placeholderMap = Map.of(CodeTemplatePlaceholder.protocol_imports, protocol_imports.toString() + , CodeTemplatePlaceholder.protocol_manager_registrations, StringUtils.substringBeforeLast(protocol_manager_registrations.toString(), StringUtils.COMMA)); + var formatProtocolManagerTemplate = CodeTemplatePlaceholder.formatTemplate(protocolManagerTemplate, placeholderMap); + var protocolManagerFile = new File(StringUtils.format("{}/{}", protocolOutputPath, "ProtocolManager.gd")); + FileUtils.writeStringToFile(protocolManagerFile, formatProtocolManagerTemplate, true); + logger.info("Generated GdScript protocol manager file:[{}] is in path:[{}]", protocolManagerFile.getName(), protocolManagerFile.getAbsolutePath()); + + + var protocol_imports_protocols = new StringBuilder(); + var protocol_class = new StringBuilder(); + for (var registration : registrations) { + var protocol_id = registration.protocolId(); + var protocol_name = registration.protocolConstructor().getDeclaringClass().getSimpleName(); + var protocolTemplate = ClassUtils.getFileFromClassPathToString("gdscript/ProtocolClassTemplate.gd"); + var formatProtocolTemplate = CodeTemplatePlaceholder.formatTemplate(protocolTemplate, Map.of( + CodeTemplatePlaceholder.protocol_id, String.valueOf(protocol_id) + , CodeTemplatePlaceholder.protocol_name, protocol_name + , CodeTemplatePlaceholder.protocol_note, GenerateProtocolNote.protocol_note(protocol_id, CodeLanguage.GdScript) + , CodeTemplatePlaceholder.protocol_field_definition, protocol_field_definition(registration) + , CodeTemplatePlaceholder.protocol_write_serialization, protocol_write_serialization(registration) + , CodeTemplatePlaceholder.protocol_read_deserialization, protocol_read_deserialization(registration) + , CodeTemplatePlaceholder.protocol_json, protocol_json(registration) + , CodeTemplatePlaceholder.protocol_to_string, protocol_to_string(registration) + )); + protocol_class.append(formatProtocolTemplate).append(LS); + } + var protocolTemplate = ClassUtils.getFileFromClassPathToString("gdscript/ProtocolsTemplate.gd"); + var formatProtocolTemplate = CodeTemplatePlaceholder.formatTemplate(protocolTemplate, Map.of( + CodeTemplatePlaceholder.protocol_imports, protocol_imports_protocols.toString() + , CodeTemplatePlaceholder.protocol_class, protocol_class.toString() + )); + var outputPath = StringUtils.format("{}/Protocols.gd", protocolOutputPath); + var file = new File(outputPath); + FileUtils.writeStringToFile(file, formatProtocolTemplate, true); + logger.info("Generated GdScript protocol file:[{}] is in path:[{}]", file.getName(), file.getAbsolutePath()); + } + + @Override + public void foldProtocol(List registrations) throws IOException { + createTemplateFile(); + + + // 生成ProtocolManager.gd文件 + var protocolManagerTemplate = ClassUtils.getFileFromClassPathToString("gdscript/ProtocolManagerTemplate.gd"); + var protocol_imports = new StringBuilder(); + var protocol_manager_registrations = new StringBuilder(); + for (var registration : registrations) { + var protocol_id = registration.protocolId(); + var protocol_name = registration.protocolConstructor().getDeclaringClass().getSimpleName(); + protocol_imports.append(StringUtils.format("const {} = preload(\"res://{}/{}/{}.gd\")", protocol_name, protocolOutputRootPath, GenerateProtocolPath.protocolPathSlash(protocol_id), protocol_name)).append(LS); + protocol_manager_registrations.append(StringUtils.format("{}{}: {},", TAB_ASCII, protocol_id, protocol_name)).append(LS); + } + var placeholderMap = Map.of(CodeTemplatePlaceholder.protocol_imports, protocol_imports.toString() + , CodeTemplatePlaceholder.protocol_manager_registrations, StringUtils.substringBeforeLast(protocol_manager_registrations.toString(), StringUtils.COMMA)); + var formatProtocolManagerTemplate = CodeTemplatePlaceholder.formatTemplate(protocolManagerTemplate, placeholderMap); + var protocolManagerFile = new File(StringUtils.format("{}/{}", protocolOutputPath, "ProtocolManager.gd")); + FileUtils.writeStringToFile(protocolManagerFile, formatProtocolManagerTemplate, true); + logger.info("Generated GdScript protocol manager file:[{}] is in path:[{}]", protocolManagerFile.getName(), protocolManagerFile.getAbsolutePath()); + + + for (var registration : registrations) { + var protocol_id = registration.protocolId(); + var protocol_name = registration.protocolConstructor().getDeclaringClass().getSimpleName(); + var protocolTemplate = ClassUtils.getFileFromClassPathToString("gdscript/ProtocolTemplate.gd"); + var formatProtocolTemplate = CodeTemplatePlaceholder.formatTemplate(protocolTemplate, Map.of( + CodeTemplatePlaceholder.protocol_id, String.valueOf(protocol_id) + , CodeTemplatePlaceholder.protocol_name, protocol_name + , CodeTemplatePlaceholder.protocol_note, GenerateProtocolNote.protocol_note(protocol_id, CodeLanguage.GdScript) + , CodeTemplatePlaceholder.protocol_imports, protocol_imports_fold(registration) + , CodeTemplatePlaceholder.protocol_field_definition, protocol_field_definition(registration) + , CodeTemplatePlaceholder.protocol_write_serialization, protocol_write_serialization(registration) + , CodeTemplatePlaceholder.protocol_read_deserialization, protocol_read_deserialization(registration) + , CodeTemplatePlaceholder.protocol_json, protocol_json(registration) + , CodeTemplatePlaceholder.protocol_to_string, protocol_to_string(registration) + )); + var outputPath = StringUtils.format("{}/{}/{}.gd", protocolOutputPath, GenerateProtocolPath.protocolPathSlash(protocol_id), protocol_name); + var file = new File(outputPath); + FileUtils.writeStringToFile(file, formatProtocolTemplate, true); + logger.info("Generated GdScript protocol file:[{}] is in path:[{}]", file.getName(), file.getAbsolutePath()); + } + } + + @Override + public void defaultProtocol(List registrations) throws IOException { + createTemplateFile(); + + + // 生成ProtocolManager.gd文件 + var protocolManagerTemplate = ClassUtils.getFileFromClassPathToString("gdscript/ProtocolManagerTemplate.gd"); + var protocol_imports = new StringBuilder(); + var protocol_manager_registrations = new StringBuilder(); + for (var registration : registrations) { + var protocol_id = registration.protocolId(); + var protocol_name = registration.protocolConstructor().getDeclaringClass().getSimpleName(); + protocol_imports.append(StringUtils.format("const {} = preload(\"res://{}/{}.gd\")", protocol_name, protocolOutputRootPath, protocol_name)).append(LS); + protocol_manager_registrations.append(StringUtils.format("{}{}: {},", TAB_ASCII, protocol_id, protocol_name)).append(LS); + } + var placeholderMap = Map.of(CodeTemplatePlaceholder.protocol_imports, protocol_imports.toString() + , CodeTemplatePlaceholder.protocol_manager_registrations, StringUtils.substringBeforeLast(protocol_manager_registrations.toString(), StringUtils.COMMA)); + var formatProtocolManagerTemplate = CodeTemplatePlaceholder.formatTemplate(protocolManagerTemplate, placeholderMap); + var protocolManagerFile = new File(StringUtils.format("{}/{}", protocolOutputPath, "ProtocolManager.gd")); + FileUtils.writeStringToFile(protocolManagerFile, formatProtocolManagerTemplate, true); + logger.info("Generated GdScript protocol manager file:[{}] is in path:[{}]", protocolManagerFile.getName(), protocolManagerFile.getAbsolutePath()); + + + for (var registration : registrations) { + var protocol_id = registration.protocolId(); + var protocol_name = registration.protocolConstructor().getDeclaringClass().getSimpleName(); + var protocolTemplate = ClassUtils.getFileFromClassPathToString("gdscript/ProtocolTemplate.gd"); + var formatProtocolTemplate = CodeTemplatePlaceholder.formatTemplate(protocolTemplate, Map.of( + CodeTemplatePlaceholder.protocol_id, String.valueOf(protocol_id) + , CodeTemplatePlaceholder.protocol_name, protocol_name + , CodeTemplatePlaceholder.protocol_note, GenerateProtocolNote.protocol_note(protocol_id, CodeLanguage.GdScript) + , CodeTemplatePlaceholder.protocol_imports, protocol_imports_default(registration) + , CodeTemplatePlaceholder.protocol_field_definition, protocol_field_definition(registration) + , CodeTemplatePlaceholder.protocol_write_serialization, protocol_write_serialization(registration) + , CodeTemplatePlaceholder.protocol_read_deserialization, protocol_read_deserialization(registration) + , CodeTemplatePlaceholder.protocol_json, protocol_json(registration) + , CodeTemplatePlaceholder.protocol_to_string, protocol_to_string(registration) + )); + var outputPath = StringUtils.format("{}/{}.gd", protocolOutputPath, protocol_name); + var file = new File(outputPath); + FileUtils.writeStringToFile(file, formatProtocolTemplate, true); + logger.info("Generated GdScript protocol file:[{}] is in path:[{}]", file.getName(), file.getAbsolutePath()); + } + } + + private void createTemplateFile() throws IOException { + var byteBufferFile = new File(StringUtils.format("{}/{}", protocolOutputPath, "ByteBuffer.gd")); + var byteBufferTemplate = ClassUtils.getFileFromClassPathToString("gdscript/buffer/ByteBuffer.gd"); + FileUtils.writeStringToFile(byteBufferFile, StringUtils.format(byteBufferTemplate, protocolOutputRootPath), false); + } + + + private String protocol_imports_fold(ProtocolRegistration registration) { + var protocolId = registration.getId(); + var subProtocols = ProtocolAnalysis.getAllSubProtocolIds(protocolId); + var importBuilder = new StringBuilder(); + for (var subProtocolId : subProtocols) { + var name = EnhanceObjectProtocolSerializer.getProtocolClassSimpleName(subProtocolId); + importBuilder.append(StringUtils.format("const {} = preload(\"res://{}/{}/{}.gd\")", name, protocolOutputRootPath, GenerateProtocolPath.protocolPathSlash(protocolId), name)).append(LS); + } + return importBuilder.toString(); + } + + private String protocol_imports_default(ProtocolRegistration registration) { + var protocolId = registration.getId(); + var subProtocols = ProtocolAnalysis.getAllSubProtocolIds(protocolId); + var importBuilder = new StringBuilder(); + for (var subProtocolId : subProtocols) { + var protocolName = EnhanceObjectProtocolSerializer.getProtocolClassSimpleName(subProtocolId); + importBuilder.append(StringUtils.format("const {} = preload(\"res://{}/{}.gd\")", protocolName, protocolOutputRootPath, protocolName)).append(LS); + } + return importBuilder.toString(); + } + + private String protocol_json(ProtocolRegistration registration) { + var fields = registration.getFields(); + var fieldRegistrations = registration.getFieldRegistrations(); + var gdBuilder = new StringBuilder(); + gdBuilder.append("{"); + // when generate source code fields, use origin fields sort + var sequencedFields = ReflectionUtils.notStaticAndTransientFields(registration.getConstructor().getDeclaringClass()); + var params = new ArrayList(); + for (var field : sequencedFields) { + var fieldRegistration = fieldRegistrations[GenerateProtocolFile.indexOf(fields, field)]; + var fieldName = field.getName(); + var fieldType = gdSerializer(fieldRegistration.serializer()).fieldType(field, fieldRegistration); + if (fieldType.equals("String")) { + params.add(StringUtils.format("{}:'{}'", fieldName)); + } else { + params.add(StringUtils.format("{}:{}", fieldName)); + } + } + gdBuilder.append(StringUtils.joinWith(", ", params.toArray())); + gdBuilder.append("}"); + return gdBuilder.toString(); + } + + private String protocol_to_string(ProtocolRegistration registration) { + var fields = registration.getFields(); + var fieldRegistrations = registration.getFieldRegistrations(); + var gdBuilder = new StringBuilder(); + // when generate source code fields, use origin fields sort + var sequencedFields = ReflectionUtils.notStaticAndTransientFields(registration.getConstructor().getDeclaringClass()); + var params = new ArrayList(); + for (var field : sequencedFields) { + var fieldRegistration = fieldRegistrations[GenerateProtocolFile.indexOf(fields, field)]; + var fieldName = field.getName(); + var fieldType = gdSerializer(fieldRegistration.serializer()).fieldType(field, fieldRegistration); + if (fieldType.equals("Dictionary") || fieldType.startsWith("Array")) { + params.add(StringUtils.format("JSON.stringify(self.{})", field.getName())); + } else { + params.add(StringUtils.format("self.{}", field.getName())); + } + } + gdBuilder.append(StringUtils.joinWith(", ", params.toArray())); + return gdBuilder.toString(); + } + + private String protocol_field_definition(ProtocolRegistration registration) { + var protocolId = registration.getId(); + var fields = registration.getFields(); + var fieldRegistrations = registration.getFieldRegistrations(); + var gdBuilder = new StringBuilder(); + // 生成源代码字段的时候,按照原始定义的方式生成 + var sequencedFields = ReflectionUtils.notStaticAndTransientFields(registration.getConstructor().getDeclaringClass()); + for (int i = 0; i < sequencedFields.size(); i++) { + var field = sequencedFields.get(i); + IFieldRegistration fieldRegistration = fieldRegistrations[GenerateProtocolFile.indexOf(fields, field)]; + var fieldName = field.getName(); + // 生成注释 + var fieldNotes = GenerateProtocolNote.fieldNotes(protocolId, fieldName, CodeLanguage.GdScript); + for (var fieldNote : fieldNotes) { + gdBuilder.append(fieldNote).append(LS); + } + var fieldType = gdSerializer(fieldRegistration.serializer()).fieldType(field, fieldRegistration); + // 生成类型的注释 + gdBuilder.append(StringUtils.format("var {}: {}", fieldName, fieldType)); + if (fieldType.equals("Dictionary") || fieldType.equals("Array")) { + var typeNote = CodeGenerateTypeScript.toTsClassName(field.getGenericType().toString()); + gdBuilder.append(StringUtils.format(TAB_ASCII + "# {}", typeNote)); + } + gdBuilder.append(LS); + } + return gdBuilder.toString(); + } + + private String protocol_write_serialization(ProtocolRegistration registration) { + GenerateProtocolFile.localVariableId = 0; + var fields = registration.getFields(); + var fieldRegistrations = registration.getFieldRegistrations(); + var gdBuilder = new StringBuilder(); + if (registration.isCompatible()) { + gdBuilder.append("var beforeWriteIndex = buffer.getWriteOffset()").append(LS); + gdBuilder.append(StringUtils.format("buffer.writeInt({})", registration.getPredictionLength())).append(LS); + } else { + gdBuilder.append("buffer.writeInt(-1)").append(LS); + } + for (var i = 0; i < fields.length; i++) { + var field = fields[i]; + var fieldRegistration = fieldRegistrations[i]; + gdSerializer(fieldRegistration.serializer()).writeObject(gdBuilder, "packet." + field.getName(), 0, field, fieldRegistration); + } + if (registration.isCompatible()) { + gdBuilder.append(StringUtils.format("buffer.adjustPadding({}, beforeWriteIndex)", registration.getPredictionLength())).append(LS); + } + return gdBuilder.toString(); + } + + private String protocol_read_deserialization(ProtocolRegistration registration) { + GenerateProtocolFile.localVariableId = 0; + var fields = registration.getFields(); + var fieldRegistrations = registration.getFieldRegistrations(); + var gdBuilder = new StringBuilder(); + for (var i = 0; i < fields.length; i++) { + var field = fields[i]; + var fieldRegistration = fieldRegistrations[i]; + if (field.isAnnotationPresent(Compatible.class)) { + gdBuilder.append("if buffer.compatibleRead(beforeReadIndex, length):").append(LS); + var compatibleReadObject = gdSerializer(fieldRegistration.serializer()).readObject(gdBuilder, 1, field, fieldRegistration); + gdBuilder.append(TAB_ASCII).append(StringUtils.format("packet.{} = {};", field.getName(), compatibleReadObject)).append(LS); + continue; + } + var readObject = gdSerializer(fieldRegistration.serializer()).readObject(gdBuilder, 0, field, fieldRegistration); + gdBuilder.append(StringUtils.format("packet.{} = {}", field.getName(), readObject)).append(LS); + } + return gdBuilder.toString(); + } + +} diff --git a/protocol/src/main/java/com/zfoo/protocol/serializer/gdscript/GdArraySerializer.java b/protocol/src/main/java/com/zfoo/protocol/serializer/gdscript/GdArraySerializer.java index 6a8c4381..a3903fbe 100644 --- a/protocol/src/main/java/com/zfoo/protocol/serializer/gdscript/GdArraySerializer.java +++ b/protocol/src/main/java/com/zfoo/protocol/serializer/gdscript/GdArraySerializer.java @@ -42,7 +42,7 @@ public class GdArraySerializer implements IGdSerializer { public String fieldType(Field field, IFieldRegistration fieldRegistration) { var arrayField = (ArrayField) fieldRegistration; var registration = arrayField.getArrayElementRegistration(); - var type = GenerateGdUtils.gdSerializer(registration.serializer()).fieldType(field, registration); + var type = CodeGenerateGdScript.gdSerializer(registration.serializer()).fieldType(field, registration); return arrayType(type); } @@ -67,7 +67,7 @@ public class GdArraySerializer implements IGdSerializer { String element = "element" + GenerateProtocolFile.localVariableId++; GenerateProtocolFile.addTabAscii(builder, deep + 1); builder.append(StringUtils.format("for {} in {}:", element, objectStr)).append(LS); - GenerateGdUtils.gdSerializer(arrayField.getArrayElementRegistration().serializer()) + CodeGenerateGdScript.gdSerializer(arrayField.getArrayElementRegistration().serializer()) .writeObject(builder, element, deep + 2, field, arrayField.getArrayElementRegistration()); } @@ -94,7 +94,7 @@ public class GdArraySerializer implements IGdSerializer { builder.append(StringUtils.format("if ({} > 0):", size)).append(LS); GenerateProtocolFile.addTabAscii(builder, deep + 1); builder.append(StringUtils.format("for {} in range({}):", i, size)).append(LS); - String readObject = GenerateGdUtils.gdSerializer(arrayField.getArrayElementRegistration().serializer()) + String readObject = CodeGenerateGdScript.gdSerializer(arrayField.getArrayElementRegistration().serializer()) .readObject(builder, deep + 2, field, arrayField.getArrayElementRegistration()); GenerateProtocolFile.addTabAscii(builder, deep + 2); builder.append(StringUtils.format("{}.append({})", result, readObject)).append(LS); diff --git a/protocol/src/main/java/com/zfoo/protocol/serializer/gdscript/GdListSerializer.java b/protocol/src/main/java/com/zfoo/protocol/serializer/gdscript/GdListSerializer.java index d53b6fbf..144fed99 100644 --- a/protocol/src/main/java/com/zfoo/protocol/serializer/gdscript/GdListSerializer.java +++ b/protocol/src/main/java/com/zfoo/protocol/serializer/gdscript/GdListSerializer.java @@ -33,7 +33,7 @@ public class GdListSerializer implements IGdSerializer { public String fieldType(Field field, IFieldRegistration fieldRegistration) { var listField = (ListField) fieldRegistration; var registration = listField.getListElementRegistration(); - var type = GenerateGdUtils.gdSerializer(registration.serializer()).fieldType(field, registration); + var type = CodeGenerateGdScript.gdSerializer(registration.serializer()).fieldType(field, registration); return GdArraySerializer.arrayType(type); } @@ -58,7 +58,7 @@ public class GdListSerializer implements IGdSerializer { String element = "element" + GenerateProtocolFile.localVariableId++; GenerateProtocolFile.addTabAscii(builder, deep + 1); builder.append(StringUtils.format("for {} in {}:", element, objectStr)).append(LS); - GenerateGdUtils.gdSerializer(listField.getListElementRegistration().serializer()) + CodeGenerateGdScript.gdSerializer(listField.getListElementRegistration().serializer()) .writeObject(builder, element, deep + 2, field, listField.getListElementRegistration()); } @@ -85,7 +85,7 @@ public class GdListSerializer implements IGdSerializer { builder.append(StringUtils.format("if ({} > 0):", size)).append(LS); GenerateProtocolFile.addTabAscii(builder, deep + 1); builder.append(StringUtils.format("for {} in range({}):", i, size)).append(LS); - String readObject = GenerateGdUtils.gdSerializer(listField.getListElementRegistration().serializer()) + String readObject = CodeGenerateGdScript.gdSerializer(listField.getListElementRegistration().serializer()) .readObject(builder, deep + 2, field, listField.getListElementRegistration()); GenerateProtocolFile.addTabAscii(builder, deep + 2); builder.append(StringUtils.format("{}.append({})", result, readObject)).append(LS); diff --git a/protocol/src/main/java/com/zfoo/protocol/serializer/gdscript/GdMapSerializer.java b/protocol/src/main/java/com/zfoo/protocol/serializer/gdscript/GdMapSerializer.java index 040f9a7d..9aa97145 100644 --- a/protocol/src/main/java/com/zfoo/protocol/serializer/gdscript/GdMapSerializer.java +++ b/protocol/src/main/java/com/zfoo/protocol/serializer/gdscript/GdMapSerializer.java @@ -59,9 +59,9 @@ public class GdMapSerializer implements IGdSerializer { builder.append(StringUtils.format("for {} in {}:", key, objectStr)).append(LS); GenerateProtocolFile.addTabAscii(builder, deep + 2); builder.append(StringUtils.format("var {} = {}[{}]", value, objectStr, key)).append(LS); - GenerateGdUtils.gdSerializer(mapField.getMapKeyRegistration().serializer()) + CodeGenerateGdScript.gdSerializer(mapField.getMapKeyRegistration().serializer()) .writeObject(builder, key, deep + 2, field, mapField.getMapKeyRegistration()); - GenerateGdUtils.gdSerializer(mapField.getMapValueRegistration().serializer()) + CodeGenerateGdScript.gdSerializer(mapField.getMapValueRegistration().serializer()) .writeObject(builder, value, deep + 2, field, mapField.getMapValueRegistration()); } @@ -89,11 +89,11 @@ public class GdMapSerializer implements IGdSerializer { GenerateProtocolFile.addTabAscii(builder, deep + 1); builder.append(StringUtils.format("for {} in range({}):", i, size)).append(LS); - String keyObject = GenerateGdUtils.gdSerializer(mapField.getMapKeyRegistration().serializer()) + String keyObject = CodeGenerateGdScript.gdSerializer(mapField.getMapKeyRegistration().serializer()) .readObject(builder, deep + 2, field, mapField.getMapKeyRegistration()); - String valueObject = GenerateGdUtils.gdSerializer(mapField.getMapValueRegistration().serializer()) + String valueObject = CodeGenerateGdScript.gdSerializer(mapField.getMapValueRegistration().serializer()) .readObject(builder, deep + 2, field, mapField.getMapValueRegistration()); GenerateProtocolFile.addTabAscii(builder, deep + 2); diff --git a/protocol/src/main/java/com/zfoo/protocol/serializer/gdscript/GdSetSerializer.java b/protocol/src/main/java/com/zfoo/protocol/serializer/gdscript/GdSetSerializer.java index 245e677e..0652e567 100644 --- a/protocol/src/main/java/com/zfoo/protocol/serializer/gdscript/GdSetSerializer.java +++ b/protocol/src/main/java/com/zfoo/protocol/serializer/gdscript/GdSetSerializer.java @@ -33,7 +33,7 @@ public class GdSetSerializer implements IGdSerializer { public String fieldType(Field field, IFieldRegistration fieldRegistration) { var listField = (SetField) fieldRegistration; var registration = listField.getSetElementRegistration(); - var type = GenerateGdUtils.gdSerializer(registration.serializer()).fieldType(field, registration); + var type = CodeGenerateGdScript.gdSerializer(registration.serializer()).fieldType(field, registration); return GdArraySerializer.arrayType(type); } @@ -58,7 +58,7 @@ public class GdSetSerializer implements IGdSerializer { String element = "element" + GenerateProtocolFile.localVariableId++; GenerateProtocolFile.addTabAscii(builder, deep + 1); builder.append(StringUtils.format("for {} in {}:", element, objectStr)).append(LS); - GenerateGdUtils.gdSerializer(setField.getSetElementRegistration().serializer()) + CodeGenerateGdScript.gdSerializer(setField.getSetElementRegistration().serializer()) .writeObject(builder, element, deep + 2, field, setField.getSetElementRegistration()); } @@ -85,7 +85,7 @@ public class GdSetSerializer implements IGdSerializer { builder.append(StringUtils.format("if ({} > 0):", size)).append(LS); GenerateProtocolFile.addTabAscii(builder, deep + 1); builder.append(StringUtils.format("for {} in range({}):", i, size)).append(LS); - String readObject = GenerateGdUtils.gdSerializer(setField.getSetElementRegistration().serializer()) + String readObject = CodeGenerateGdScript.gdSerializer(setField.getSetElementRegistration().serializer()) .readObject(builder, deep + 2, field, setField.getSetElementRegistration()); GenerateProtocolFile.addTabAscii(builder, deep + 2); builder.append(StringUtils.format("{}.append({})", result, readObject)).append(LS); diff --git a/protocol/src/main/java/com/zfoo/protocol/serializer/gdscript/GenerateGdUtils.java b/protocol/src/main/java/com/zfoo/protocol/serializer/gdscript/GenerateGdUtils.java deleted file mode 100644 index ddc0b0fc..00000000 --- a/protocol/src/main/java/com/zfoo/protocol/serializer/gdscript/GenerateGdUtils.java +++ /dev/null @@ -1,263 +0,0 @@ -/* - * 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.gdscript; - -import com.zfoo.protocol.anno.Compatible; -import com.zfoo.protocol.collection.CollectionUtils; -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.registration.ProtocolAnalysis; -import com.zfoo.protocol.registration.ProtocolRegistration; -import com.zfoo.protocol.registration.field.IFieldRegistration; -import com.zfoo.protocol.serializer.CodeLanguage; -import com.zfoo.protocol.serializer.enhance.EnhanceObjectProtocolSerializer; -import com.zfoo.protocol.serializer.reflect.*; -import com.zfoo.protocol.serializer.typescript.CodeGenerateTypeScript; -import com.zfoo.protocol.util.ClassUtils; -import com.zfoo.protocol.util.FileUtils; -import com.zfoo.protocol.util.ReflectionUtils; -import com.zfoo.protocol.util.StringUtils; -import org.slf4j.Logger; -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_ASCII; - -/** - * @author godotg - */ -public abstract class GenerateGdUtils { - private static final Logger logger = LoggerFactory.getLogger(GenerateGdUtils.class); - - // custom configuration - public static String protocolOutputRootPath = "zfoogd"; - private static String protocolOutputPath = StringUtils.EMPTY; - - private static Map gdSerializerMap; - - public static IGdSerializer gdSerializer(ISerializer serializer) { - return gdSerializerMap.get(serializer); - } - - public static void init(GenerateOperation generateOperation) { - protocolOutputPath = FileUtils.joinPath(generateOperation.getProtocolPath(), protocolOutputRootPath); - FileUtils.deleteFile(new File(protocolOutputPath)); - - gdSerializerMap = new HashMap<>(); - gdSerializerMap.put(BooleanSerializer.INSTANCE, new GdBooleanSerializer()); - gdSerializerMap.put(ByteSerializer.INSTANCE, new GdByteSerializer()); - gdSerializerMap.put(ShortSerializer.INSTANCE, new GdShortSerializer()); - gdSerializerMap.put(IntSerializer.INSTANCE, new GdIntSerializer()); - gdSerializerMap.put(LongSerializer.INSTANCE, new GdLongSerializer()); - gdSerializerMap.put(FloatSerializer.INSTANCE, new GdFloatSerializer()); - gdSerializerMap.put(DoubleSerializer.INSTANCE, new GdDoubleSerializer()); - gdSerializerMap.put(StringSerializer.INSTANCE, new GdStringSerializer()); - gdSerializerMap.put(ArraySerializer.INSTANCE, new GdArraySerializer()); - gdSerializerMap.put(ListSerializer.INSTANCE, new GdListSerializer()); - gdSerializerMap.put(SetSerializer.INSTANCE, new GdSetSerializer()); - gdSerializerMap.put(MapSerializer.INSTANCE, new GdMapSerializer()); - gdSerializerMap.put(ObjectProtocolSerializer.INSTANCE, new GdObjectProtocolSerializer()); - } - - public static void clear() { - gdSerializerMap = null; - protocolOutputRootPath = null; - protocolOutputPath = null; - } - - public static void createProtocolManager(List protocolList) throws IOException { - var byteBufferFile = new File(StringUtils.format("{}/{}", protocolOutputPath, "ByteBuffer.gd")); - var byteBufferTemplate = ClassUtils.getFileFromClassPathToString("gdscript/buffer/ByteBuffer.gd"); - FileUtils.writeStringToFile(byteBufferFile, StringUtils.format(byteBufferTemplate, protocolOutputRootPath), false); - - var protocolManagerTemplate = ClassUtils.getFileFromClassPathToString("gdscript/ProtocolManagerTemplate.gd"); - var importBuilder = new StringBuilder(); - var initList = new ArrayList(); - for (var protocol : protocolList) { - var protocolId = protocol.protocolId(); - var name = protocol.protocolConstructor().getDeclaringClass().getSimpleName(); - importBuilder.append(StringUtils.format("const {} = preload(\"res://{}/{}/{}.gd\")", name, protocolOutputRootPath, GenerateProtocolPath.protocolPathSlash(protocolId), name)).append(LS); - initList.add(StringUtils.format("{}{}: {}", TAB_ASCII, protocolId, name)); - } - var initProtocols = StringUtils.joinWith(StringUtils.COMMA + LS, initList.toArray()); - protocolManagerTemplate = StringUtils.format(protocolManagerTemplate, importBuilder.toString().trim(), initProtocols); - var file = new File(StringUtils.format("{}/{}", protocolOutputPath, "ProtocolManager.gd")); - FileUtils.writeStringToFile(file, protocolManagerTemplate, true); - logger.info("Generated GdScript protocol manager file:[{}] is in path:[{}]", file.getName(), file.getAbsolutePath()); - } - - public static void createGdProtocolFile(ProtocolRegistration registration) throws IOException { - var protocolId = registration.protocolId(); - var registrationConstructor = registration.getConstructor(); - var protocolClazzName = registrationConstructor.getDeclaringClass().getSimpleName(); - - var includeSubProtocol = includeSubProtocol(registration); - var classNote = GenerateProtocolNote.classNote(protocolId, CodeLanguage.GdScript, TAB_ASCII, 0); - var fieldDefinition = fieldDefinition(registration); - var toStringJsonTemplate = toStringJsonTemplate(registration); - var toStringParams = toStringParams(registration); - var writeObject = writeObject(registration); - var readObject = readObject(registration); - - var protocolTemplate = ClassUtils.getFileFromClassPathToString("gdscript/ProtocolTemplate.gd"); - protocolTemplate = StringUtils.format(protocolTemplate, protocolId, protocolClazzName, includeSubProtocol, classNote, fieldDefinition.trim(), - toStringJsonTemplate, toStringParams, StringUtils.EMPTY_JSON, writeObject.trim(), readObject.trim()); - - var outputPath = StringUtils.format("{}/{}/{}.gd", protocolOutputPath, GenerateProtocolPath.protocolPathSlash(protocolId), protocolClazzName); - var file = new File(outputPath); - FileUtils.writeStringToFile(file, protocolTemplate, true); - logger.info("Generated GdScript protocol file:[{}] is in path:[{}]", file.getName(), file.getAbsolutePath()); - } - - private static String includeSubProtocol(ProtocolRegistration registration) { - var protocolId = registration.getId(); - var subProtocols = ProtocolAnalysis.getAllSubProtocolIds(protocolId); - - if (CollectionUtils.isEmpty(subProtocols)) { - return StringUtils.EMPTY; - } - var gdBuilder = new StringBuilder(); - for (var subProtocolId : subProtocols) { - var name = EnhanceObjectProtocolSerializer.getProtocolClassSimpleName(subProtocolId); - gdBuilder.append(StringUtils.format("const {} = preload(\"res://{}/{}/{}.gd\")", name, protocolOutputRootPath, GenerateProtocolPath.protocolPathSlash(protocolId), name)).append(LS); - } - return gdBuilder.toString(); - } - - private static String fieldDefinition(ProtocolRegistration registration) { - var protocolId = registration.getId(); - var fields = registration.getFields(); - var fieldRegistrations = registration.getFieldRegistrations(); - var gdBuilder = new StringBuilder(); - // 生成源代码字段的时候,按照原始定义的方式生成 - var sequencedFields = ReflectionUtils.notStaticAndTransientFields(registration.getConstructor().getDeclaringClass()); - for (int i = 0; i < sequencedFields.size(); i++) { - var field = sequencedFields.get(i); - IFieldRegistration fieldRegistration = fieldRegistrations[GenerateProtocolFile.indexOf(fields, field)]; - var fieldName = field.getName(); - // 生成注释 - var fieldNotes = GenerateProtocolNote.fieldNotes(protocolId, fieldName, CodeLanguage.GdScript); - for (var fieldNote : fieldNotes) { - gdBuilder.append(fieldNote).append(LS); - } - var fieldType = gdSerializer(fieldRegistration.serializer()).fieldType(field, fieldRegistration); - // 生成类型的注释 - gdBuilder.append(StringUtils.format("var {}: {}", fieldName, fieldType)); - if (fieldType.equals("Dictionary") || fieldType.equals("Array")) { - var typeNote = CodeGenerateTypeScript.toTsClassName(field.getGenericType().toString()); - gdBuilder.append(StringUtils.format(TAB_ASCII + "# {}", typeNote)); - } - gdBuilder.append(LS); - } - return gdBuilder.toString(); - } - - private static String toStringJsonTemplate(ProtocolRegistration registration) { - var fields = registration.getFields(); - var fieldRegistrations = registration.getFieldRegistrations(); - var gdBuilder = new StringBuilder(); - gdBuilder.append("{"); - // when generate source code fields, use origin fields sort - var sequencedFields = ReflectionUtils.notStaticAndTransientFields(registration.getConstructor().getDeclaringClass()); - var params = new ArrayList(); - for (var field : sequencedFields) { - var fieldRegistration = fieldRegistrations[GenerateProtocolFile.indexOf(fields, field)]; - var fieldName = field.getName(); - var fieldType = gdSerializer(fieldRegistration.serializer()).fieldType(field, fieldRegistration); - if (fieldType.equals("String")) { - params.add(StringUtils.format("{}:'{}'", fieldName)); - } else { - params.add(StringUtils.format("{}:{}", fieldName)); - } - } - gdBuilder.append(StringUtils.joinWith(", ", params.toArray())); - gdBuilder.append("}"); - return gdBuilder.toString(); - } - - private static String toStringParams(ProtocolRegistration registration) { - var fields = registration.getFields(); - var fieldRegistrations = registration.getFieldRegistrations(); - var gdBuilder = new StringBuilder(); - gdBuilder.append("["); - // when generate source code fields, use origin fields sort - var sequencedFields = ReflectionUtils.notStaticAndTransientFields(registration.getConstructor().getDeclaringClass()); - var params = new ArrayList(); - for (var field : sequencedFields) { - var fieldRegistration = fieldRegistrations[GenerateProtocolFile.indexOf(fields, field)]; - var fieldName = field.getName(); - var fieldType = gdSerializer(fieldRegistration.serializer()).fieldType(field, fieldRegistration); - if (fieldType.equals("Dictionary") || fieldType.startsWith("Array")) { - params.add(StringUtils.format("JSON.stringify(self.{})", field.getName())); - } else { - params.add(StringUtils.format("self.{}", field.getName())); - } - } - gdBuilder.append(StringUtils.joinWith(", ", params.toArray())); - gdBuilder.append("]"); - return gdBuilder.toString(); - } - - private static String writeObject(ProtocolRegistration registration) { - GenerateProtocolFile.localVariableId = 0; - var fields = registration.getFields(); - var fieldRegistrations = registration.getFieldRegistrations(); - var gdBuilder = new StringBuilder(); - if (registration.isCompatible()) { - gdBuilder.append("var beforeWriteIndex = buffer.getWriteOffset()").append(LS); - gdBuilder.append(TAB_ASCII).append(StringUtils.format("buffer.writeInt({})", registration.getPredictionLength())).append(LS); - } else { - gdBuilder.append(TAB_ASCII).append("buffer.writeInt(-1)").append(LS); - } - for (var i = 0; i < fields.length; i++) { - var field = fields[i]; - var fieldRegistration = fieldRegistrations[i]; - gdSerializer(fieldRegistration.serializer()).writeObject(gdBuilder, "packet." + field.getName(), 1, field, fieldRegistration); - } - if (registration.isCompatible()) { - gdBuilder.append(TAB_ASCII).append(StringUtils.format("buffer.adjustPadding({}, beforeWriteIndex)", registration.getPredictionLength())).append(LS); - } - return gdBuilder.toString(); - } - - private static String readObject(ProtocolRegistration registration) { - GenerateProtocolFile.localVariableId = 0; - var fields = registration.getFields(); - var fieldRegistrations = registration.getFieldRegistrations(); - var gdBuilder = new StringBuilder(); - for (var i = 0; i < fields.length; i++) { - var field = fields[i]; - var fieldRegistration = fieldRegistrations[i]; - if (field.isAnnotationPresent(Compatible.class)) { - gdBuilder.append(TAB_ASCII).append("if buffer.compatibleRead(beforeReadIndex, length):").append(LS); - var compatibleReadObject = gdSerializer(fieldRegistration.serializer()).readObject(gdBuilder, 2, field, fieldRegistration); - gdBuilder.append(TAB_ASCII + TAB_ASCII).append(StringUtils.format("packet.{} = {};", field.getName(), compatibleReadObject)).append(LS); - continue; - } - var readObject = gdSerializer(fieldRegistration.serializer()).readObject(gdBuilder, 1, field, fieldRegistration); - gdBuilder.append(TAB_ASCII).append(StringUtils.format("packet.{} = {}", field.getName(), readObject)).append(LS); - } - return gdBuilder.toString(); - } - -} diff --git a/protocol/src/main/java/com/zfoo/protocol/serializer/typescript/CodeGenerateTypeScript.java b/protocol/src/main/java/com/zfoo/protocol/serializer/typescript/CodeGenerateTypeScript.java index 09bcd6c6..ebbbc9b1 100644 --- a/protocol/src/main/java/com/zfoo/protocol/serializer/typescript/CodeGenerateTypeScript.java +++ b/protocol/src/main/java/com/zfoo/protocol/serializer/typescript/CodeGenerateTypeScript.java @@ -237,9 +237,9 @@ public class CodeGenerateTypeScript implements ICodeGenerate { var subProtocols = ProtocolAnalysis.getFirstSubProtocolIds(protocolId); // import other sub protocols for (var subProtocolId : subProtocols) { - var protocolClassName = EnhanceObjectProtocolSerializer.getProtocolClassSimpleName(subProtocolId); + var protocolName = EnhanceObjectProtocolSerializer.getProtocolClassSimpleName(subProtocolId); var path = GenerateProtocolPath.getRelativePath(protocolId, subProtocolId); - importBuilder.append(StringUtils.format("import {} from '{}/{}';", protocolClassName, path, protocolClassName)).append(LS); + importBuilder.append(StringUtils.format("import {} from '{}/{}';", protocolName, path, protocolName)).append(LS); } return importBuilder.toString(); } @@ -253,8 +253,8 @@ public class CodeGenerateTypeScript implements ICodeGenerate { // import other sub protocols var subProtocols = ProtocolAnalysis.getFirstSubProtocolIds(protocolId); for (var subProtocolId : subProtocols) { - var protocolClassName = EnhanceObjectProtocolSerializer.getProtocolClassSimpleName(subProtocolId); - importBuilder.append(StringUtils.format("import {} from './{}';", protocolClassName, protocolClassName)).append(LS); + var protocolName = EnhanceObjectProtocolSerializer.getProtocolClassSimpleName(subProtocolId); + importBuilder.append(StringUtils.format("import {} from './{}';", protocolName, protocolName)).append(LS); } return importBuilder.toString(); } diff --git a/protocol/src/main/resources/gdscript/ProtocolClassTemplate.gd b/protocol/src/main/resources/gdscript/ProtocolClassTemplate.gd new file mode 100644 index 00000000..b312d9e2 --- /dev/null +++ b/protocol/src/main/resources/gdscript/ProtocolClassTemplate.gd @@ -0,0 +1,29 @@ +${protocol_note} +class ${protocol_name}: + ${protocol_field_definition} + + const PROTOCOL_ID = ${protocol_id} + const PROTOCOL_CLASS_NAME = "${protocol_name}" + + func _to_string() -> String: + const jsonTemplate = "${protocol_json}" + var params = [${protocol_to_string}] + return jsonTemplate.format(params, "{}") + + static func write(buffer, packet): + if (packet == null): + buffer.writeInt(0) + return + ${protocol_write_serialization} + pass + + static func read(buffer): + var length = buffer.readInt() + if (length == 0): + return null + var beforeReadIndex = buffer.getReadOffset() + var packet = buffer.newInstance(PROTOCOL_ID) + ${protocol_read_deserialization} + if (length > 0): + buffer.setReadOffset(beforeReadIndex + length) + return packet diff --git a/protocol/src/main/resources/gdscript/ProtocolManagerTemplate.gd b/protocol/src/main/resources/gdscript/ProtocolManagerTemplate.gd index 2f95eaf4..cd85dd03 100644 --- a/protocol/src/main/resources/gdscript/ProtocolManagerTemplate.gd +++ b/protocol/src/main/resources/gdscript/ProtocolManagerTemplate.gd @@ -1,7 +1,7 @@ -{} +${protocol_imports} const protocols: Dictionary = { -{} + ${protocol_manager_registrations} } static func getProtocol(protocolId: int): diff --git a/protocol/src/main/resources/gdscript/ProtocolTemplate.gd b/protocol/src/main/resources/gdscript/ProtocolTemplate.gd index d9f9d391..24e1b783 100644 --- a/protocol/src/main/resources/gdscript/ProtocolTemplate.gd +++ b/protocol/src/main/resources/gdscript/ProtocolTemplate.gd @@ -1,19 +1,19 @@ -const PROTOCOL_ID = {} -const PROTOCOL_CLASS_NAME = "{}" -{} -{} -{} +const PROTOCOL_ID = ${protocol_id} +const PROTOCOL_CLASS_NAME = "${protocol_name}" +${protocol_imports} +${protocol_note} +${protocol_field_definition} func _to_string() -> String: - const jsonTemplate = "{}" - var params = {} + const jsonTemplate = "${protocol_json}" + var params = [${protocol_to_string}] return jsonTemplate.format(params, "{}") static func write(buffer, packet): if (packet == null): buffer.writeInt(0) return - {} + ${protocol_write_serialization} pass static func read(buffer): @@ -22,7 +22,7 @@ static func read(buffer): return null var beforeReadIndex = buffer.getReadOffset() var packet = buffer.newInstance(PROTOCOL_ID) - {} + ${protocol_read_deserialization} if (length > 0): buffer.setReadOffset(beforeReadIndex + length) return packet diff --git a/protocol/src/main/resources/gdscript/ProtocolsTemplate.gd b/protocol/src/main/resources/gdscript/ProtocolsTemplate.gd new file mode 100644 index 00000000..fe4db4f4 --- /dev/null +++ b/protocol/src/main/resources/gdscript/ProtocolsTemplate.gd @@ -0,0 +1 @@ +${protocol_class} \ No newline at end of file