Monthly Archives: November 2011

Get the real type in javascript

In javascript, we can use “type” function to get the type of an element (e.g “aa”, [], {}, 1, true, null, undefined, function, global), but get an array’s type. it returns a “object”. So, how to get the real type of the element?

USE “Object.prototype.toString.apply” function.

WHY?

Because any elements inherit it. Now, let’s see the results

Object.prototype.toString.apply("aa") //return [object String]
Object.prototype.toString.apply(1) //return [object Number]
Object.prototype.toString.apply({}) //return [object Object]
Object.prototype.toString.apply([]) //return [object Array]
Object.prototype.toString.apply(true) //return [object Boolean]
Object.prototype.toString.apply(null) //return [object Null]
Object.prototype.toString.apply(undefined) //return [object Undefined]
Object.prototype.toString.apply(window) //return [object global]
Object.prototype.toString.apply(Math.abs)//return [object Function]

//... and all

[php]unpack “N” bug on 64 bit system

这个问题只有在64系统下有问题. 当一个数值为负数时候, unpack后会变成一个超大整数.这是由于PHP_INT_MAX导致的.
32为下的PHP_INT_MAX为 2147483647; 而64位下为9223372036854775807;
如何判断php是运行在64位下?

php -r "echo PHP_INT_SIZE;"

如何返回4为32bit, 8为64bit.

我们看下例子

<?php
$s = -379;
$a = pack("N", $s);//转化后还是正常的.得到 ff ff fe 85

print_r(unpack("N", $a));//在32为解出来的结果正常为-379. 而64bit下则为4294966917
?>

如何解决?
网上找到了这么一个处理办法

/// portably build 64bit id from 32bit hi and lo parts
function _Make64 ( $hi, $lo )
{
// on x64, we can just use int
if ( ((int)4294967296)!=0 )
return (((int)$hi)<<32) + ((int)$lo);// workaround signed/unsigned braindamage on x32 $hi = sprintf ( "%u", $hi ); $lo = sprintf ( "%u", $lo );// use GMP or bcmath if possible if ( function_exists("gmp_mul") ) return gmp_strval ( gmp_add ( gmp_mul ( $hi, "4294967296" ), $lo ) );if ( function_exists("bcmul") ) return bcadd ( bcmul ( $hi, "4294967296" ), $lo );// compute everything manually $a = substr ( $hi, 0, -5 ); $b = substr ( $hi, -5 ); $ac = $a*42949; // hope that float precision is enough $bd = $b*67296; $adbc = $a*67296+$b*42949; $r4 = substr ( $bd, -5 ) + + substr ( $lo, -5 ); $r3 = substr ( $bd, 0, -5 ) + substr ( $adbc, -5 ) + substr ( $lo, 0, -5 ); $r2 = substr ( $adbc, 0, -5 ) + substr ( $ac, -5 ); $r1 = substr ( $ac, 0, -5 ); while ( $r4>100000 ) { $r4-=100000; $r3++; }
while ( $r3>100000 ) { $r3-=100000; $r2++; }
while ( $r2>100000 ) { $r2-=100000; $r1++; }

$r = sprintf ( “%d%05d%05d%05d”, $r1, $r2, $r3, $r4 );
$l = strlen($r);
$i = 0;
while ( $r[$i]==”0″ && $i<$l-1 ) $i++; return substr ( $r, $i ); }list(,$a) = unpack ( "N", "\xff\xff\xff\xff" ); list(,$b) = unpack ( "N", "\xff\xff\xff\xff" ); $q = _Make64($a,$b); var_dump($q); [/php]

[PHP]如何判断array真正的类型

习惯了javascript中的array和object.在php中array又可以是Array也可以是Object(这里的Object 与js的object相同. 并非stdClass的Object). 但是问题来了如何判断他真正的类型.在有些时候, 我们需要它真实的类型.才能做一点事情.
目前我找到一个非常挫的方法.通过判断array头部的key是否为0, array最后一个元素的key是否为count – 1值. 并且同时判断, 他的所有key是否为数字. 缺陷在于如果加入一个数组为array(1, 2 => “c”, 10 => 6, 4=>”1″, 3). 这个时候仍然能通过.
刚刚测试了一下, 如何改动了key值. 后面会根据上面一个key值变化.测试如下:

Array ( [0] => 1 [2] => c [10] => 6 [4] => 5 [11] => 3 )

判断方法: 如果有更好的, 请留贴告诉我.

