Unity 3D: Используем текстурки из DLL

» Раздел: Программирование - редакторы

Всем привет, сегодня я пришел с легенькой темой, которая, однако, требует некоторых усилий на реализацию.
Когда программируются редакторы мы повсеместно используем нестандартные иконки (если, конечно, хотим сделать качественный продукт - нужно поработать над оформлением).
Предположим, что на выходе вы хотите получить некоторый редактор одним DLL файлом. Но вот иконки, которые вы вынуждены хранить в одной папке с проектом ну просто портят всю картину!
Все мы знаем, что есть стандартная возможность "пришить ресурсы к DLL". Именно это и делается с картинками.
Но вот о том, как с ними взаимодействовать - я сегодня и расскажу.
Всё до безумия просто и уже готово для вас. Условлюсь лишь на том, что выдаю материал "как есть", без всяких универсальностей и подгона под статью - по сути там только две функции, в которых легко разобраться самим.
Предполагается, что для формирования самой DLL вы используете плагин UnityVS и все настройки уже проставлены верно.

Сама работа

  1. Создаете папку для ресурсов в проекте вашей DLL (например Resources) и кидаете туда нужные вам картинки.
Обязательно нужно выставить свойство "BuildAction = Embedded Resource".
Важно: ни в коем случае не надо пытаться использовать стандартный Resource-файл, если вы сформировали такой - удалите его нафиг. Нам нужны только картинки, Unity не поддерживает тип Bitmap, который там используется.
  1. Далее разбираемся в этом скрипте и делаем по аналогии:
    public static class Icons
     {
         public static Texture2D 
             MultiCreate0,
             MultiCreate1,
             MultiCreate2,
             MultiPick0,
             MultiPick1,
             SingleCreate0,
             SingleCreate1;

         public const string ManifestPath = "SpriteMaper.Editor.Resources.";

         static Icons()
         {
             var fields =
                 typeof (Icons)
                     .GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static)
                     .Where(x => x.FieldType == typeof (Texture2D))
                     .ToList();
             var assembly = typeof (Icons).Assembly;
             Debug.Log(fields.Count);
             foreach (FieldInfo field in fields)
                 field.SetValue(null, LoadTextureResource(assembly, field.Name, 64, 64));
         }
         
         public static Texture2D LoadTextureResource(Assembly assembly, string resourceName, int width, int height, FilterMode filterMode = 0)
         {
             Texture2D textured = null;
             try
             {
                 var manifestResourceStream = assembly.GetManifestResourceStream(ManifestPath + resourceName + ".png");
                 if (manifestResourceStream != null)
                 {
                     using (manifestResourceStream)
                     {
                         textured = new Texture2D(width, height, TextureFormat.ARGB32, false, true)
                         {
                             filterMode = filterMode
                         };
                         textured.LoadImage(ReadToEnd(manifestResourceStream));
                         textured.hideFlags = HideFlags.HideAndDontSave;
                         return textured;
                     }
                 }
             }
             catch {}
             if (textured == null)
                 Debug.LogError("Missing Dll resource: " + resourceName);
             return textured;
         }

         private static byte[] ReadToEnd(Stream stream)
         {
             byte[] buffer4;
             long position = 0L;
             if (stream.CanSeek)
             {
                 position = stream.Position;
                 stream.Position = 0L;
             }
             try
             {
                 int num3;
                 var buffer = new byte[0x1000];
                 int offset = 0;
                 while ((num3 = stream.Read(buffer, offset, buffer.Length - offset)) > 0)
                 {
                     offset += num3;
                     if (offset == buffer.Length)
                     {
                         int num4 = stream.ReadByte();
                         if (num4 != -1)
                         {
                             var buffer2 = new byte[buffer.Length * 2];
                             Buffer.BlockCopy(buffer, 0, buffer2, 0, buffer.Length);
                             Buffer.SetByte(buffer2, offset, (byte)num4);
                             buffer = buffer2;
                             offset++;
                         }
                     }
                 }
                 byte[] dst = buffer;
                 if (buffer.Length != offset)
                 {
                     dst = new byte[offset];
                     Buffer.BlockCopy(buffer, 0, dst, 0, offset);
                 }
                 buffer4 = dst;
             }
             finally
             {
                 if (stream.CanSeek)
                     stream.Position = position;
             }
             return buffer4;
         }
     }
Для вашего проекта будут некоторые отличия:
  • Исправьте константу ManifestPath на нужное вам значение. Обычно это название вашего основного пространства имен + ".Resources." или ".Properties.Resources." на конце. Пространство имен можно посмотреть в свойствах проекта.
  • У вас будут другие поля для ваших Texture2D файлов
  • Мой вариант конструктора создает иконки размером 64 на 64 с помощью рефлексии. Вы можете использовать другой подход и вручную перебрать всех нужные вам иконки. Для ручного перебора просто используйте эту функцию:
LoadTextureResource(assembly, textureName, 64, 64)
  • Возможно вы имеет файлы с другим расширением (не .png). В этом случае участок кода можно изменить:
Находим:
var manifestResourceStream = assembly.GetManifestResourceStream(ManifestPath + resourceName + ".png");
И меняем расширение.
Далее можно спокойно использовать такие текстурки, не засоряя папку проекта:
Всем спасибо за внимание.

Просмотров: 1 063

alexprey #1 - 2 года назад 0
Далее разбираемся в этом скрипте и делаем по аналогии
А почему бы не воспользоваться T4?
Devion #2 - 2 года назад (отредактировано ) 0
alexprey, дополню по возможности, если она будет конечно. Вообще я хз сам откуда достать скажем размер иконки, потому забиваю вручную.
alexprey #3 - 2 года назад 0
Extravert, так в T4 можно сделать так, чтобы он грузил эту иконку и смотрел ее размеры
Devion #4 - 2 года назад 0
alexprey, верю на слово. Я просто с генератором этим не работал особо, и времени разбираться сейчас в нём нет.
alexprey #5 - 2 года назад 0
Extravert, Ну я так понял там нативный шарп используется для генерации, хотя могу и ошибаться, тоже не работал, но у нас активно используется. Сканируется ресурсный файл и генерируются свойства для получения значений от туда