MySql can’t open files after upgrade on Debian wheezy

So I upgraded a lot of stuff on one of my Debian servers. Afterwards my pages were all offline due to MySql not being able to access files. Interestingly enough most of what the almighty search-engine put out was not working, actually even misleading. So if you see this error:

ERROR 1016 (HY000) at line 1: Can't open file: './mysql/db.frm' (errno: 24)

Don’t adjust anything in your security settings. All you need to do here is add the following line to the mysqld section in your /etc/mysql/my.cnf:

[mysqld]
open-files-limit = 65535

Restart the MySql server and check connect to it and check the value the following way:

mysql> SHOW VARIABLES LIKE 'open%';
+------------------+-------+
| Variable_name    | Value |
+------------------+-------+
| open_files_limit | 65535 |
+------------------+-------+
1 row in set (0.00 sec)

file_get_contents gets stuck on redirects

It took me quite a while to pin down why something was failing on a live system. I tried adding timeouts, to the context, but what killed it in the end was the max_execution time of PHP. With no error message to work on and being able to run it with curl every time, I finally figured out that it was the 301 redirect for an image that then simply was not followed.
So in the future I rather use a little curl snipped instead:

 $ch = curl_init();
 curl_setopt($ch, CURLOPT_URL, $url);
 curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
 curl_setopt($ch, CURLOPT_BINARYTRANSFER, true);
 curl_setopt($ch, CURLOPT_HEADER, false);
 curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5);
 curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
 $contents = curl_exec($ch);
 curl_close($ch);

is (maybe not yet fully) equivalent to

 $contents = @file_get_contents($url);

Add logging for GuzzleHttp (Guzzle6) to text-file

It is not really documented much, therefore I thought why not leave a snippet on the world wide dump ๐Ÿ˜€

$monologHandler = new Monolog\Logger(
    'Logger',
    array(
        new Monolog\Handler\StreamHandler('/tmp/log.txt', Monolog\Logger::DEBUG)
    )
);

$stack = GuzzleHttp\HandlerStack::create();
$stack->push(
    GuzzleHttp\Middleware::log(
        $monologHandler,
        new GuzzleHttp\MessageFormatter('{req_body} - {res_body}')
    )
);
$guzzleClient = new \GuzzleHttp\Client(
    array('handler' => $stack)
);
return $guzzleClient;

Be aware that so far this logging can interfere with you application, as it reads the content of a stream and prints it!

IRC Client for UDK

I have spent a little time trying to bring a simple irc client to the UDK. I am very happy to announce that I was successful. Based on some of the ut2k4 code I rewrote the client myself.

There are some restrictions in the UDK when it comes to dealing with events. Events are all linked to the Engine and therefore i could not simply write event listeners that would react to messages once received. To work around that Problem I added the Interface IngameChat. It is now possible to add even multiple Receivers (through Decoration) if your game requires that. However a simple always accessible graphical Lobby would do just fine.

I will keep you updated with further implementations around that, because I have quite a few things on my mind already ๐Ÿ™‚

So far I need to add some documentation, but if you want to test it, there is a mutator that allows to add it to any gametype.


https://github.com/ToxikkModdingTeam/IngameChat

First Toxikk Mutator

I have actually finished it quite a while ago, but I am only going to release it now ๐Ÿ™‚

What does this Mutator do?
It modifies the cells to give it new properties. First of all dropping the cell using the command dropflag will actually allow it to be passed now. This should make the game a little more agile since passing can help distributing the damage over multiple people and it can actually be used to get the flag over the map quicker.
Multiple configuration values allow to adjust the way it behaves. If you reduce the mass, the momentum of a rocket explosion will throw the cell further away.

The second feature allows the cell to be destroyed when bInvulnerable is set to false. Adjust the CellHealthMax to define how strong it is against fire. This can be used to quickly deny a capture when you are out of range. It also limits the amount of passes failing since it takes fall-damage. The property CellMaxFallSpeed sets the limit to the maximum speed it can have when it is hitting a wall or the ground without taking damage.

The last feature is the explosion when the cell gets destroyed. By default the damage dealt is 90, so you can actually kill people with that explosion. You can adjust the momentum and the radius.

How to configure:
The mutator can be configured through the ini. You either start the game with the mutator once and create the ini, or just place it in the config folder with the name UDKPassableCellMutator.ini

