示例#1
0
        private void WritePropertyValue(TagIndexEntry tagInfo, ResolvedTagPropertyInfo info, TagPropertyPatch patch)
        {
            if (info.RelativeOffset < 0)
            {
                Debugger.Break();
            }

            var propType = info.PropertyType;

            if (propType.IsGenericType)
            {
                propType = propType.GetGenericTypeDefinition();
            }

            if (propType.IsEnum)
            {
                propType = propType.GetEnumUnderlyingType();
            }

            if (this.DataWriters.TryGetValue(propType, out var writer))
            {
                writer(this.mapToPatch, tagInfo.Offset.Value + info.RelativeOffset, patch.Value);
            }
            else
            {
                Console.WriteLine($"Writing '{info.PropertyType}' values is not configured, skipping");
            }
        }
示例#2
0
        public void PatchProperty(TagIndexEntry tagInfo, TagPropertyPatch patch)
        {
            var propertyInfo = ResolvePropertyInfo(tagInfo, patch.PropertySelector);

            Logger.Log(propertyInfo.PropertyType.ToString() + " @ " + propertyInfo.RelativeOffset, Logger.Color.Magenta);

            WritePropertyValue(tagInfo, propertyInfo, patch);
        }
示例#3
0
        public void PatchBinaryData(TagIndexEntry tagInfo, TagBinaryPatch bin)
        {
            var patchOffset = tagInfo.Offset.Value + bin.RelativeOffset;

            Logger.Log(bin.Data.Length + "bytes @ " + bin.RelativeOffset, Logger.Color.Cyan);

            this.mapToPatch.Position = patchOffset;
            this.mapToPatch.Write(bin.Data);
        }
示例#4
0
        public static BaseTag CreateTag(uint id, string name, TagIndexEntry index, IH2Map map, MapStream reader)
        {
            var tagType = GetTypeForTag(index.Tag);

            BaseTag tag;

            if (tagType == null)
            {
                tag = new UnknownTag(id, index.Tag.ToString())
                {
                    Name   = name,
                    Length = (uint)index.DataSize,
                    Offset = (uint)index.Offset.Value,
                    InternalSecondaryMagic = map.SecondaryMagic + index.Offset.Value
                };
            }
            else
            {
                BaseTag instance;

                // PERF: check ctor existence ahead of time
                try
                {
                    //var ctor = tagType.GetConstructor(new[] { typeof(uint) });
                    //instance = (BaseTag)ctor.Invoke(new object[] { id });
                    instance = Activator.CreateInstance(tagType, new object[] { id }) as BaseTag;
                }
                catch
                {
                    instance = (BaseTag)FormatterServices.GetUninitializedObject(tagType);
                }

                tag = (BaseTag)BlamSerializer.DeserializeInto(instance,
                                                              tagType,
                                                              reader.GetStream(map.OriginFile),
                                                              index.Offset.Value,
                                                              map.SecondaryMagic,
                                                              map);
            }

            tag.Name          = name;
            tag.TagIndexEntry = index;
            tag.DataFile      = map.OriginFile;
            tag.PopulateExternalData(reader);

            return(tag);
        }
示例#5
0
        private ResolvedTagPropertyInfo ResolvePropertyInfo(TagIndexEntry tagInfo, string propertyPath)
        {
            var topTagType = TagFactory.GetTypeForTag(tagInfo.Tag);

            var steps = PropertyAccessorParser.ExtractProperties(propertyPath);

            var offset = 0;

            var stepType = topTagType;

            foreach (var step in steps)
            {
                var prop = stepType.GetProperty(step.PropertyName);

                if (prop == null)
                {
                    throw new Exception($"Couldn't find property '{step.PropertyName}' on type '{stepType}'");
                }

                if (step.AccessType == PropertyAccessorParser.PropertyAccessType.Normal)
                {
                    offset  += BlamSerializer.StartsAt(stepType, step.PropertyName);
                    stepType = prop.PropertyType;
                }
                else if (step.AccessType == PropertyAccessorParser.PropertyAccessType.ElementAccess)
                {
                    if (prop.PropertyType.IsArray == false || step.ElementArgument is not int)
                    {
                        throw new NotSupportedException("Only arrays are currently supported for element access");
                    }

                    var elementSize   = BlamSerializer.SizeOf(prop.PropertyType.GetElementType());
                    var elementOffset = (elementSize * ((int)step.ElementArgument));

                    if (prop.GetCustomAttribute <ReferenceArrayAttribute>() != null)
                    {
                        var startsAt = BlamSerializer.StartsAt(stepType, step.PropertyName);

                        // Read element array base offset
                        var baseOffset = new SecondaryOffset(this.originalMap, this.mapToPatch.ReadInt32At(tagInfo.Offset.Value + offset + startsAt + 4));

                        // baseOffset is the absolute offset, need to subtract tag offset and prior property offsets to get relative
                        offset += baseOffset.Value - tagInfo.Offset.Value - offset + elementOffset;
                    }
                    else if (prop.GetCustomAttribute <PrimitiveArrayAttribute>() != null)
                    {
                        offset += elementOffset;
                    }
                    else
                    {
                        throw new Exception("Only primitive and reference arrays are supported");
                    }

                    stepType = prop.PropertyType.GetElementType();
                }
            }

            return(new ResolvedTagPropertyInfo()
            {
                RelativeOffset = offset,
                PropertyType = stepType
            });
        }