function getRealArrayType($d){
		if (gettype($d) != "array"){return;}	
		//get realtype
		$realType = "array";
		//array / object
		$count = count($d);
		reset($d);
		//first element key is 0?
		if (key($d) != 0){
			$realType = "object";
		}
		end($d);
                //the last element key is (count - 1)
		if (key($d) != ($count - 1)){
			$realType = "object";
		}

		reset($d);
		while (next($d)){
			$key = key($d);
			if (is_string($key)){
				$realType = "object";
				break;
			}
		}
		reset($d);//reset position
		return $realType;
	}

[RT] Defining Getters and Setters in NodeJS

Recently I discovered something interesting while messing around with NodeJS… you can define getters and setters using the ECMAScript5 syntax. For a useless example I could do something like this:

var sys = require('sys')

function Person(age){
this.__defineGetter__('age', function(){
return age
})

this.__defineSetter__('age', function(arg){
age = arg
})
}

var dude = new Person(18)

sys.puts(dude.age)
dude.age = 32

sys.puts(dude.age)

This is kind of boring though because it’s just a more complicated way of doing

function Person(age){
this.age = age
}

however you can notice in the first example you can add any kind of custom behavior to the getter and setter and access it via person.age. Where this does become useful however is if you want to create a read only property, which you can do by just defining the getter alone:

var sys = require('sys')

function Person(age){
this.__defineGetter__('age', function(){
return age
})
}

var dude = new Person(18)

sys.puts(dude.age)
dude.age = 32

This will print the initial age as expected, however the last line where the attempt is made to set the property will throw the exception “TypeError: Cannot set property age of # which has only a getter.”

A small discovery, yet very useful.

This origin post url: http://blog.james-carr.org/2010/07/19/defining-getters-and-setters-in-nodejs/

Create a warcraft world map by PIL

通过使用Python Image Library创建魔兽世界地图
代码如下

#coding: utf-8
import _mysql as mysql
import MySQLdb
import os, io, re, math;
import Image

class WorldMaps(object):
def __init__(self, base, output):
self._basedir = base
self._output = output

self.connectMysql()
self.cacheMaps()

def connectMysql(self):
self.db = mysql.connect(host=”127.0.0.1″, user=”root”, passwd=””, db=”wowdb_ctm”)
self.db.query(“SET NAMES UTF8”)

#cache maps metadata from WorldMapArea.dbc
def cacheMaps(self):
self.MAPS_INFO = {}
sql = “SELECT ID, Map, AreaTable, Icon FROM worldmapareadbc”
self.db.query(sql)
results = self.db.store_result()
data = results.fetch_row()

while (data):
data, = data;
self.MAPS_INFO[int(data[0])] = {
“mapid” : data[1],
“areaid” : data[2],
“mapfilename” : data[3]
}
#fetch now
data = results.fetch_row()

def GetNumberOfDetailTiles(self, dirname, mapfilename):
numOnDetailTiles = 0;
for filename in os.listdir(dirname):
if (re.match(mapfilename+”(\d+)”, filename)):
numOnDetailTiles = numOnDetailTiles + 1;
return numOnDetailTiles;

def GetMapInfo(self, mapid):
mapid = int(mapid)
mapinfo = self.MAPS_INFO[mapid]
mapfilename = mapinfo[“mapfilename”]
return mapfilename, self._basedir + “/” + mapfilename + “/”

def GetMapOverlays(self, mapid):
overlays = []
sql = “SELECT Path, Width, Height, `Left`, `Top` FROM worldmapoverlaydbc WHERE ZoneId = ” + str(mapid);
self.db.query(sql);
results = self.db.store_result();
data = results.fetch_row();
while data:
data, = data
overlays.append({
“path” : data[0],
“width” : int(data[1]),
“height”: int(data[2]),
“left” : int(data[3]),
“top” : int(data[4])
});

data = results.fetch_row();

return overlays

def createWorldMap(self, mapid):
mapfilename, dirname = self.GetMapInfo(mapid)

numOnDetailTiles = self.GetNumberOfDetailTiles(dirname, mapfilename);
texs = {};

#map standard size: 1002 * 668
new_image = Image.new(“RGB”, (1002, 668));
x = 0;
y = 1;
for i in range (1, numOnDetailTiles+1):
texName = dirname + “/” + mapfilename + str(i) + “.png”
# x x x x
# x x x x
# x x x x
texs[i] = Image.open(texName);
x = x + 1;
#print x, y
new_image.paste(texs[i], (x * 256 – 256, y * 256 – 256));
if x == 4:
y = y + 1
x = 0;

