UNPKG

il2cpp-dump-analyzer-mcp

Version:

Agentic RAG system for analyzing IL2CPP dump.cs files from Unity games

297 lines 12.8 kB
"use strict"; /** * C# Class Wrapper Generator for IL2CPP classes * Generates C# wrapper classes from IL2CPP class definitions with full type fidelity */ Object.defineProperty(exports, "__esModule", { value: true }); exports.ClassWrapperGenerator = void 0; const types_1 = require("./types"); const base_generator_1 = require("./base-generator"); /** * Generator for C# class wrappers from IL2CPP class definitions */ class ClassWrapperGenerator extends base_generator_1.BaseGenerator { /** * Validate the generation request for class wrapper generation * @param request Code generation request * @returns Validation result */ async validateRequest(request) { const errors = []; const warnings = []; // Check if request type is correct if (request.type !== types_1.GenerationType.CLASS_WRAPPER) { errors.push({ type: types_1.GenerationErrorType.VALIDATION_ERROR, message: `Invalid generation type: expected ${types_1.GenerationType.CLASS_WRAPPER}, got ${request.type}`, code: 'INVALID_GENERATION_TYPE', context: 'ClassWrapperGenerator.validateRequest' }); } // Check if source is an IL2CPP class const source = request.source; if (!source || typeof source !== 'object') { errors.push({ type: types_1.GenerationErrorType.VALIDATION_ERROR, message: 'Source entity is required and must be an object', code: 'INVALID_SOURCE_ENTITY', context: 'ClassWrapperGenerator.validateRequest' }); } else { // Check for required class properties const requiredProps = ['name', 'namespace', 'fullName', 'fields', 'methods']; for (const prop of requiredProps) { if (!(prop in source)) { errors.push({ type: types_1.GenerationErrorType.VALIDATION_ERROR, message: `Source entity missing required property: ${prop}`, code: 'MISSING_REQUIRED_PROPERTY', context: 'ClassWrapperGenerator.validateRequest' }); } } // Check if fields and methods are arrays if (source.fields && !Array.isArray(source.fields)) { errors.push({ type: types_1.GenerationErrorType.VALIDATION_ERROR, message: 'Source entity fields must be an array', code: 'INVALID_FIELDS_TYPE', context: 'ClassWrapperGenerator.validateRequest' }); } if (source.methods && !Array.isArray(source.methods)) { errors.push({ type: types_1.GenerationErrorType.VALIDATION_ERROR, message: 'Source entity methods must be an array', code: 'INVALID_METHODS_TYPE', context: 'ClassWrapperGenerator.validateRequest' }); } } // Check target language if (request.target.language !== 'csharp') { errors.push({ type: types_1.GenerationErrorType.VALIDATION_ERROR, message: `Unsupported target language: ${request.target.language}`, code: 'UNSUPPORTED_LANGUAGE', context: 'ClassWrapperGenerator.validateRequest' }); } // Warnings for potential issues if (source && source.name && !/^[A-Z][a-zA-Z0-9]*$/.test(source.name)) { warnings.push('Class name should follow PascalCase convention'); } return { isValid: errors.length === 0, errors: errors.map(err => ({ message: err.message, line: 1, column: 1, severity: 'error' })), warnings }; } /** * Parse the IL2CPP class source entity * @param request Code generation request * @returns Parsed class data */ async parseSourceEntity(request) { const source = request.source; const usings = new Set(); // Add basic using statements usings.add('using System;'); // Add Unity using if it's a MonoBehaviour if (source.isMonoBehaviour || source.baseClass === 'MonoBehaviour') { usings.add('using UnityEngine;'); } // Add using statements based on base class and interfaces if (source.baseClass) { const baseUsings = this.context.typeResolver.getUsingsForType(source.baseClass); baseUsings.forEach(using => usings.add(using)); } if (source.interfaces) { for (const interfaceType of source.interfaces) { const interfaceUsings = this.context.typeResolver.getUsingsForType(interfaceType); interfaceUsings.forEach(using => usings.add(using)); } } // Add using statements based on field and method types for (const field of source.fields || []) { const fieldUsings = this.context.typeResolver.getUsingsForType(field.type); fieldUsings.forEach(using => usings.add(using)); } for (const method of source.methods || []) { const returnUsings = this.context.typeResolver.getUsingsForType(method.returnType); returnUsings.forEach(using => usings.add(using)); for (const param of method.parameters || []) { const paramUsings = this.context.typeResolver.getUsingsForType(param.type); paramUsings.forEach(using => usings.add(using)); } } // Add additional using statements from options for (const additionalUsing of request.options.additionalUsings) { usings.add(`using ${additionalUsing};`); } return { name: source.name, namespace: source.namespace, fullName: source.fullName, baseClass: source.baseClass, interfaces: source.interfaces || [], fields: source.fields || [], methods: source.methods || [], isMonoBehaviour: source.isMonoBehaviour || false, typeDefIndex: source.typeDefIndex, usings }; } /** * Generate C# class wrapper code from parsed class data * @param parsedEntity Parsed class data * @param options Generation options * @returns Generated C# code */ async generateCode(parsedEntity, options) { let code = ''; // Add using statements const sortedUsings = Array.from(parsedEntity.usings).sort(); for (const usingStatement of sortedUsings) { code += `${usingStatement}\n`; } if (sortedUsings.length > 0) { code += '\n'; } // Add namespace declaration if (parsedEntity.namespace) { code += `namespace ${parsedEntity.namespace}\n{\n`; } // Add XML documentation if requested if (options.includeDocumentation) { const indent = parsedEntity.namespace ? ' ' : ''; code += `${indent}/// <summary>\n`; code += `${indent}/// Generated wrapper for ${parsedEntity.name}\n`; code += `${indent}/// IL2CPP TypeDefIndex: ${parsedEntity.typeDefIndex}\n`; code += `${indent}/// </summary>\n`; } // Add class declaration const indent = parsedEntity.namespace ? ' ' : ''; code += `${indent}public class ${parsedEntity.name}`; // Add inheritance const inheritance = []; if (parsedEntity.baseClass) { const resolvedBaseClass = this.context.typeResolver.resolveType(parsedEntity.baseClass); inheritance.push(resolvedBaseClass); } for (const interfaceType of parsedEntity.interfaces) { const resolvedInterface = this.context.typeResolver.resolveType(interfaceType); inheritance.push(resolvedInterface); } if (inheritance.length > 0) { code += ` : ${inheritance.join(', ')}`; } code += '\n' + indent + '{\n'; // Add fields if (parsedEntity.fields.length > 0) { code += this.generateFields(parsedEntity.fields, options, indent + ' '); code += '\n'; } // Add methods if (parsedEntity.methods.length > 0) { code += this.generateMethods(parsedEntity.methods, options, indent + ' '); } // Close class code += indent + '}\n'; // Close namespace if (parsedEntity.namespace) { code += '}\n'; } // Format the code according to style options return this.formatCode(code, options.codeStyle); } /** * Generate field declarations * @param fields Array of IL2CPP fields * @param options Generation options * @param indent Indentation string * @returns Generated field code */ generateFields(fields, options, indent) { let code = ''; for (const field of fields) { // Add attributes if requested if (options.includeUnityAttributes && field.attributes.length > 0) { for (const attribute of field.attributes) { code += `${indent}[${attribute}]\n`; } } // Add field declaration const accessModifier = field.isPublic ? 'public' : 'private'; const staticModifier = field.isStatic ? 'static ' : ''; const readonlyModifier = field.isReadOnly ? 'readonly ' : ''; const resolvedType = this.context.typeResolver.resolveType(field.type); code += `${indent}${accessModifier} ${staticModifier}${readonlyModifier}${resolvedType} ${field.name};\n`; } return code; } /** * Generate method declarations * @param methods Array of IL2CPP methods * @param options Generation options * @param indent Indentation string * @returns Generated method code */ generateMethods(methods, options, indent) { let code = ''; for (let i = 0; i < methods.length; i++) { const method = methods[i]; // Add XML documentation if requested if (options.includeDocumentation) { code += `${indent}/// <summary>\n`; code += `${indent}/// ${method.name} method\n`; code += `${indent}/// RVA: ${method.rva}, Offset: ${method.offset}\n`; code += `${indent}/// </summary>\n`; // Add parameter documentation for (const param of method.parameters) { code += `${indent}/// <param name="${param.name}">Parameter of type ${param.type}</param>\n`; } } // Add method signature const accessModifier = method.isPublic ? 'public' : 'private'; const staticModifier = method.isStatic ? 'static ' : ''; const virtualModifier = method.isVirtual ? 'virtual ' : ''; const overrideModifier = method.isOverride ? 'override ' : ''; const abstractModifier = method.isAbstract ? 'abstract ' : ''; const resolvedReturnType = this.context.typeResolver.resolveType(method.returnType); code += `${indent}${accessModifier} ${staticModifier}${virtualModifier}${overrideModifier}${abstractModifier}${resolvedReturnType} ${method.name}(`; // Add parameters const parameters = method.parameters.map(param => { const resolvedParamType = this.context.typeResolver.resolveType(param.type); return `${resolvedParamType} ${param.name}`; }); code += parameters.join(', '); code += ')'; // Add method body or semicolon for abstract methods if (method.isAbstract) { code += ';\n'; } else { code += '\n' + indent + '{\n'; code += indent + ' // TODO: Implement method\n'; if (resolvedReturnType !== 'void') { code += indent + ' throw new System.NotImplementedException();\n'; } code += indent + '}\n'; } // Add spacing between methods (except for the last one) if (i < methods.length - 1) { code += '\n'; } } return code; } } exports.ClassWrapperGenerator = ClassWrapperGenerator; //# sourceMappingURL=class-wrapper-generator.js.map