Все еще используете Denwer? Пора попробовать Open Server!

Сразу сделаю оговорку для тех, кто использует для web-разработки среду *NIX — конечно, это намного логичнее разрабатывать на том, на чем и будет работать. Спору нет.

Ну а тем кто все же не покинул мир Windows 🙂 да и еще разрабатывает с помощью этой платформы сайты, пора пересмотреть свой пакет приложений. Например вместо Denwer почему бы не попробовать Open Server, который, кстати, стартовал уже довольно давно — летом 2010. За это время он обрел версию 5.2.6. А количество скачиваний перевалило за миллион. Вобщем проект устоявшийся и к тому же очень функциональный.

настройка Open Server

Доступна быстрая смена версии PHP и других модулей. Можно настроить порты, домены, планировщик заданий и многое другое. Настройки применяются на лету. Если в связи с изменениями конфигурации необходим перезапуск сервера, он произойдет автоматически.

Кстати, если вы хотите вести разработку на PHP 7, то здесь Open Server не заменим. Denwer уже порядком устарел — в последней версии на данный момент доступен лишь PHP 5.3. Вобщем, как ни хорош был когда то Denwer, кажется ему пришла достойная замена.

SQLite в Unity

Хранение данных в базе данных, извините за тавтологию — это очень удобно. Сегодня мы рассмотрим как организовать подключение к встраиваемой БД SQLite в Unity. Это, на мой взгляд, гораздо лучше чем использовать PlayerPrefs. В примере используется Unity 5.3.1f1.

  1. Создаем БД любым доступным инструментом. Я использовал менеджер SQLite в виде плагина к Firefox. Файл БД надо сохранить в папке [путь_к_вашему_проекту_Unity]\Assets\StreamingAssets\. В примере используется имя файла db.bytes.
  2. Нам понадобятся библиотеки для доступа к SQLite. Скачать их можно отсюда. Скачиваем и распаковываем куда нибудь архив SQLite4Unity3d. Копируем папку Assets\Plugins\ из распакованного архива в [путь_к_вашему_проекту_Unity]\Assets\Plugins\.
  3. Теперь создаем в папке [путь_к_вашему_проекту_Unity]\Assets\Scripts\ файл DataService.cs:
    using SQLite4Unity3d;
    using UnityEngine;
    #if !UNITY_EDITOR
    using System.Collections;
    using System.IO;
    #endif
    using System.Collections.Generic;
    
    public class DataService  {
    	public SQLiteConnection _connection;
    
    	public DataService(string DatabaseName){
    #if UNITY_EDITOR
    		var dbPath = string.Format(@"Assets/StreamingAssets/{0}", DatabaseName);
    #else
            	// check if file exists in Application.persistentDataPath
            	var filepath = string.Format("{0}/{1}", Application.persistentDataPath, DatabaseName);
    
            	if (!File.Exists(filepath))
    		{
    			Debug.Log("Database not in Persistent path");
    			// if it doesn't ->
    			// open StreamingAssets directory and load the db ->
    #if UNITY_ANDROID 
    			var loadDb = new WWW("jar:file://" + Application.dataPath + "!/assets/" + DatabaseName);  // this is the path to your StreamingAssets in android
    			while (!loadDb.isDone) { }  // CAREFUL here, for safety reasons you shouldn't let this while loop unattended, place a timer and error check
    			// then save to Application.persistentDataPath
    			File.WriteAllBytes(filepath, loadDb.bytes);
    #elif UNITY_IOS
    			var loadDb = Application.dataPath + "/Raw/" + DatabaseName;  // this is the path to your StreamingAssets in iOS
    			// then save to Application.persistentDataPath
    			File.Copy(loadDb, filepath);
    #elif UNITY_WP8
    			var loadDb = Application.dataPath + "/StreamingAssets/" + DatabaseName;  // this is the path to your StreamingAssets in iOS
    			// then save to Application.persistentDataPath
    			File.Copy(loadDb, filepath);
    #elif UNITY_WINRT
    			var loadDb = Application.dataPath + "/StreamingAssets/" + DatabaseName;  // this is the path to your StreamingAssets in iOS
    			// then save to Application.persistentDataPath
    			File.Copy(loadDb, filepath);
    #endif
    			Debug.Log("Database written");
    		}
    		var dbPath = filepath;
    #endif
    		_connection = new SQLiteConnection(dbPath, SQLiteOpenFlags.ReadWrite | SQLiteOpenFlags.Create);
    		Debug.Log("Final PATH: " + dbPath);     
    	}
    }

    Этот код взят практически без изменений из проекта SQLite4Unity3d. Оттуда убраны лишние методы которые приведены там просто для примера. А так же переменная _connection сделана публичной. Как видно класс кроссплатформенный. Его можно использовать как под Windows, так и под Android или iOS. Я тестировал только на Android.

  4. Далее надо создать классы таблиц БД, к которым будем обращаться из Unity. Ниже приведен пример класса для таблицы Items. Вам нужно будет создать свои классы для каждой таблицы в согласии с вашими наименованиями полей и типами хранимых данных. Названия классов повторяют имена таблиц в БД, а наименования переменных-членов класса соответственно идентичны полям в таблице. Называем как нибудь файл скрипта, например Tables.cs, и сохраняем также в папку [путь_к_вашему_проекту_Unity]\Assets\Scripts\ :
    using SQLite4Unity3d;
    
    public class Items  {
    
    	[PrimaryKey, AutoIncrement]
    	public int Id { get; set; }
    	public string Item { get; set; }
    	public string Type { get; set; }
    	public string Subtype { get; set; }
    	public int Weight { get; set; }
    }
  5. Для иллюстрации работы с БД привожу пример:
    using UnityEngine;
    using System.Collections.Generic;
    
    public class PlayerScript : MonoBehaviour {
    	public DataService ds;
    
    	// Use this for initialization
    	void Start () {
    		// подключение к БД
    		ds = new DataService("db.bytes");
    
    		// создание таблицы (таблица будет создана на основании данных класса Items, код которого приведен выше)
    		ds._connection.CreateTable();
    
    		// аналог запроса INSERT INTO `Items` (`Item`, `Type`, `Sybtype`, `Weight`) VALUES ("Flyer", "aircraft", "glider", 500)
    		ds._connection.Insert (new Items{
    			Item = "Flyer",
    			Type = "aircraft",
    			Sybtype = "glider",
    			Weight = 500
    		});
    
    		// аналог запроса SELECT * FROM `Items` WHERE `Id`=1
    		Items item1 = ds._connection.Table ().Where (x => x.Id == 1).FirstOrDefault ();
    		// для примера выводим в консоль отладки значение поля Weight у записи с Id = 1
    		Debug.Log(item1.Weight);
    
    		// удаление таблицы Items
    		ds._connection.DropTable();
    	}
    
    	// Update is called once per frame
    	void Update () {
    
    	}
    }

    Как видно из комментариев, сначала создается таблица Items на основании одноименного класса. Затем в нее вставляется запись. Следующим запросом из записи извлекаются данные и выводятся в консоль отладки. В конце таблица уничтожается.
    Чтобы протестировать этот код в вашем проекте, прикрепите его к какому нибудь объекту на сцене.