#sec, get overlays, and paste
overlays = self.GetMapOverlays(mapid)
textureCount = 0
for overlayinfo in overlays:
textureName = overlayinfo[“path”];
textureWidth = overlayinfo[“width”];
textureHeight = overlayinfo[“height”];
offsetX = overlayinfo[“left”];
offsetY = overlayinfo[“top”];
#print textureWidth, textureHeight, textureName

if (textureName and textureName != “”):
numTexturesWide = math.ceil(float(textureWidth) / float(256))
numTexturesTall = math.ceil(float(textureHeight) / float(256))
#print textureWidth, textureHeight, textureName, numTexturesWide, numTexturesTall
neededTextures = int(textureCount + (numTexturesWide * numTexturesTall))

texturePixelWidth = 0
texturePixelHeight = 0
textureFileWidth = 0
textureFileHeight = 0
for j in range(1, int(numTexturesTall) + 1):
if (j < numTexturesTall): texturePixelHeight = 256 textureFileHeight = 256 else: texturePixelHeight = textureHeight % 256; if (texturePixelHeight == 0): texturePixelHeight = 256 textureFileHeight = 16 while textureFileHeight < texturePixelHeight: textureFileHeight = textureFileHeight * 2for k in range(1, int(numTexturesWide) + 1): textureCount = textureCount + 1 if (k < numTexturesWide): texturePixelWidth = 256 textureFileWidth = 256 else: texturePixelWidth = textureWidth % 256 if (texturePixelWidth == 0): texturePixelWidth = 256 textureFileWidth = 256 while textureFileWidth < texturePixelWidth: textureFileWidth = textureFileWidth * 2_textureName = textureName + str(int((( j - 1) * numTexturesWide) + k)) + ".png"; texture = Image.open(dirname + "/" + _textureName); new_image.paste(texture, ( (offsetX + (256 * (k - 1))) , ((offsetY + (256 * (j - 1)))) ), texture ); new_image.save( self._output + "/" + str(mapid) + ".png"); [/python]生成的效果图:

世界地图外部生成机制

根据上一篇所讲. 现在我们如何在外部生成一张地图.
一.
首先GetMapInfo.
从worldmapareadbc 获得
ID 以及mapName
GetNumberOfDetailTiles() 获取大地图的tile数量? 游戏内能直接获取, 游戏外部如何获取?
二.
从worldmapoverlay.dbc
同上面的ID, 获得当前地图overlays数量
以及他的材质名称, 高度 宽度 坐标位置.

地图 1002 * 668 ?
布局
256 256 256 256
256 256 256 256
256 256 256 256
特殊变量

WORLDMAP_POI_TEXTURE_WIDTH = 256;
WORLDMAP_COSMIC_ID = -1;
WORLDMAP_WORLD_ID = 0;
WORLDMAP_OUTLAND_ID = 3;
WORLDMAP_MAELSTROM_ID = 5;
MAELSTROM_ZONES_ID = { TheMaelstrom = 737, Deepholm = 640, Kezan = 605, TheLostIsles = 544 };

https://github.com/tekkub/wow-ui-source/blob/4.2.2/FrameXML/WorldMapFrame.lua

