Exemplo n.º 1
0
ModelInstance::ModelInstance(MPQFile& f, string& ModelInstName, uint32 mapID, uint32 tileX, uint32 tileY, FILE* pDirfile, int coreNumber)
{
    float ff[3];
    f.read(&id, 4);
    f.read(ff, 12);
    pos = fixCoords(Vec3D(ff[0], ff[1], ff[2]));
    f.read(ff, 12);
    rot = Vec3D(ff[0], ff[1], ff[2]);
    if (coreNumber == CLIENT_TBC || coreNumber == CLIENT_WOTLK)
    {
        uint16 fFlags;      // dummy var
        f.read(&scaleOthers, 2);
        f.read(&fFlags, 2); // unknown but flag 1 is used for biodome in Outland, currently this value is not used
        sc = scaleOthers / 1024.0f; // scale factor - divide by 1024. why not just use a float?
    }
    if (coreNumber == CLIENT_CLASSIC)
    {
        f.read(&scaleZeroOnly,4);  // The above three lines introduced a regression bug in Mangos Zero, is Fine for other cores.
        sc = scaleZeroOnly / 1024.0f; // scale factor - divide by 1024. why not just use a float?
    }
    
    char tempname[512];
    sprintf(tempname, "%s/%s", szWorkDirWmo, ModelInstName.c_str());
    FILE* input;
    input = fopen(tempname, "r+b");

    if (!input)
    {
        //printf("ModelInstance::ModelInstance couldn't open %s\n", tempname);
        return;
    }

    fseek(input, 8, SEEK_SET); // get the correct no of vertices
    int nVertices;
    size_t file_read = fread(&nVertices, sizeof(int), 1, input);
    fclose(input);

    if (nVertices == 0 || file_read <= 0)
        { return; }

    uint16 adtId = 0;// not used for models
    uint32 flags = MOD_M2;
    if (tileX == 65 && tileY == 65) { flags |= MOD_WORLDSPAWN; }
    //write mapID, tileX, tileY, Flags, ID, Pos, Rot, Scale, name
    fwrite(&mapID, sizeof(uint32), 1, pDirfile);
    fwrite(&tileX, sizeof(uint32), 1, pDirfile);
    fwrite(&tileY, sizeof(uint32), 1, pDirfile);
    fwrite(&flags, sizeof(uint32), 1, pDirfile);
    fwrite(&adtId, sizeof(uint16), 1, pDirfile);
    fwrite(&id, sizeof(uint32), 1, pDirfile);
    fwrite(&pos, sizeof(float), 3, pDirfile);
    fwrite(&rot, sizeof(float), 3, pDirfile);
    fwrite(&sc, sizeof(float), 1, pDirfile);
    uint32 nlen = ModelInstName.length();
    fwrite(&nlen, sizeof(uint32), 1, pDirfile);
    fwrite(ModelInstName.c_str(), sizeof(char), nlen, pDirfile);

}
Exemplo n.º 2
0
ModelInstance::ModelInstance(MPQFile& f, const char* ModelInstName, uint32 mapID, uint32 tileX, uint32 tileY, FILE* pDirfile)
{
    float ff[3];
    f.read(&id, 4);
    f.read(ff, 12);
    pos = fixCoords(Vec3D(ff[0], ff[1], ff[2]));
    f.read(ff, 12);
    rot = Vec3D(ff[0], ff[1], ff[2]);

    uint16 dummyFlags;        // dummy var
    f.read(&scale, 2);
    f.read(&dummyFlags, 2);   // unknown but flag 1 is used for biodome in Outland, currently this value is not used

    // scale factor - divide by 1024. blizzard devs must be on crack, why not just use a float?
    sc = scale / 1024.0f;

    char tempname[512];
    sprintf(tempname, "%s/%s", szWorkDirWmo, ModelInstName);

    FILE* input = fopen(tempname, "r+b");
    if (!input)
    {
        //printf("ModelInstance::ModelInstance couldn't open %s\n", tempname);
        return;
    }

    fseek(input, 8, SEEK_SET); // get the correct no of vertices
    int nVertices;
    int count = fread(&nVertices, sizeof (int), 1, input);
    fclose(input);

    if (count != 1 || nVertices == 0)
        return;

    uint16 adtId = 0; // not used for models
    uint32 flags = MOD_M2;
    if (tileX == 65 && tileY == 65)
        flags |= MOD_WORLDSPAWN;

    // write mapID, tileX, tileY, Flags, ID, Pos, Rot, Scale, name
    fwrite(&mapID, sizeof(uint32), 1, pDirfile);
    fwrite(&tileX, sizeof(uint32), 1, pDirfile);
    fwrite(&tileY, sizeof(uint32), 1, pDirfile);
    fwrite(&flags, sizeof(uint32), 1, pDirfile);
    fwrite(&adtId, sizeof(uint16), 1, pDirfile);
    fwrite(&id, sizeof(uint32), 1, pDirfile);
    fwrite(&pos, sizeof(float), 3, pDirfile);
    fwrite(&rot, sizeof(float), 3, pDirfile);
    fwrite(&sc, sizeof(float), 1, pDirfile);
    uint32 nlen = strlen(ModelInstName);
    fwrite(&nlen, sizeof(uint32), 1, pDirfile);
    fwrite(ModelInstName, sizeof(char), nlen, pDirfile);
}
Exemplo n.º 3
0
ModelInstance::ModelInstance(MPQFile &f, const char* ModelInstName, uint32 mapID, uint32 tileX, uint32 tileY, FILE *pDirfile)
{
    float ff[3];
    f.read(&id, 4);
    f.read(ff, 12);
    pos = fixCoords(Vec3D(ff[0], ff[1], ff[2]));
    f.read(ff, 12);
    rot = Vec3D(ff[0], ff[1], ff[2]);
    f.read(&scale, 4);
    // scale factor - divide by 1024. blizzard devs must be on crack, why not just use a float?
    sc = scale / 1024.0f;

    char tempname[512];
    sprintf(tempname, "%s/%s", szWorkDirWmo, ModelInstName);
    FILE *input;
    input = fopen(tempname, "r+b");

    if (!input)
    {
        //printf("ModelInstance::ModelInstance couldn't open %s\n", tempname);
        return;
    }

    fseek(input, 8, SEEK_SET); // get the correct no of vertices
    int nVertices;
    fread(&nVertices, sizeof (int), 1, input);
    fclose(input);

    if (nVertices == 0)
        return;

    uint16 adtId = 0;// not used for models
    uint32 flags = MOD_M2;
    if (tileX == 65 && tileY == 65) flags |= MOD_WORLDSPAWN;
    //write mapID, tileX, tileY, Flags, ID, Pos, Rot, Scale, name
    fwrite(&mapID, sizeof(uint32), 1, pDirfile);
    fwrite(&tileX, sizeof(uint32), 1, pDirfile);
    fwrite(&tileY, sizeof(uint32), 1, pDirfile);
    fwrite(&flags, sizeof(uint32), 1, pDirfile);
    fwrite(&adtId, sizeof(uint16), 1, pDirfile);
    fwrite(&id, sizeof(uint32), 1, pDirfile);
    fwrite(&pos, sizeof(float), 3, pDirfile);
    fwrite(&rot, sizeof(float), 3, pDirfile);
    fwrite(&sc, sizeof(float), 1, pDirfile);
    uint32 nlen=strlen(ModelInstName);
    fwrite(&nlen, sizeof(uint32), 1, pDirfile);
    fwrite(ModelInstName, sizeof(char), nlen, pDirfile);

    /* int realx1 = (int) ((float) pos.x / 533.333333f);
    int realy1 = (int) ((float) pos.z / 533.333333f);
    int realx2 = (int) ((float) pos.x / 533.333333f);
    int realy2 = (int) ((float) pos.z / 533.333333f);

    fprintf(pDirfile, "%s/%s %f, %f, %f_%f, %f, %f %f %d %d %d, %d %d\n",
        MapName,
        ModelInstName,
        (float) pos.x, (float) pos.y, (float) pos.z,
        (float) rot.x, (float) rot.y, (float) rot.z,
        sc,
        nVertices,
        realx1, realy1,
        realx2, realy2
        ); */
}
Exemplo n.º 4
0
WMOInstance::WMOInstance(MPQFile& f, char const* WmoInstName, uint32 mapID, uint32 tileX, uint32 tileY, FILE* pDirfile)
    : currx(0), curry(0), wmo(NULL), doodadset(0), pos(), indx(0), id(0), d2(0), d3(0)
{
    float ff[3];
    f.read(&id, 4);
    f.read(ff,12);
    pos = Vec3D(ff[0],ff[1],ff[2]);
    f.read(ff,12);
    rot = Vec3D(ff[0],ff[1],ff[2]);
    f.read(ff,12);
    pos2 = Vec3D(ff[0],ff[1],ff[2]);
    f.read(ff,12);
    pos3 = Vec3D(ff[0],ff[1],ff[2]);
    f.read(&d2,4);

    uint16 trash,adtId;
    f.read(&adtId,2);
    f.read(&trash,2);

    //-----------add_in _dir_file----------------

    char tempname[512];
    sprintf(tempname, "%s/%s", szWorkDirWmo, WmoInstName);
    FILE *input;
    input = fopen(tempname, "r+b");

    if(!input)
    {
        printf("WMOInstance::WMOInstance: couldn't open %s\n", tempname);
        return;
    }

    fseek(input, 8, SEEK_SET); // get the correct no of vertices
    int nVertices;
    int count = static_cast<int>(fread(&nVertices, sizeof (int), 1, input));
    fclose(input);

    if (count != 1 || nVertices == 0)
        return;

    float x,z;
    x = pos.x;
    z = pos.z;
    if(x==0 && z == 0)
    {
        pos.x = 533.33333f*32;
        pos.z = 533.33333f*32;
    }
    pos = fixCoords(pos);
    pos2 = fixCoords(pos2);
    pos3 = fixCoords(pos3);

    float scale = 1.0f;
    uint32 flags = MOD_HAS_BOUND;
    if(tileX == 65 && tileY == 65) flags |= MOD_WORLDSPAWN;
    //write mapID, tileX, tileY, Flags, ID, Pos, Rot, Scale, Bound_lo, Bound_hi, name
    fwrite(&mapID, sizeof(uint32), 1, pDirfile);
    fwrite(&tileX, sizeof(uint32), 1, pDirfile);
    fwrite(&tileY, sizeof(uint32), 1, pDirfile);
    fwrite(&flags, sizeof(uint32), 1, pDirfile);
    fwrite(&adtId, sizeof(uint16), 1, pDirfile);
    fwrite(&id, sizeof(uint32), 1, pDirfile);
    fwrite(&pos, sizeof(float), 3, pDirfile);
    fwrite(&rot, sizeof(float), 3, pDirfile);
    fwrite(&scale, sizeof(float), 1, pDirfile);
    fwrite(&pos2, sizeof(float), 3, pDirfile);
    fwrite(&pos3, sizeof(float), 3, pDirfile);
    uint32 nlen=static_cast<uint32_t>(strlen(WmoInstName));
    fwrite(&nlen, sizeof(uint32), 1, pDirfile);
    fwrite(WmoInstName, sizeof(char), nlen, pDirfile);

    /* fprintf(pDirfile,"%s/%s %f,%f,%f_%f,%f,%f 1.0 %d %d %d,%d %d\n",
        MapName,
        WmoInstName,
        (float) x, (float) pos.y, (float) z,
        (float) rot.x, (float) rot.y, (float) rot.z,
        nVertices,
        realx1, realy1,
        realx2, realy2
        ); */

    // fclose(dirfile);
}
Exemplo n.º 5
0
void Doodad::Extract(ADT::MDDF const& doodadDef, char const* ModelInstName, uint32 mapID, uint32 tileX, uint32 tileY, uint32 originalMapId, FILE* pDirfile, std::vector<ADTOutputCache>* dirfileCache)
{
    // scale factor - divide by 1024. blizzard devs must be on crack, why not just use a float?
    float sc = doodadDef.Scale / 1024.0f;

    char tempname[512];
    sprintf(tempname, "%s/%s", szWorkDirWmo, ModelInstName);
    FILE* input = fopen(tempname, "r+b");

    if (!input)
        return;

    fseek(input, 8, SEEK_SET); // get the correct no of vertices
    int nVertices;
    int count = fread(&nVertices, sizeof (int), 1, input);
    fclose(input);

    if (count != 1 || nVertices == 0)
        return;

    Vec3D position = fixCoords(doodadDef.Position);

    uint16 nameSet = 0;// not used for models
    uint32 tcflags = MOD_M2;
    if (tileX == 65 && tileY == 65)
        tcflags |= MOD_WORLDSPAWN;
    if (mapID != originalMapId)
        tcflags |= MOD_PARENT_SPAWN;

    //write mapID, tileX, tileY, Flags, NameSet, UniqueId, Pos, Rot, Scale, name
    fwrite(&mapID, sizeof(uint32), 1, pDirfile);
    fwrite(&tileX, sizeof(uint32), 1, pDirfile);
    fwrite(&tileY, sizeof(uint32), 1, pDirfile);
    fwrite(&tcflags, sizeof(uint32), 1, pDirfile);
    fwrite(&nameSet, sizeof(uint16), 1, pDirfile);
    fwrite(&doodadDef.UniqueId, sizeof(uint32), 1, pDirfile);
    fwrite(&position, sizeof(Vec3D), 1, pDirfile);
    fwrite(&doodadDef.Rotation, sizeof(Vec3D), 1, pDirfile);
    fwrite(&sc, sizeof(float), 1, pDirfile);
    uint32 nlen = strlen(ModelInstName);
    fwrite(&nlen, sizeof(uint32), 1, pDirfile);
    fwrite(ModelInstName, sizeof(char), nlen, pDirfile);

    if (dirfileCache)
    {
        dirfileCache->emplace_back();
        ADTOutputCache& cacheModelData = dirfileCache->back();
        cacheModelData.Flags = tcflags & ~MOD_PARENT_SPAWN;
        cacheModelData.Data.resize(
            sizeof(uint16) +    // nameSet
            sizeof(uint32) +    // doodadDef.UniqueId
            sizeof(Vec3D) +     // position
            sizeof(Vec3D) +     // doodadDef.Rotation
            sizeof(float) +     // sc
            sizeof(uint32) +    // nlen
            nlen);              // ModelInstName

        uint8* cacheData = cacheModelData.Data.data();
#define CACHE_WRITE(value, size, cnt, dest) memcpy(dest, value, size * cnt); dest += size * cnt;

        CACHE_WRITE(&nameSet, sizeof(uint16), 1, cacheData);
        CACHE_WRITE(&doodadDef.UniqueId, sizeof(uint32), 1, cacheData);
        CACHE_WRITE(&position, sizeof(Vec3D), 1, cacheData);
        CACHE_WRITE(&doodadDef.Rotation, sizeof(Vec3D), 1, cacheData);
        CACHE_WRITE(&sc, sizeof(float), 1, cacheData);
        CACHE_WRITE(&nlen, sizeof(uint32), 1, cacheData);
        CACHE_WRITE(ModelInstName, sizeof(char), nlen, cacheData);

#undef CACHE_WRITE
    }
}
Exemplo n.º 6
0
static void* x11connThreadWriteProc(void* dataPtr)
{
	X11ConnData* data = (X11ConnData*)dataPtr;

	unsigned char *buf = NULL;
	size_t bufLen = 0;

	{
		xConnSetupPrefix header;
		if (!recvAll(data->server, &header, sz_xConnSetupPrefix)) goto done;
		if (!sendAll(data->client, &header, sz_xConnSetupPrefix)) goto done;

		log_debug("Server connection setup reply: %d\n", header.success);

		size_t dataLength = header.length * 4;
		bufSize(&buf, &bufLen, dataLength);
		if (!recvAll(data->server, buf, dataLength)) goto done;
		if (!sendAll(data->client, buf, dataLength)) goto done;
	}

	bufSize(&buf, &bufLen, sz_xReply);
	while (!data->exiting)
	{
		if (!recvAll(data->server, buf, sz_xReply)) goto done;
		size_t ofs = sz_xReply;
		const xReply* reply = (xReply*)buf;

		if (reply->generic.type == X_Reply || reply->generic.type == GenericEvent)
		{
			size_t dataLength = reply->generic.length * 4;
			bufSize(&buf, &bufLen, ofs + dataLength);
			reply = (xReply*)buf; // in case bufSize moved buf
			if (!recvAll(data->server, buf+ofs, dataLength)) goto done;
			ofs += dataLength;
		}
		log_debug2(" [%d]Response: %d sequenceNumber=%d length=%d\n", data->index, reply->generic.type, reply->generic.sequenceNumber, ofs);

		if (reply->generic.type == X_Reply)
		{
			switch (data->notes[reply->generic.sequenceNumber])
			{
				case Note_X_GetGeometry:
				{
					xGetGeometryReply* reply = (xGetGeometryReply*)buf;
					log_debug2("  XGetGeometry(%d,%d,%d,%d)\n", reply->x, reply->y, reply->width, reply->height);
					fixCoords(&reply->x, &reply->y, &reply->width, &reply->height);
					log_debug2("  ->          (%d,%d,%d,%d)\n", reply->x, reply->y, reply->width, reply->height);
					break;
				}

				case Note_X_InternAtom_Other:
				{
					xInternAtomReply* reply = (xInternAtomReply*)buf;
					log_debug2("  X_InternAtom: atom=%d\n", reply->atom);
					break;
				}

				case Note_X_QueryExtension_XFree86_VidModeExtension:
				{
					xQueryExtensionReply* reply = (xQueryExtensionReply*)buf;
					log_debug2("  X_QueryExtension (XFree86-VidModeExtension): present=%d major_opcode=%d first_event=%d first_error=%d\n",
						reply->present, reply->major_opcode, reply->first_event, reply->first_error);
					if (reply->present)
						data->opcode_XFree86_VidModeExtension = reply->major_opcode;
					break;
				}

				case Note_X_QueryExtension_RANDR:
				{
					xQueryExtensionReply* reply = (xQueryExtensionReply*)buf;
					log_debug2("  X_QueryExtension (RANDR): present=%d major_opcode=%d first_event=%d first_error=%d\n",
						reply->present, reply->major_opcode, reply->first_event, reply->first_error);
					if (reply->present)
						data->opcode_RANDR = reply->major_opcode;
					break;
				}

				case Note_X_QueryExtension_Xinerama:
				{
					xQueryExtensionReply* reply = (xQueryExtensionReply*)buf;
					log_debug2("  X_QueryExtension (XINERAMA): present=%d major_opcode=%d first_event=%d first_error=%d\n",
						reply->present, reply->major_opcode, reply->first_event, reply->first_error);
					if (reply->present)
						data->opcode_Xinerama = reply->major_opcode;
					break;
				}

				case Note_X_QueryExtension_NV_GLX:
				{
					xQueryExtensionReply* reply = (xQueryExtensionReply*)buf;
					log_debug2("  X_QueryExtension (NV-GLX): present=%d major_opcode=%d first_event=%d first_error=%d\n",
						reply->present, reply->major_opcode, reply->first_event, reply->first_error);
					if (reply->present)
						data->opcode_NV_GLX = reply->major_opcode;
					break;
				}

				case Note_X_QueryExtension_Other:
				{
					xQueryExtensionReply* reply = (xQueryExtensionReply*)buf;
					log_debug2("  X_QueryExtension: present=%d major_opcode=%d first_event=%d first_error=%d\n",
						reply->present, reply->major_opcode, reply->first_event, reply->first_error);
					break;
				}

				case Note_X_XF86VidModeGetModeLine:
				{
					xXF86VidModeGetModeLineReply* reply = (xXF86VidModeGetModeLineReply*)buf;
					log_debug2("  X_XF86VidModeGetModeLine(%d x %d)\n", reply->hdisplay, reply->vdisplay);
					fixSize(&reply->hdisplay, &reply->vdisplay);
					log_debug2("  ->                      (%d x %d)\n", reply->hdisplay, reply->vdisplay);
					break;
				}

				case Note_X_XF86VidModeGetAllModeLines:
				{
					xXF86VidModeGetAllModeLinesReply* reply = (xXF86VidModeGetAllModeLinesReply*)buf;
					xXF86VidModeModeInfo* modeInfos = (xXF86VidModeModeInfo*)(buf + sz_xXF86VidModeGetAllModeLinesReply);
					for (size_t i=0; i<reply->modecount; i++)
					{
						xXF86VidModeModeInfo* modeInfo = modeInfos + i;
						log_debug2("  X_XF86VidModeGetAllModeLines[%d] = %d x %d\n", i, modeInfo->hdisplay, modeInfo->vdisplay);
						fixSize(&modeInfo->hdisplay, &modeInfo->vdisplay);
						log_debug2("  ->                                %d x %d\n",    modeInfo->hdisplay, modeInfo->vdisplay);
					}
					break;
				}

				case Note_X_RRGetScreenInfo:
				{
					xRRGetScreenInfoReply* reply = (xRRGetScreenInfoReply*)buf;
					xScreenSizes* sizes = (xScreenSizes*)(buf+sz_xRRGetScreenInfoReply);
					for (size_t i=0; i<reply->nSizes; i++)
					{
						xScreenSizes* size = sizes+i;
						log_debug2("  X_RRGetScreenInfo[%d] = %d x %d\n", i, size->widthInPixels, size->heightInPixels);
						fixSize(&size->widthInPixels, &size->heightInPixels);
						log_debug2("  ->                      %d x %d\n",    size->widthInPixels, size->heightInPixels);
					}
					break;
				}

				case Note_X_RRGetScreenResources:
				{
					xRRGetScreenResourcesReply* reply = (xRRGetScreenResourcesReply*)buf;
					void* ptr = buf+sz_xRRGetScreenResourcesReply;
					ptr += reply->nCrtcs * sizeof(CARD32);
					ptr += reply->nOutputs * sizeof(CARD32);
					for (size_t i=0; i<reply->nModes; i++)
					{
						xRRModeInfo* modeInfo = (xRRModeInfo*)ptr;
						log_debug2("  X_RRGetScreenResources[%d] = %d x %d\n", i, modeInfo->width, modeInfo->height);
						fixSize(&modeInfo->width, &modeInfo->height);
						log_debug2("  ->                           %d x %d\n",    modeInfo->width, modeInfo->height);
						ptr += sz_xRRModeInfo;
					}
					break;
				}

				case Note_X_RRGetCrtcInfo:
				{
					xRRGetCrtcInfoReply* reply = (xRRGetCrtcInfoReply*)buf;
					log_debug2("  X_RRGetCrtcInfo = %dx%d @ %dx%d\n", reply->width, reply->height, reply->x, reply->y);
					if (reply->mode != None)
					{
						fixMonitor(&reply->x, &reply->y, &reply->width, &reply->height);
						if (!reply->width || !reply->height)
						{
							reply->x = reply->y = reply->width = reply->height = 0;
							reply->mode = None;
							reply->rotation = reply->rotations = RR_Rotate_0;
							reply->nOutput = reply->nPossibleOutput = 0;
						}
					}
					log_debug2("  ->                %dx%d @ %dx%d\n", reply->width, reply->height, reply->x, reply->y);
					break;
				}

				case Note_X_XineramaQueryScreens:
				{
					xXineramaQueryScreensReply* reply = (xXineramaQueryScreensReply*)buf;
					xXineramaScreenInfo* screens = (xXineramaScreenInfo*)(buf+sz_XineramaQueryScreensReply);
					for (size_t i=0; i<reply->number; i++)
					{
						xXineramaScreenInfo* screen = screens+i;
						log_debug2("  X_XineramaQueryScreens[%d] = %dx%d @ %dx%d\n", i, screen->width, screen->height, screen->x_org, screen->y_org);
						fixCoords(&screen->x_org, &screen->y_org, &screen->width, &screen->height);
						log_debug2("  ->                           %dx%d @ %dx%d\n",    screen->width, screen->height, screen->x_org, screen->y_org);
					}
					break;
				}

				case Note_NV_GLX:
				{
#if 0
					char fn[256];
					static int counter = 0;
					sprintf(fn, "/tmp/hax11-NV-%d-rsp-%d", reply->generic.sequenceNumber, counter++);
					FILE* f = fopen(fn, "wb");
					fwrite(buf, 1, ofs, f);
					fclose(f);
#endif
					break;
				}
			}
		}

		if (config.debug >= 2 && config.actualX && config.actualY && memmem(buf, ofs, &config.actualX, 2) && memmem(buf, ofs, &config.actualY, 2))
			log_debug2("   Found actualW/H in output! ----------------------------------------------------------------------------------------------\n");

		if (!sendAll(data->client, buf, ofs)) goto done;
	}
done:
	log_debug("Exiting write thread.\n");
	data->exiting = 1;
	close(data->client);
	close(data->server);
	return NULL;
}
Exemplo n.º 7
0
static void* x11connThreadReadProc(void* dataPtr)
{
	X11ConnData* data = (X11ConnData*)dataPtr;
	unsigned char *buf = NULL;
	size_t bufLen = 0;
	bufSize(&buf, &bufLen, 1<<16);

	xConnClientPrefix header;
	if (!recvAll(data->client, &header, sizeof(header))) goto done;
	if (header.byteOrder != 'l')
	{
		log_debug("Unsupported byte order %c!\n", header.byteOrder);
		goto done;
	}
	if (!sendAll(data->server, &header, sz_xConnClientPrefix)) goto done;

	if (!recvAll(data->client, buf, pad(header.nbytesAuthProto))) goto done;
	if (!sendAll(data->server, buf, pad(header.nbytesAuthProto))) goto done;
	if (!recvAll(data->client, buf, pad(header.nbytesAuthString))) goto done;
	if (!sendAll(data->server, buf, pad(header.nbytesAuthString))) goto done;

	unsigned short sequenceNumber = 0;

	while (!data->exiting)
	{
		sequenceNumber++;

		size_t ofs = 0;
		if (!recvAll(data->client, buf+ofs, sz_xReq)) goto done;
		ofs += sz_xReq;

		const xReq* req = (xReq*)buf;
		uint requestLength = req->length * 4;
		if (requestLength == 0) // Big Requests Extension
		{
			recvAll(data->client, buf+ofs, 4);
			requestLength = *(uint*)(buf+ofs) * 4;
			ofs += 4;
		}
		log_debug2("[%d][%d] Request %d (%s) with data %d, length %d\n", data->index, sequenceNumber, req->reqType, requestNames[req->reqType], req->data, requestLength);
		bufSize(&buf, &bufLen, requestLength);
		req = (xReq*)buf; // in case bufSize moved buf

		if (!recvAll(data->client, buf+ofs, requestLength - ofs)) goto done;

		data->notes[sequenceNumber] = Note_None;
		switch (req->reqType)
		{
			// Fix for games that create the window of the wrong size or on the wrong monitor.
			case X_CreateWindow:
			{
				xCreateWindowReq* req = (xCreateWindowReq*)buf;
				log_debug2(" XCreateWindow(%dx%d @ %dx%d)\n", req->width, req->height, req->x, req->y);
				fixCoords(&req->x, &req->y, &req->width, &req->height);
				log_debug2(" ->           (%dx%d @ %dx%d)\n", req->width, req->height, req->x, req->y);
				break;
			}

			case X_ConfigureWindow:
			{
				xConfigureWindowReq* req = (xConfigureWindowReq*)buf;

				INT16 dummyXY = 0;
				CARD16 dummyW = config.mainW;
				CARD16 dummyH = config.mainH;
				INT16 *x = &dummyXY, *y = &dummyXY;
				CARD16 *w = &dummyW, *h = &dummyH;

				int* ptr = (int*)(buf + sz_xConfigureWindowReq);
				if (req->mask & 0x0001) // x
				{
					x = (INT16*)ptr;
					ptr++;
				}
				if (req->mask & 0x0002) // y
				{
					y = (INT16*)ptr;
					ptr++;
				}
				if (req->mask & 0x0004) // width
				{
					w = (CARD16*)ptr;
					ptr++;
				}
				if (req->mask & 0x0008) // height
				{
					h = (CARD16*)ptr;
					ptr++;
				}

				log_debug2(" XConfigureWindow(%dx%d @ %dx%d)\n", *w, *h, *x, *y);
				fixCoords(x, y, w, h);
				log_debug2(" ->              (%dx%d @ %dx%d)\n", *w, *h, *x, *y);
				break;
			}

			// Fix for games setting their window size based on the X root window size
			// (which can encompass multiple physical monitors).
			case X_GetGeometry:
			{
				data->notes[sequenceNumber] = Note_X_GetGeometry;
				break;
			}

			case X_InternAtom:
			{
				xInternAtomReq* req = (xInternAtomReq*)buf;
				const char* name = (const char*)(buf + sz_xInternAtomReq);
				log_debug2(" XInternAtom: %.*s\n", req->nbytes, name);
				data->notes[sequenceNumber] = Note_X_InternAtom_Other;
				break;
			}

			case X_ChangeProperty:
			{
				xChangePropertyReq* req = (xChangePropertyReq*)buf;
				log_debug2(" XChangeProperty: property=%d type=%d format=%d)\n", req->property, req->type, req->format);
				if (req->type == XA_WM_SIZE_HINTS)
				{
					XSizeHints* data = (XSizeHints*)(buf + sz_xChangePropertyReq);
					fixCoords((INT16*)&data->x, (INT16*)&data->y, (CARD16*)&data->width, (CARD16*)&data->height);
					fixSize((CARD16*)&data->max_width, (CARD16*)&data->max_height);
					fixSize((CARD16*)&data->base_width, (CARD16*)&data->base_height);
				}
				break;
			}

			case X_QueryExtension:
			{
				xQueryExtensionReq* req = (xQueryExtensionReq*)buf;
				const char* name = (const char*)(buf + sz_xQueryExtensionReq);
				log_debug2(" XQueryExtension(%.*s)\n", req->nbytes, name);

				if (!strmemcmp("XFree86-VidModeExtension", name, req->nbytes))
					data->notes[sequenceNumber] = Note_X_QueryExtension_XFree86_VidModeExtension;
				else
				if (!strmemcmp("RANDR", name, req->nbytes))
					data->notes[sequenceNumber] = Note_X_QueryExtension_RANDR;
				else
				if (!strmemcmp("XINERAMA", name, req->nbytes))
					data->notes[sequenceNumber] = Note_X_QueryExtension_Xinerama;
				else
				if (!strmemcmp("NV-GLX", name, req->nbytes))
					data->notes[sequenceNumber] = Note_X_QueryExtension_NV_GLX;
				else
					data->notes[sequenceNumber] = Note_X_QueryExtension_Other;
			}

			case 0:
				break;

			default:
			{
				if (req->reqType == data->opcode_XFree86_VidModeExtension)
				{
					xXF86VidModeGetModeLineReq* req = (xXF86VidModeGetModeLineReq*)buf;
					log_debug2(" XFree86_VidModeExtension - %d\n", req->xf86vidmodeReqType);
					switch (req->xf86vidmodeReqType)
					{
						case X_XF86VidModeGetModeLine:
							data->notes[sequenceNumber] = Note_X_XF86VidModeGetModeLine;
							break;
						case X_XF86VidModeGetAllModeLines:
							data->notes[sequenceNumber] = Note_X_XF86VidModeGetAllModeLines;
							break;
					}
				}
				else
				if (req->reqType == data->opcode_RANDR)
				{
					log_debug2(" RANDR - %d\n", req->data);
					switch (req->data)
					{
						case X_RRGetScreenInfo:
							data->notes[sequenceNumber] = Note_X_RRGetScreenInfo;
							break;
						case X_RRGetScreenResources:
							data->notes[sequenceNumber] = Note_X_RRGetScreenResources;
							break;
						case X_RRGetCrtcInfo:
							data->notes[sequenceNumber] = Note_X_RRGetCrtcInfo;
							break;
					}
				}
				else
				if (req->reqType == data->opcode_Xinerama)
				{
					log_debug2(" Xinerama - %d\n", req->data);
					switch (req->data)
					{
						case X_XineramaQueryScreens:
							data->notes[sequenceNumber] = Note_X_XineramaQueryScreens;
							break;
					}
				}
				else
				if (req->reqType == data->opcode_NV_GLX)
				{
#if 0
					char fn[256];
					sprintf(fn, "/tmp/hax11-NV-%d-req", sequenceNumber);
					FILE* f = fopen(fn, "wb");
					fwrite(buf, 1, requestLength, f);
					fclose(f);
#endif
					data->notes[sequenceNumber] = Note_NV_GLX;
				}
				break;
			}
		}

		if (config.debug >= 2 && config.actualX && config.actualY && memmem(buf, requestLength, &config.actualX, 2) && memmem(buf, requestLength, &config.actualY, 2))
			log_debug2("   Found actualW/H in input! ----------------------------------------------------------------------------------------------\n");

		if (!sendAll(data->server, buf, requestLength)) goto done;
	}
done:
	log_debug("Exiting read thread.\n");
	data->exiting = 1;
	close(data->client);
	close(data->server);
	return NULL;
}