Кстати, вместо команды Insert можно использовать Update для обновления данных или InsertOrReplace для вставки или замены. Только в этом случае нужно добавить в объект еще и поле Id, для того чтобы можно было идентифицировать запись:

ds._connection.InsertOrReplace (new Items{
	Id = 1,
	Item = "Flyer",
	Type = "aircraft",
	Sybtype = "glider",
	Weight = 1000
});

Понятно что в примере приведены простейшие запросы, но этого уже достаточно чтобы начать использовать SQLite в Unity.
В заключение ещё один момент. При компиляции проекта для Andriod, Unity выдал ошибку — ему не понравились «лишние» кроссплатформенные библиотеки SQLite в папке Assets\Plugins\. Пришлось на время компиляции убрать оттуда вложенные папки WP8, x64 и x86. После компиляции возвращаем их назад, а то теперь проект не будет запускаться в отладчике Unity. Может есть более удобное решение, но я пока его не нашел (да и не искал).

1062: Duplicate entry ‘2147483647’ for key ‘PRIMARY’ или Проблема 2038 года

Наверное помните раскрученную проблему 2000? А все из-за того что кто-то заранее не подумал о том что будет через каких то 30 лет и использовал в программном обеспечении 2-ух значное обозначение года. И надо сказать, что проблема 2000 не единственная в своем роде. Наверное еще рановато об этом говорить, но назревает еще и проблема 2038 года. Поясню что имеется в виду. Попробуйте запустить следующий PHP-код:

<?php echo date("d.m.Y H:i", 2147483647); ?>

На выходе получим: 19.01.2038 06:14. А теперь увеличьте число на 1. Получилось 13.12.1901 23:15 что не соответствует истине. А все потому что метка времени UNIX при этом выходит за рамки диапазона типа данных Integer.

Хотя проблема 2038 года — это конечно больше шутка. Но однажды при записи данных в MySQL базу данных я получил ошибку:

1062: Duplicate entry ‘2147483647’ for key ‘PRIMARY’

Дело в том что для первичного ключа использовалось поле с типом данных INT. И так получилось, что AUTO INCREMENT вышел за пределы числа 2147483647, максимального для INT. Решение простое в данном случае — пришлось использовать тип данных BIGINT. Так что думайте сами, решайте сами …

Не запускается The Crew