[PassableCellMutator.PassableCellMutator]
bConfigInitialized=True
bInvulnerable=False
InheritedVelocity=0.750000
ThrowingVelocity=1200.000000
BounceDampeningFactor=0.400000
CellHealthMax=200
CellMaxFallSpeed=800.000000
CellMass=75.000000
ExplosionDamage=90.000000
ExplosionRadius=1200.000000
ExplosionMomentum=30000.000000

Todo:
Currently I have not fully localized the strings used in the mutator. I will revise it as soon as toxikk is released.

Download:
PassableCellMutator

Is your Apache2 slow?

I wanted to locally debug a remote page. Downloaded the source, kept the configuration intact and changed my hosts file to let the url of the page point to 127.0.0.1. Debugging was a pain, since requests took forever to be delivered.

First of all i tried to get rid of the following warning:

Could not reliably determine the server's fully qualified domain name, using 127.0.1.1. Set the 'ServerName' directive globally to suppress this message

I added the following to the apache2.conf (using ubuntu).

ServerName 127.0.0.1:80

Later on i cam accross an entry in my database that tracked the ip and it was ::ffff:7f00:1 which is an alternative to writing ::ffff:127.0.0.1 and that is my ipv4 loalhost in the ipv6 space. I then disabled ipv6 by only allowing ipv4:

Listen 0.0.0.0:80

Now pages are finally delivered in milliseconds again.

Remote Console Debugging with PhpStorm

Have you ever tried to run unit-tests or a console application on a remote environment and you just wanted to understand why it was failing on the remote environment?

There is a little icon on top of the application right below the main menu:
PHPStorm Remote Debugging option
Source

When you click it your PhpStorm is already ready for remote connections. The (sadly outdated) blog post also states that you need to prepare a server for this. In Version 8 of Storm you do it like this:

  • Go to Settings -> Languages & Frameworks -> PHP -> Servers
  • Add a Server using the + Icon on the top left of the settings window
  • Name it Console (or anything that makes it more meaningful)
  • Add the host of the remote environment
  • Finally be sure to set up the path mapping if needed!

Now in the console enter:

export PHP_IDE_CONFIG="serverName=Console"
export XDEBUG_CONFIG="remote_host=$(echo $SSH_CLIENT | awk '{print $1}') idekey=PHPSTORM"

Source

The good thing about the last line here is that it automatically places the correct IP of your current connection into the configuration and it is very unlikely that you have to adjust it.

Happy Debugging!

Update:

I guess it is kind of worth mentioning that this does not necessarily work with โ€œvagrant sshโ€. Depending on your vagrant configuration, NAS, Host only etc it could give you an ip that you are not really listening on on the host.

It works if i connect manually:

ssh vagrant@192.168.58.68
export -p
declare -x SSH_CLIENT=โ€192.168.58.1 59179 22โ€ณ

With

vagrant ssh

i get:

declare -x SSH_CLIENT=โ€10.0.2.2 59233 22โ€ณ

Which i could not even find in my list after running ifconfig.

UDK settings storage on steam

I am assuming you have a nice front-end for your users to store their settings. So far everything is stored locally in the inis and if you are still patching the game regularly you probably have users complaining their inis are constantly wiped.

One way to deal with it is to use one of the many OnlineSubsystems available in UDK. In this case I will show you a few functions that will help you store those settings. I decided to store the settings in JSON format for readability but theoretically you can come up with your own format. Also you can also decide to prepare the JSON only when saving the settings and converting the settings as one later on and adjust the following functions to take the settings as a parameter. The delegates however need to be of a
In this case this code is stored in a base class that all settings pages are inheriting from.

First of all we add the settings and the subsystem:

var JsonObject SettingsAsJson;
var OnlineSubsystemSteamworks OnlineSubSteam;

A factory Method for the Subsystem:

/**
 * Factory method for the steam subsystem.
 */
protected function OnlineSubsystemSteamworks GetOnlineSubsytem()
{
   if (OnlineSubSteam == None)
   {
      OnlineSubSteam = OnlineSubsystemSteamworks(class'GameEngine'.static.GetOnlineSubsystem());
   }

   return OnlineSubSteam;
}

Since the subsystem stores files in an array of bytes i wrote 2 conversion methods:

/**
 * Converts the given byte array to a json object.
 */
protected function JsonObject ByteArrayToJson(array<byte> SettingsBuffer)
{
   local JsonObject SettingsJson;
   local int i;
   local string Content;

   for (i=0; i<SettingsBuffer.Length; i++)
   {
      Content $= Chr(SettingsBuffer[i]);
   }

   SettingsJson = class'JsonObject'.static.DecodeJson(Content);

   return SettingsJson;
}

