egametang/ET · critical · Exception

OpcodeType not found opcode: {type.FullName}

Error message

OpcodeType not found opcode: {type.FullName}

What it means

OpcodeType.GetOpcode(Type) returns the registered opcode for a message type; a value of 0 means the type was never registered. The framework treats unregistered messages as a fatal serialization contract error.

Source

Thrown at Packages/cn.etetet.core/Scripts/Core/Share/Network/OpcodeType.cs:64

                    var attrs = type.GetCustomAttributes(typeof (ResponseTypeAttribute), false);
                    if (attrs.Length == 0)
                    {
                        Log.Error($"not found responseType: {type}");
                        continue;
                    }

                    ResponseTypeAttribute responseTypeAttribute = attrs[0] as ResponseTypeAttribute;
                    this.requestResponse.Add(type, CodeTypes.Instance.GetType($"ET.{responseTypeAttribute.Type}"));
                }
            }
        }
        
        public ushort GetOpcode(Type type)
        {
            ushort opcode = this.typeOpcode.GetValueByKey(type);
            if (opcode == 0)
            {
                throw new Exception($"OpcodeType not found opcode: {type.FullName}");
            }
            return opcode;
        }

        public Type GetType(ushort opcode)
        {
            Type type = this.typeOpcode.GetKeyByValue(opcode);
            if (type == null)
            {
                throw new Exception($"OpcodeType not found type: {opcode}");
            }
            return type;
        }

        public Type GetResponseType(Type request)
        {
            if (!this.requestResponse.TryGetValue(request, out Type response))
            {

View on GitHub (pinned to 5cab01f7a8)

Solutions

  1. Confirm the type has the message attribute and is in a scanned assembly.
  2. Re-run the Luban/opcode code generation so the opcode table includes the type.
  3. Ensure the message assembly is loaded before OpcodeType initialization.

Example fix

// before
ushort op = OpcodeType.Instance.GetOpcode(typeof(MyNewMessage));
// after
// add [Message(...)]; regenerate opcodes; then:
ushort op = OpcodeType.Instance.GetOpcode(typeof(MyNewMessage));
Defensive patterns

Strategy: validation

Validate before calling

if (!OpcodeType.Instance.IsRegistered(type)) throw new InvalidOperationException($"{type} has no opcode; regenerate protocol");
ushort op = OpcodeType.Instance.GetOpcode(type);

Type guard

public bool IsRegistered(Type t) => typeOpcode.ContainsKey(t);

Try / catch

null

Prevention

When it happens

Trigger: Sending a message Type that was not scanned by CodeTypes or lacks the message/protocol attributes, or sending a type from an assembly that wasn't loaded at registration time.

Common situations: New message class added without [Message]/[ProtoContract] attribute, the assembly not passed to CodeTypes, or hotfix code referencing a type compiled out of the opcode generation.

Related errors


AI-assisted analysis of egametang/ET@5cab01f7a8 (2026-08-13). Data as JSON: /api/errors/0bd4c89736adfa49. Report an issue: GitHub.