В гости приехал племянник, которому подарили Uplay-ключ игры The Crew. Естественно захотели запустить его (её?) на нашем «слегка игровом» HTPC. К тому моменту на компьютере уже было 4Gb RAM (2 шт по 2Gb, то есть в двухканальном режиме). Минимальные требования игры, помимо памяти, заявлены такие: процессор Intel Core2 Quad Q9300 @ 2,5 ГГц или AMD Athlon II X4 620 @ 2,6 ГГц; видеокарта NVIDIA GeForce GTX260 или AMD Radeon HD4870. Это несколько мощнее чем начинка имеющегося HTPC (g1620 + GT630), но не намного. И как оказалось позднее, комфортно поиграть на средних настройках (и на среднем разрешении) вполне можно. Но вначале игра вообще не запускалась. На тот момент была установлена Windows 7 32bit, которая естественно видела только 3,5Gb ОЗУ из 4-ёх, и как оказалось вообще не поддерживала Crew.

Переустановили Win 7 64bit. Но игра по прежнему не подавала признаков жизни. Никаких ошибок не отображалось, просто вообще нет реакции на запуск. Решили немного обновить компоненты системы, в частности MS Framework — ничего не изменилось.

Топтались на месте довольно долго, потом решили попробовать запустить игру от Администратора. Также назначили запуск от Админа и для клиентов Uplay и Steam (он в данном случае тоже был задействован — хотя игра от Uplay, она приписана к аккаунту Steam). После этого наметился определенный прогресс — на экране появилась ошибка! В ней система нам поведала что для запуска не хватает xinput1_3.dll.

Скачали указанную библиотеку и положили её в папку игры: c:\Program Files (x86)\Steam\steamapps\common\The Crew\. А также в папку c:\windows\SysWOW64\. Но не тут то было — теперь выпала ошибка с кодом 0xc000007b. В связи с этим нашли информацию, что надо обновить DirectX. Обновили с помощью утилиты dxwebsetup.exe (её можно скачать на официальном сайте Microsoft). Но дело было не в этом — ошибка появилась вновь.

В конце концов, когда уже почти отчаялись запустить Crew, помог неожиданный ход. После того как попробовали несколько версий xinput1_3.dll, найденных в сети, и ни одна не подошла, обратили внимание что в папке Uplay тоже есть такая библиотека. Скопировали именно её в вышеупомянутые папки c:\Program Files (x86)\Steam\steamapps\common\The Crew\ и  c:\windows\SysWOW64\. Запуск игры произвели через файл TheCrewLauncher.exe из папки The Crew. После этого всё наконец заработало!

В общем Win 64bit нужен без вопросов. Возможно один из промежуточных упомянутых шагов тоже сыграл роль, проверять повторно не стали. Но решающим было именно копирование xinput1_3.dll из папки Uplay в системную папку c:\windows\SysWOW64\ и папку игры. У некоторых, похоже, бывают проблемы запуска The Crew немного иного характера, но может данный опыт тоже пригодится.

Wi-Fi повторитель (репитер) из компьютера на базе Windows 7

Проблема покрытия (или не покрытия) помещения сетью Wi-Fi встречается довольно часто. Решить её можно с помощью использования более мощного сетевого оборудования, а так же с помощью Wi-Fi репитеров. Ну или обойтись проводной сетью. Однако в некоторых случаях можно обойтись использованием в качестве повторителя или репитера одного из компьютеров.

Чтобы это сделать в ОС Windows 7, достаточно просто запустить маленькую программку WiFi Repeater с двумя параметрами. Кстати, эти параметры лучше прописать в ярлыке, чтобы не вводить каждый раз. Подробнее о том как сделать эту программку из bat-файла, смотрите внизу поста. Ранее я выложил на нее ссылку, но Яндекс посчитал ее вредоносной и пришлось убрать.

wifi repeater

Первый параметр (на скриншоте netname) — имя сети, которая будет продолжать основную сеть. Второй (на скриншоте netkey) — ключ сети. Запустить программу нужно с правами администратора. Сама программа в данном примере находится в корне диска C, что не является условием для её работы.

wifi repeater

Если все было сделано правильно и ваш Wi-Fi адаптер поддерживается, то в Центре управления сетями и общим доступом появится новая сеть. В моем случае она называется aero2.

wifi repeater

Если у второй сети нет доступа в интернет, нужно зайти в свойства основного беспроводного соединения, вкладка «Доступ». Там нужно поставить галочку «Разрешить другим пользователям сети использовать подключение к Интернету данного компьютера».

wifi repeater

Теперь устройства, которые плохо видели основную Wi-Fi сеть, смогут подключатся через созданный программно репитер.

P.S. Итак как упоминалось выше, программа WiFi Repeater упомянутая выше — это не совсем программа. Это просто bat-файл преобразованный в exe-файл. Содержимое bat-файла приведено ниже:

@echo off
netsh wlan set hostednetwork mode=allow ssid="%1" key="%2" keyUsage=persistent
netsh wlan start hostednetwork

Его запуск, соответственно, будет иметь тот же эффект. Можно и не использовать параметры bat-файла, а прописать их внутри — кому как удобнее.


Так же интересно…
Займитесь самостоятельным выбором мебели, присмотрите для своего дома столовые сервизы, всевозможные отдельные предметы из фарфора или же чайные сервизы и на минутку представьте, как они будут выглядеть в вашем жилище.