/**
 * Converts a given jsonobject to a byte array.
 */
protected function array<byte> JsonObjectToByteArray(JsonObject JsonSettings)
{
   local array<byte> SettingsBuffer;
   local string Content;
   local int i;

   Content = class'JsonObject'.static.EncodeJson(JsonSettings);
   
   i = 0;
   while (Len(Content) > 0)
   {
      SettingsBuffer[i] = Asc(Left(Content, 1));
      Content = Mid(Content, 1);
      i++;
   }

   return SettingsBuffer;
}

Writing and reading is confirmed by delegates. Here i wrapped the definition of it directly into the function. You can actually provide a parameter for the ReadSettingsFromSteamCloud function to be able to handle the settings differently.

/**
 * Triggers the reading of the settings from the steam cloud.
 */
protected function ReadSettingsFromSteamCloud(string Filename)
{
   OnlineSubSteam = GetOnlineSubsytem();
   if ( OnlineSubSteam != none )
   {
      OnlineSubSteam.AddReadUserFileCompleteDelegate(ReadSettingsComplete);
      OnlineSubSteam.ReadUserFile(OnlineSubSteam.UniqueNetIdToString(OnlineSubSteam.LoggedInPlayerId), Filename);
   }
}

/**
 * Reads the settings from steam.
 */
protected function ReadSettingsComplete(bool bWasSuccessful, string UserId, string FileName)
{
   local string User;
    local array<byte> SettingsBuffer;

   OnlineSubSteam = GetOnlineSubsytem();
   if ( OnlineSubSteam != none )
   {
      User=OnlineSubSteam.UniqueNetIdToString(OnlineSubSteam.LoggedInPlayerId);
      if(User == UserId)
      {
         if(bWasSuccessful)
         {
            if(OnlineSubSteam.GetFileContents(UserId, FileName, SettingsBuffer))
               `log("Reading settings from "$FileName$" successful.");
            else
               `log("Warning! Settings did not exist.");            
         }
         else
         {
            `log("Warning! Reading settings file: "$FileName$" failed!");
         }
         SettingsAsJson = ByteArrayToJson(SettingsBuffer);
      }

      OnlineSubSteam.ClearReadUserFileCompleteDelegate(ReadSettingsComplete);
   }
}

And finally the code that write the settings to the steamcloud.

/**
 * Writes the settings to the steam cloud.
 */
protected function WriteSettingsToSteamCloud(string Filename)
{
   local array<byte> SettingsBuffer;

   OnlineSubSteam = GetOnlineSubsytem();
   if ( OnlineSubSteam != none )
   {
      SettingsBuffer = JsonObjectToByteArray(SettingsAsJson);
      OnlineSubSteam.AddWriteUserFileCompleteDelegate(WriteSettingsComplete);
      OnlineSubSteam.WriteUserFile(OnlineSubSteam.UniqueNetIdToString(OnlineSubSteam.LoggedInPlayerId), FileName, SettingsBuffer);
   }
}

/**
 * Tells us if writes the settings to steam was successful.
 */
protected function WriteSettingsComplete(bool bWasSuccessful, string UserId, string FileName)
{
   local string User;

   OnlineSubSteam = GetOnlineSubsytem();
   if ( OnlineSubSteam != none )
   {
      User=OnlineSubSteam.UniqueNetIdToString(OnlineSubSteam.LoggedInPlayerId);
      if(bWasSuccessful && User == UserId)
      {
         `log("Writing settings file: "$FileName$" was successful!");
      }
      else
         `log("Writing settings file: "$FileName$" failed!");

      OnlineSubSteam.ClearWriteUserFileCompleteDelegate(WriteSettingsComplete);
    }
}

At this point we prepared the base class for the configuration. What we want to do now is implement the settings class itself. Make sure the settings in the json are updated whenever something changes in your settings. The JsonObject has multiple function for storing and retrieving different types of data.

local JsonObject SettingsAsJson;

// boolean
SettingsAsJson.SetBoolValue("booleanVar", false);
SettingsAsJson.GetBoolValue("booleanVar");

// float
SettingsAsJson.SetFloatValue("floatVar", 0.1);
SettingsAsJson.GetFloatValue("floatVar");

// integer
SettingsAsJson.SetIntValue("integerVar", 1);
SettingsAsJson.GetIntValue("integerVar");

// string
SettingsAsJson.SetStringValue("stringVar", "Hello World");
SettingsAsJson.GetStringValue("stringVar");