— Setup the overlays
local textureCount = 0;
for i=1, GetNumMapOverlays() do
local textureName, textureWidth, textureHeight, offsetX, offsetY = GetMapOverlayInfo(i);
if ( textureName and textureName ~= “” ) then
local numTexturesWide = ceil(textureWidth/256);
local numTexturesTall = ceil(textureHeight/256);
local neededTextures = textureCount + (numTexturesWide * numTexturesTall);
if ( neededTextures > NUM_WORLDMAP_OVERLAYS ) then
for j=NUM_WORLDMAP_OVERLAYS+1, neededTextures do
WorldMapDetailFrame:CreateTexture(“WorldMapOverlay”..j, “ARTWORK”);
end
NUM_WORLDMAP_OVERLAYS = neededTextures;
end
local texturePixelWidth, textureFileWidth, texturePixelHeight, textureFileHeight;
for j=1, numTexturesTall do
if ( j < numTexturesTall ) then texturePixelHeight = 256; textureFileHeight = 256; else texturePixelHeight = mod(textureHeight, 256); if ( texturePixelHeight == 0 ) then texturePixelHeight = 256; end textureFileHeight = 16; while(textureFileHeight < texturePixelHeight) do textureFileHeight = textureFileHeight * 2; end end for k=1, numTexturesWide do textureCount = textureCount + 1; local texture = _G["WorldMapOverlay"..textureCount]; if ( k < numTexturesWide ) then texturePixelWidth = 256; textureFileWidth = 256; else texturePixelWidth = mod(textureWidth, 256); if ( texturePixelWidth == 0 ) then texturePixelWidth = 256; end textureFileWidth = 16; while(textureFileWidth < texturePixelWidth) do textureFileWidth = textureFileWidth * 2; end end texture:SetWidth(texturePixelWidth); texture:SetHeight(texturePixelHeight); texture:SetTexCoord(0, texturePixelWidth/textureFileWidth, 0, texturePixelHeight/textureFileHeight); texture:SetPoint("TOPLEFT", offsetX + (256 * (k-1)), -(offsetY + (256 * (j - 1)))); texture:SetTexture(textureName..(((j - 1) * numTexturesWide) + k)); texture:Show(); end end end end for i=textureCount+1, NUM_WORLDMAP_OVERLAYS do _G["WorldMapOverlay"..i]:Hide(); end [/lua]

WoW世界地图分析

一.
在游戏中
mapFileName, textureHeight, textureWidth = GetMapInfo() 获取地图信息
然后获取到地图所在的图片路径
pathPrefix = “Interface\\WorldMap\\”..mapFileName..”\\”

例如荒芜之地
Badlands, 667, 768
二.
获取覆盖层数量
numOverlays = GetNumMapOverlays()


获取覆盖层信息
local texName, texWidth, texHeight, offsetX, offsetY = GetMapOverlayInfo(1-numOverlays)


拼接算法:

for texName, texID in pairs(overlayMap) do
local textureName = pathPrefix .. texName
local textureWidth, textureHeight, offsetX, offsetY = mod(texID, 2^10), mod(floor(texID / 2^10), 2^10), mod(floor(texID / 2^20), 2^10), floor(texID / 2^30)

local numTexturesWide = ceil(textureWidth / 256)
local numTexturesTall = ceil(textureHeight / 256)
local neededTextures = textureCount + (numTexturesWide * numTexturesTall)
if neededTextures > numOv then
for j = numOv + 1, neededTextures do
local texture = frame:CreateTexture(format(frameName, j), “ARTWORK”)
tinsert(textureCache, texture)
end
numOv = neededTextures
end
local texturePixelWidth, textureFileWidth, texturePixelHeight, textureFileHeight
for j = 1, numTexturesTall do
if j < numTexturesTall then texturePixelHeight = 256 textureFileHeight = 256 else texturePixelHeight = mod(textureHeight, 256) if texturePixelHeight == 0 then texturePixelHeight = 256 end textureFileHeight = 16 while textureFileHeight < texturePixelHeight do textureFileHeight = textureFileHeight * 2 end end for k = 1, numTexturesWide do textureCount = textureCount + 1 local texture = textureCache[textureCount] if k < numTexturesWide then texturePixelWidth = 256 textureFileWidth = 256 else texturePixelWidth = mod(textureWidth, 256) if texturePixelWidth == 0 then texturePixelWidth = 256 end textureFileWidth = 16 while textureFileWidth < texturePixelWidth do textureFileWidth = textureFileWidth * 2 end end texture:SetWidth(texturePixelWidth*scale) texture:SetHeight(texturePixelHeight*scale) texture:SetTexCoord(0, texturePixelWidth / textureFileWidth, 0, texturePixelHeight / textureFileHeight) texture:ClearAllPoints() texture:SetPoint("TOPLEFT", (offsetX + (256 * (k-1))) * scale, -(offsetY + (256 * (j - 1))) * scale) texture:SetTexture(format(textureName.."%d", ((j - 1) * numTexturesWide) + k))if discoveredOverlays[texName] then texture:SetVertexColor(1, 1, 1) texture:SetAlpha(1 - (alphaMod or 0)) texture:SetDrawLayer("ARTWORK") else texture:SetVertexColor(r, g, b) texture:SetAlpha(a * ( 1 - (alphaMod or 0))) texture:SetDrawLayer("BORDER") if db.debug then DEFAULT_CHAT_FRAME:AddMessage(format("|cff33ff99Mapster|r: Subzone: %s in zone: %s", texName, mapFileName)) end endtexture:Show() end end end [/lua]