Moved some around, more renames

This commit is contained in:
KimLS
2014-08-21 22:43:33 -07:00
parent 504a8b19ce
commit cd0824ee71
63 changed files with 8 additions and 10 deletions
+101
View File
@@ -0,0 +1,101 @@
#ifndef __OPENEQ_THREED__
#define __OPENEQ_THREED__
#include "3d_base.hpp"
#include <list>
#include <vector>
#include <string>
using namespace std;
struct ObjectGroupEntry
{
ObjectGroupEntry()
{
IncludeInMap = true;
}
bool FromTOG;
bool IncludeInMap;
float TileX, TileY, TileZ;
float x, y, z;
float RotX, RotY, RotZ;
float ScaleX, ScaleY, ScaleZ;
list<int> SubObjects;
};
class Octree_Node;
class Bone {
public:
char *name;
int bone1, bone2;
float x, y, z;
float e[4];
float scale[3];
int vert_count;
int *verts;
};
class Zone_Model {
public:
Zone_Model() {}
~Zone_Model() {}
Vertex **verts;
Polygon **polys;
Octree_Node *octree;
Texture **tex;
int vert_count, poly_count, tex_count;
};
class MobModel {
public:
MobModel() {}
~MobModel() {}
Vertex **verts;
Polygon **polys;
Texture **tex;
int vert_count, poly_count, tex_count;
Bone *bones;
int bone_count;
};
class Content_3D {
public:
Content_3D() { this->mob_model_count = 0; this->mob_count = 0; }
~Content_3D() {}
Model *GetModel(char *model_name);
void GenerateOctree();
void MergeTextures();
void MergeTexturesLazy();
Zone_Model *zone_model;
Model **models;
Placeable **placeable;
int model_count, plac_count; // Count of placeable object models and count of instances
int ObjectGroupCount;
MobModel **mob_models;
Placeable **mob_locs;
int mob_model_count, mob_count;
vector<ObjectGroupEntry> ObjectGroups;
vector<string> ModelNames;
vector<Placeable> PlaceableList;
};
#endif
+107
View File
@@ -0,0 +1,107 @@
#ifndef __OPENEQ_THREED_BASE__
#define __OPENEQ_THREED_BASE__
#pragma pack(1)
#include "archive.hpp"
#ifdef GLMODELVIEWER
#include <gl\gl.h> // Header File For The OpenGL32 Library
#endif
struct Light {
float x, y, z;
float r, g, b;
float rad;
} typedef Light;
struct Vertex {
float x, y, z;
float i, j, k;
float u, v;
// int bone;
Vertex()
{
x = y = z = i = j = k = u = v = 0.0f;
};
Vertex(float ix, float iy, float iz)
{
x = ix;
y = iy;
z = iz;
}
} typedef Vertex;
struct Polygon {
int flags;
int v1, v2, v3;
int tex;
} typedef Polygon;
struct Texture {
Archive *archive;
char frame_count;
char current_frame;
#ifdef GLMODELVIEWER
GLuint *tex;
#else
int32 *tex;
#endif
char **filenames;
char flags;
} typedef Texture;
class Model {
public:
Model() { IncludeInMap = false; verts = nullptr; vert_count = 0; polys = nullptr; poly_count = 0; tex = nullptr; tex_count = 0; name = nullptr; }
~Model() {}
Vertex **verts;
Polygon **polys;
Texture **tex;
int vert_count, poly_count, tex_count;
char *name;
bool IncludeInMap; // Include in EQEmu .map file
};
class Placeable {
public:
Placeable() {}
Placeable(int iModel, float ix, float iy, float iz, float irx, float iry, float irz, float iScale0, float iScale1, float iScale2)
{
model = iModel;
x = ix;
y = iy;
z = iz;
rx = irx;
ry = iry;
rz = irz;
scale[0] = iScale0;
scale[1] = iScale1;
scale[2] = iScale2;
}
float x, y, z;
float rx, ry, rz;
float scale[3];
int model;
};
#pragma pack()
#endif
+548
View File
@@ -0,0 +1,548 @@
// Quick and dirty EQ model viewer for Windows, using OpenGL
//
// Put together by Derision from EQEmu forums using basic Windows OpenGL framework from NeHe tutorials @ gamedev.net
// and S3D and EQG file loaders from OpenEQ (modified a bit to fix some bugs and support newer EQG formats).
#ifdef WIN32
#define Polygon Polygon_win32
#include <windows.h>
#undef Polygon
#endif
#include <gl\gl.h>
#include <gl\glu.h>
#include <stdio.h>
#include <cstdlib>
#include <math.h>
#include "types.h"
#include "wld.hpp"
#include "archive.hpp"
#include "pfs.hpp"
#include "file_loader.hpp"
#include "zon.hpp"
#include "zonv4.hpp"
#include "ter.hpp"
typedef struct _vertex{
float x;
float y;
float z;
}VERTEX;
void DrawEQModel(FileLoader *fileloader, int modnum);
FileLoader *mfileloader;
bool ProcessZoneFile(const char *shortname);
enum EQFileType { S3D, EQG, UNKNOWN };
HDC hDC=NULL;
HGLRC hRC=NULL;
HWND hWnd=NULL;
HINSTANCE hInstance;
bool keys[256];
char ch;
bool active=true;
GLuint base;
int modelnum = 1; // The Number of the model we are currently displaying.
float angle = 0; // used to rotate the model. Updated by a timer
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); // Declaration For WndProc
GLvoid BuildFont(GLvoid)
{
HFONT font;
HFONT oldfont;
base = glGenLists(96);
font = CreateFont(-24, 0, 0, 0, FW_BOLD, false, false, false, ANSI_CHARSET,
OUT_TT_PRECIS, CLIP_DEFAULT_PRECIS, ANTIALIASED_QUALITY,
FF_DONTCARE|DEFAULT_PITCH, "Courier New");
oldfont = (HFONT)SelectObject(hDC, font);
wglUseFontBitmaps(hDC, 32, 96, base);
SelectObject(hDC, oldfont);
DeleteObject(font);
}
GLvoid KillFont(GLvoid)
{
glDeleteLists(base, 96);
}
GLvoid glPrint(const char *fmt, ...)
{
char text[256];
va_list ap;
if (fmt == NULL) return;
va_start(ap, fmt);
vsprintf(text, fmt, ap);
va_end(ap);
glPushAttrib(GL_LIST_BIT);
glListBase(base - 32);
glCallLists(strlen(text), GL_UNSIGNED_BYTE, text);
glPopAttrib();
}
GLvoid ReSizeGLScene(GLsizei width, GLsizei height)
{
if (height==0)height=1;
glViewport(0,0,width,height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(60.0f,(GLfloat)width/(GLfloat)height,0.1f,12000.0f);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
int InitGL(GLvoid)
{
glShadeModel(GL_SMOOTH);
glClearColor(0.0f, 0.0f, 0.0f, 0.5f);
glClearDepth(1.0f);
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LEQUAL);
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
BuildFont();
return true;
}
int DrawGLScene(char *ZoneFileName)
{
char textBuffer[100];
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
if(mfileloader->model_data.models[modelnum])
DrawEQModel(mfileloader, modelnum);
glLoadIdentity();
glTranslatef(0.0f,0.0f,-1.2f);
glColor3f(100.0f,0.0f,0.0f);
glRasterPos2f(-1.15f,0.56f);
if(mfileloader->model_data.models[modelnum])
if(mfileloader->model_data.models[modelnum]->name)
sprintf(textBuffer," %s: Model Number %4d. Name %s", ZoneFileName, modelnum, mfileloader->model_data.models[modelnum]->name);
else
sprintf(textBuffer," %s: Model Number %4d. Not Viewable (load failed).", ZoneFileName, modelnum);
else
sprintf(textBuffer," %s: Model Number %4d. Not Viewable (probably zone mesh).", ZoneFileName, modelnum);
glPrint(textBuffer);
sprintf(textBuffer," Use the + and - keys to cycle through models.");
glRasterPos2f(-1.15f,0.50f);
glPrint(textBuffer);
return true;
}
GLvoid KillGLWindow(GLvoid) {
if (hRC) {
if (!wglMakeCurrent(NULL,NULL)) {
MessageBox(NULL,"Release Of DC And RC Failed.","SHUTDOWN ERROR",MB_OK | MB_ICONINFORMATION);
}
if (!wglDeleteContext(hRC)) {
MessageBox(NULL,"Release Rendering Context Failed.","SHUTDOWN ERROR",MB_OK | MB_ICONINFORMATION);
}
hRC=NULL;
}
if (hDC && !ReleaseDC(hWnd,hDC)) {
MessageBox(NULL,"Release Device Context Failed.","SHUTDOWN ERROR",MB_OK | MB_ICONINFORMATION);
hDC=NULL;
}
if (hWnd && !DestroyWindow(hWnd)) {
MessageBox(NULL,"Could Not Release hWnd.","SHUTDOWN ERROR",MB_OK | MB_ICONINFORMATION);
hWnd=NULL;
}
if (!UnregisterClass("OpenGL",hInstance)) {
MessageBox(NULL,"Could Not Unregister Class.","SHUTDOWN ERROR",MB_OK | MB_ICONINFORMATION);
hInstance=NULL;
}
KillFont();
}
BOOL CreateGLWindow(char* title, int width, int height, int bits) {
GLuint PixelFormat;
WNDCLASS wc;
DWORD dwExStyle;
DWORD dwStyle;
RECT WindowRect;
WindowRect.left=(long)0;
WindowRect.right=(long)width;
WindowRect.top=(long)0;
WindowRect.bottom=(long)height;
hInstance = GetModuleHandle(NULL);
wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
wc.lpfnWndProc = (WNDPROC) WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(NULL, IDI_WINLOGO);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = NULL;
wc.lpszMenuName = NULL;
wc.lpszClassName = "OpenGL";
if (!RegisterClass(&wc)) {
MessageBox(NULL,"Failed To Register The Window Class.","ERROR",MB_OK|MB_ICONEXCLAMATION);
return false;
}
dwExStyle=WS_EX_APPWINDOW | WS_EX_WINDOWEDGE;
dwStyle=WS_OVERLAPPEDWINDOW;
AdjustWindowRectEx(&WindowRect, dwStyle, false, dwExStyle);
if (!(hWnd=CreateWindowEx(dwExStyle, "OpenGL", title, dwStyle|WS_CLIPSIBLINGS|WS_CLIPCHILDREN,
0, 0, WindowRect.right-WindowRect.left, WindowRect.bottom-WindowRect.top,
NULL, NULL, hInstance, NULL))) {
KillGLWindow();
MessageBox(NULL,"Window Creation Error.","ERROR",MB_OK|MB_ICONEXCLAMATION);
return false;
}
static PIXELFORMATDESCRIPTOR pfd= {
sizeof(PIXELFORMATDESCRIPTOR), 1, PFD_DRAW_TO_WINDOW|PFD_SUPPORT_OPENGL|PFD_DOUBLEBUFFER,
PFD_TYPE_RGBA, bits, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, PFD_MAIN_PLANE,
0, 0, 0, 0
};
if (!(hDC=GetDC(hWnd))) {
KillGLWindow();
MessageBox(NULL,"Can't Create A GL Device Context.","ERROR",MB_OK|MB_ICONEXCLAMATION);
return false;
}
if (!(PixelFormat=ChoosePixelFormat(hDC,&pfd))) {
KillGLWindow();
MessageBox(NULL,"Can't Find A Suitable PixelFormat.","ERROR",MB_OK|MB_ICONEXCLAMATION);
return false;
}
if(!SetPixelFormat(hDC,PixelFormat,&pfd)) {
KillGLWindow();
MessageBox(NULL,"Can't Set The PixelFormat.","ERROR",MB_OK|MB_ICONEXCLAMATION);
return false;
}
if (!(hRC=wglCreateContext(hDC))) {
KillGLWindow();
MessageBox(NULL,"Can't Create A GL Rendering Context.","ERROR",MB_OK|MB_ICONEXCLAMATION);
return false;
}
if(!wglMakeCurrent(hDC,hRC)) {
KillGLWindow();
MessageBox(NULL,"Can't Activate The GL Rendering Context.","ERROR",MB_OK|MB_ICONEXCLAMATION);
return false;
}
ShowWindow(hWnd,SW_SHOW);
SetForegroundWindow(hWnd);
SetFocus(hWnd);
ReSizeGLScene(width, height);
if (!InitGL()) {
KillGLWindow();
MessageBox(NULL,"Initialization Failed.","ERROR",MB_OK|MB_ICONEXCLAMATION);
return false;
}
SetTimer(hWnd, 1, 50, (TIMERPROC) NULL);
return true;
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
switch (uMsg) {
case WM_ACTIVATE:
if (!HIWORD(wParam)) active=true;
else
active=false;
return 0;
case WM_SYSCOMMAND:
switch (wParam) {
case SC_SCREENSAVE:
case SC_MONITORPOWER:
return 0;
}
break;
case WM_CLOSE:
PostQuitMessage(0);
return 0;
case WM_KEYDOWN:
keys[wParam] = true;
return 0;
case WM_CHAR:
ch = wParam;
return 0;
case WM_KEYUP:
keys[wParam] = false;
return 0;
case WM_SIZE:
ReSizeGLScene(LOWORD(lParam),HIWORD(lParam));
return 0;
case WM_TIMER:
angle = angle + 1;
if(angle>359) angle = 0;
return 0;
}
return DefWindowProc(hWnd,uMsg,wParam,lParam);
}
void TranslateVertex(VERTEX &v, float XOffset, float YOffset, float ZOffset) {
v.x = v.x + XOffset;
v.y = v.y + YOffset;
v.z = v.z + ZOffset;
}
void ScaleVertex(VERTEX &v, float XScale, float YScale, float ZScale) {
v.x = v.x * XScale;
v.y = v.y * YScale;
v.z = v.z * ZScale;
}
void DrawEQModel(FileLoader *fileloader, int modnum) {
Polygon *poly;
Vertex *verts[3];
VERTEX v1, v2, v3;
float maxDimension = 0, minx = 999999, miny = 999999, minz = 999999, maxx = -999999, maxy=-999999, maxz=-999999;
Model *model = fileloader->model_data.models[modnum];
for(int i = 0; i < model->poly_count; ++i) {
poly = model->polys[i];
verts[0] = model->verts[poly->v1];
verts[1] = model->verts[poly->v2];
verts[2] = model->verts[poly->v3];
for(int j=0; j<3; j++) {
if(verts[j]->x > maxDimension) maxDimension = verts[j]->x;
if(verts[j]->y > maxDimension) maxDimension = verts[j]->y;
if(verts[j]->z > maxDimension) maxDimension = verts[j]->z;
if(verts[j]->x < minx) minx = verts[j]->x;
if(verts[j]->y < miny) miny = verts[j]->y;
if(verts[j]->z < minz) minz = verts[j]->z;
if(verts[j]->x > maxx) maxx = verts[j]->x;
if(verts[j]->y > maxy) maxy = verts[j]->y;
if(verts[j]->z > maxz) maxz = verts[j]->z;
}
}
maxDimension = 0;
if(maxx-minx>maxDimension) maxDimension = maxx-minx;
if(maxy-miny>maxDimension) maxDimension = maxy-miny;
if(maxz-minz>maxDimension) maxDimension = maxz-minz;
// Hack for very small models (e.g. spoons)
if(maxDimension>1)
glTranslatef(-1.5f,0.0f,-(maxDimension*2));
else
glTranslatef(-1.5f,0.0f,-10);
// angle is updated by a timer every 50ms.
glRotatef(angle, 1, 0, 0);
glRotatef(angle, 0, 1, 0);
glRotatef(angle, 0, 0, 1);
glBegin(GL_TRIANGLES);
for(int i = 0; i < model->poly_count; ++i) {
poly = model->polys[i];
verts[0] = model->verts[poly->v1];
verts[1] = model->verts[poly->v2];
verts[2] = model->verts[poly->v3];
v1.x = verts[0]->x; v1.y = verts[0]->y; v1.z = verts[0]->z;
v2.x = verts[1]->x; v2.y = verts[1]->y; v2.z = verts[1]->z;
v3.x = verts[2]->x; v3.y = verts[2]->y; v3.z = verts[2]->z;
// The aim of this is to centre the model in the window
TranslateVertex(v1, -(minx + (maxx-minx)/2), -(miny + (maxy-miny)/2), -(minz + (maxz-minz)/2));
TranslateVertex(v2, -(minx + (maxx-minx)/2), -(miny + (maxy-miny)/2), -(minz + (maxz-minz)/2));
TranslateVertex(v3, -(minx + (maxx-minx)/2), -(miny + (maxy-miny)/2), -(minz + (maxz-minz)/2));
// For very small models, magnify them
if(maxDimension<=1) {
ScaleVertex(v1, 10, 10, 10);
ScaleVertex(v2, 10, 10, 10);
ScaleVertex(v3, 10, 10, 10);
}
// Assign a kind of random colour to each polygon
//glColor3b((i%50)+50,(i*5)%200,(i*10)%200);
float col = (float)(100 + ((i*10) % 150)) /250 * 1.0f;
glColor3f(col, col, col);
glVertex3f(v1.x, v1.z, v1.y);
glVertex3f(v2.x, v2.z, v2.y);
glVertex3f(v3.x, v3.z, v3.y);
}
glEnd();
}
bool ProcessZoneFile(const char *shortname) {
char bufs[96];
Archive *archive;
Zone_Model *zm;
FILE *fff;
EQFileType FileType = UNKNOWN;
GLuint *textures;
sprintf(bufs, "%s.s3d", shortname);
archive = new PFSLoader();
fff = fopen(bufs, "rb");
if(fff != NULL)
FileType = S3D;
else {
sprintf(bufs, "%s.eqg", shortname);
fff = fopen(bufs, "rb");
if(fff != NULL)
FileType = EQG;
}
if(FileType == UNKNOWN) {
MessageBox(NULL,"Unable to locate specified zone either as EQG or S3D","ERROR",MB_OK|MB_ICONEXCLAMATION);
return(false);
}
if(archive->Open(fff) == 0) {
MessageBox(NULL,"Unable to open container file","ERROR",MB_OK|MB_ICONEXCLAMATION);
return(false);
}
switch(FileType) {
case S3D:
mfileloader = new WLDLoader();
if(mfileloader->Open(NULL, (char *) shortname, archive) == 0) {
MessageBox(NULL,"Error reading WLD from container file","ERROR",MB_OK|MB_ICONEXCLAMATION);
return(false);
}
break;
case EQG:
mfileloader = new ZonLoader();
if(mfileloader->Open(NULL, (char *) shortname, archive) == 0) {
delete mfileloader;
mfileloader = new Zonv4Loader();
if(mfileloader->Open(NULL, (char *) shortname, archive) == 0) {
MessageBox(NULL,"Error reading ZON/TER from container file","ERROR",MB_OK|MB_ICONEXCLAMATION);
return(false);
}
}
break;
case UNKNOWN:
break;
}
if(mfileloader->model_data.model_count==0) {
MessageBox(NULL,"No models found. For S3D, probably could not locate _obj.s3d file","ERROR",MB_OK|MB_ICONEXCLAMATION);
return false;
}
zm = mfileloader->model_data.zone_model;
return(true);
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
MSG msg;
BOOL done=false;
FILE *fp;
for(int i=0;i<256;i++)
keys[i] = false;
char* buf = (char *) new char[strlen(lpCmdLine) + 1] ;
char *pTmp = buf;
if(!strlen(lpCmdLine)) {
MessageBox(NULL,"Specify the shortname of the zone (without the S3D or EQG extension) on the command line.",
"ERROR",MB_OK | MB_ICONINFORMATION);
return 0;
}
strcpy(buf,lpCmdLine);
if(!ProcessZoneFile(buf)) return 0;
if (!CreateGLWindow("EQ Model Viewer",1280,768,16))
return 0;
while(!done) {
if (PeekMessage(&msg,NULL,0,0,PM_REMOVE)) {
if (msg.message==WM_QUIT)
done=true;
else {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
else {
if ((active && !DrawGLScene(buf)) || keys[VK_ESCAPE])
done=true;
else
SwapBuffers(hDC);
// Use + and - to cycle through the models
if (toupper(ch)=='+') {
if(modelnum+1 < mfileloader->model_data.model_count)
modelnum++;
else
modelnum=0;
angle = 0;
}
if (toupper(ch)=='-') {
if(modelnum>0)
modelnum--;
else
modelnum = mfileloader->model_data.model_count - 1;
angle = 0;
}
ch = 0;
}
}
KillGLWindow();
return (msg.wParam);
}
+3
View File
@@ -0,0 +1,3 @@
#pragma once
#include "resource.h"
+79
View File
@@ -0,0 +1,79 @@
Azone2, awater, listobj, glModelViewer
azone2 creates .map files for EQEmu, used in LOS and BestZ, etc.
.S3D and .EQG zone files found with the Titanium EQ distribution are
supported.
to use all of these utilities, copy them to a directory containing your .S3D and .EQG
files.
IMPORTANT NOTE:
Older EQGs had the .ZON file within the .EQG container. Newer EQGs, e.g.
tutorialb, dreadspire, have the .ZON file as a separate file in your EQ directory.
To include placeable objects for these, YOU MUST have both the .EQG and .ZON file
in the same directory as azone2.
To generate a map file, specifit the shortname of the zone (without the extension).
e.g.
./azone2 tox
./azone2 anguish
Copy the resultant .map file to the Maps directory on your server.
20/06/08 Derision:
To include placeable objects, use the listobj program to find the models you want,
e.g. ./listobj tox
LISTOBJ: List Placeable Objects in .S3D or .EQG zone files.
Placeable Object 0 @ ( -420.42, 2443.43, -50.30 uses model 27 TIKI_DMSPRITEDEF
Placeable Object 1 @ ( -482.54, 2446.06, -45.13 uses model 27 TIKI_DMSPRITEDEF
Placeable Object 2 @ ( -439.99, 2603.35, -29.50 uses model 28 TORCH1_DMSPRITEDEF
Placeable Object 3 @ ( 158.28, 1094.74, -50.40 uses model 27 TIKI_DMSPRITEDEF
Placeable Object 4 @ ( 137.83, 1074.79, -49.91 uses model 17 HUT4_DMSPRITEDEF
Placeable Object 5 @ ( 150.64, 1205.48, -48.46 uses model 27 TIKI_DMSPRITEDEF
Placeable Object 6 @ ( 128.19, 1204.95, -48.37 uses model 27 TIKI_DMSPRITEDEF
Placeable Object 7 @ ( 139.57, 1153.50, -53.74 uses model 20 KDOCK_DMSPRITEDEF
Placeable Object 8 @ ( 1139.42, -837.60, -55.38 uses model 5 ERBRAZIER_DMSPRITEDEF
^
|
|
This is the model number -------------|
If you want azone to include all occurrences of HUT4_DMSPRITEDF (model 17) and KDOCK_DMSPRITEDF (20),
you would add a line to azone.ini as follows:
# Include huts, houses and bridge from tox
tox.s3d,17,20
# Include two bridges from Tutorialb
tutorialb.eqg,17,47
# Include a couple of towers in Anguish
anguish.eqg,7,8
Note that as you can only specify a model number, it is not possible to only have selected occurrences
of that model included.
Lines in azone.ini beginning with a # are ignored.
TO INCLUDE PLACEABLE MODELS FOR .S3D ZONES, THE _OBJ.S3D FILE FOR THAT ZONE MUST ALSO BE PRESENT IN THE
SAME DIRECTORY.
You can also use glmodelviewer (Windows only) to display the models in a zone to find the ones you want
to include. To run it, from a command prompt, e.g.
glmodelviewer wallofslaughter
Finally, awater generates .wtr files containing details of the water, lava, PVP etc areas in an S3D zone.
Usage example:
./awater fieldofbone
The windows solution and project files provided were produced with Visual C++ 2008 and as configured,
require a statically linkable zlib.lib.
+32
View File
@@ -0,0 +1,32 @@
#ifndef __OPENEQ_ARCHIVE_API__
#define __OPENEQ_ARCHIVE_API__
#include "global.hpp"
#include <stdio.h>
class Archive {
public:
Archive() {}
virtual ~Archive() {}
virtual int Open(FILE *fp) = 0;
virtual int Close() = 0;
virtual int GetFile(char *name, uchar **buf, int *len) = 0;
virtual const char *FindExtension(const char *ext) = 0;
char **filenames;
int count;
protected:
uchar *buffer;
int buf_len;
int status;
uint32 *files;
FILE *fp;
};
#endif
+375
View File
@@ -0,0 +1,375 @@
/*
AWater: Generate 'Water Maps' for EQEmu. 'Water Maps' is a misnomer as,
while originally intended to produce a map of water regions from .S3D
zone files, it also includes details of lava, PVP and other 'special'
areas.
Based on Azone (Father NitWit) and OpenEQ (Daeken et al). Original
copyright notice from Azone follows:
Father Nitwit's Zone to map conversion program.
Copyright (C) 2004 Father Nitwit (eqemu@8ass.com)
This thing uses code from freaku, so whatever license that comes under
is relavent, if you care.
the rest of it is GPL, even though I hate the GPL.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY except by those people which sell it, which
are required to give you total support for your newly bought product;
without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
typedef unsigned char BYTE;
typedef unsigned short WORD;
typedef short SHORT;
typedef unsigned long DWORD;
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <stdlib.h>
//#include "EQWldData.h"
#include "awater.h"
#include "types.h"
#include "s3d.h"
#include "wld.hpp"
#include "archive.hpp"
#include "pfs.hpp"
#include "file_loader.hpp"
#include "zon.hpp"
#include "ter.hpp"
//this un-commented works with my map.cpp code correctly.
//with both of my inverts there commented.
#define INVERSEXY 1
#include <vector>
#include <map>
using namespace std;
//#define SPLIT_DEBUG
bool BuildWaterMap(const char *shortname, long DefaultRegionType);
void PrintBSP(BSP_Node *tree, long node_number);
long BSPFindRegion(BSP_Node *tree, long node_number, long region);
long BSPFindNode(BSP_Node *tree, long node_number, float x, float y, float z);
long BSPMarkRegion(BSP_Node *tree, long node_number, long region, int region_type);
long BSPCountNodes(BSP_Node *tree, long node_number);
int main(int argc, char *argv[]) {
long DefaultRegionType=RegionTypeWater;
if((argc < 2) ||
(argc > 3) ||
#ifndef WIN32
((argc == 3)&&(strcasecmp(argv[1],"-dl")))) {
#else
((argc == 3)&&(_stricmp(argv[1],"-dl")))) {
#endif
printf("Usage: %s [-dl] (zone short name) to generate a water/lava map\n\n", argv[0]);
printf(" -dl = mark special regions as lava if not tagged in .WLD\n");
printf("\nIf -dl is omitted, untagged special regions will be marked as water\n");
return(1);
}
char bufm[250];
if(argc==3)
DefaultRegionType=RegionTypeLava;
sprintf(bufm, "%s.wtr", argv[argc-1]);
if(!BuildWaterMap(argv[argc-1],DefaultRegionType))
return(1);
return(0);
}
bool BuildWaterMap(const char *shortname, long DefaultRegionType) {
char bufs[96];
Archive *archive;
WLDLoader *fileloader;
long WaterOrLavaCount = 0;
//TODO: clean up a LOT of memory that the freaku code does not
sprintf(bufs, "%s.s3d", shortname);
archive = new PFSLoader();
FILE *s3df = fopen(bufs, "rb");
if(s3df == nullptr) {
// One day we may try EQG, but not today.
printf("Unable to open s3d file '%s'.\n", bufs);
return(false);
}
if(archive->Open(s3df) == 0) {
printf("Unable to open s3d file '%s'.\n", bufs);
return(false);
}
printf("Loading %s...\n", bufs);
fileloader = new WLDLoader();
if(fileloader->Open(nullptr, (char *) shortname, archive) == 0) {
printf("Error reading WLD from %s\n", bufs);
return(false);
}
BSP_Node *tree = fileloader->tree;
struct_Data29 *data29;
for(int i=0; i<fileloader->fragcount; i++) {
if(fileloader->frags[i]->type == 0x29) {
printf("We have a type 0x29 fragment. ");
data29 = (struct_Data29 *) fileloader->frags[i]->frag;
printf("It has %ld regions and is marked as type %d. ",
data29->region_count, data29->region_type);
switch(data29->region_type) {
case RegionTypeUnsupported: { printf("Unsupported\n"); break; }
case RegionTypeUntagged: {
printf("Untagged. We will set it to ");
if(DefaultRegionType==RegionTypeWater) {
printf("Water\n");
} else printf("Lava\n");
data29->region_type = DefaultRegionType;
WaterOrLavaCount++;
break;
}
case RegionTypeWater: { printf("Water\n"); WaterOrLavaCount++; break; }
case RegionTypeLava: { printf("Lava\n"); WaterOrLavaCount++; break; }
case RegionTypeZoneLine: { printf("Zoneline\n"); break; }
case RegionTypePVP: { printf("PVP\n"); break; }
case RegionTypeSlime: { printf("Slime\n"); break; }
case RegionTypeIce: { printf("Ice\n"); break; }
case RegionTypeVWater: { printf("VWATER\n"); break; }
default: printf("UNKNOWN\n");
}
}
}
if(tree==nullptr) {
printf("No BSP Tree. Bailing out\n");
return(false);
}
unsigned long BSPTreeSize = BSPCountNodes(tree, 1);
printf("There are %ld nodes in the BSP tree\n", BSPTreeSize);
// Now we mark each leaf in the BSP tree that is in a 'special area' with what type the area is
// Water, Lava, Zoneline etc
for(int i=0; i<fileloader->fragcount; i++) {
if(fileloader->frags[i]->type == 0x29) {
data29 = (struct_Data29 *) fileloader->frags[i]->frag;
for(long j=0; j<data29->region_count; j++) {
BSPMarkRegion(tree, 1,data29->region_array[j]+1, data29->region_type);
}
}
}
// Now write out the file
char bufm[250];
sprintf(bufm, "%s.wtr", shortname);
FILE *WaterFile = fopen(bufm, "wb");
if(WaterFile == nullptr) {
printf("Failed to open %s for writing\n", bufm);
return(false);
}
const char *WFMagic = "EQEMUWATER";
const long WFVersion = 1;
if(fwrite(WFMagic, strlen(WFMagic), 1, WaterFile) != 1) {
printf("Error writing output file\n");
fclose(WaterFile);
return(false);
}
if(fwrite(&WFVersion, sizeof(WFVersion), 1, WaterFile) != 1) {
printf("Error writing output file\n");
fclose(WaterFile);
return(false);
}
if(fwrite(&BSPTreeSize, sizeof(BSPTreeSize), 1, WaterFile) != 1) {
printf("Error writing output file\n");
fclose(WaterFile);
return(false);
}
if(fwrite(tree, sizeof(BSP_Node), BSPTreeSize, WaterFile) != BSPTreeSize) {
printf("Error writing output file\n");
fclose(WaterFile);
return(false);
}
fclose(WaterFile);
return(true);
}
void PrintBSP(BSP_Node *tree, long node_number) {
printf("Node %ld, Left=%ld, Right=%ld\n",
node_number-1,
tree[node_number-1].left,
tree[node_number-1].right);
printf("Normals are %4.3f, %4.3f, %4.3f, SplitD is %4.3f\n",
tree[node_number-1].normal[0],
tree[node_number-1].normal[1],
tree[node_number-1].normal[2],
tree[node_number-1].splitdistance);
if(tree[node_number-1].left!=0) PrintBSP(tree, tree[node_number-1].left);
if(tree[node_number-1].right!=0) PrintBSP(tree, tree[node_number-1].right);
if((tree[node_number-1].left==0)&&
(tree[node_number-1].right==0)) {
printf("Region pointer is %ld\n", tree[node_number-1].region);
}
}
long BSPCountNodes(BSP_Node *tree, long node_number) {
long NodesInRightBranch = 0, NodesInLeftBranch = 0;
if((tree[node_number-1].left==0)&&
(tree[node_number-1].right==0)) return 1;
if(tree[node_number-1].left!=0) NodesInLeftBranch = BSPCountNodes(tree, (tree[node_number-1].left));
if(tree[node_number-1].right!=0) NodesInRightBranch = BSPCountNodes(tree, (tree[node_number-1].right));
return(NodesInRightBranch + NodesInLeftBranch + 1);
}
long BSPFindRegion(BSP_Node *tree, long node_number, long region) {
//printf("Find Region %ld in node %ld\n", region, node_number);
if(node_number<1) {
printf("Something went wrong\n");
exit(1);
}
if((tree[node_number-1].left==0)&&
(tree[node_number-1].right==0)) {
if(tree[node_number-1].region==region) return node_number;
}
long retnode ;
if(tree[node_number-1].left!=0) {
retnode = BSPFindRegion(tree, tree[node_number-1].left, region);
if(retnode != 0) return retnode ;
}
if(tree[node_number-1].right!=0) {
return BSPFindRegion(tree, tree[node_number-1].right, region);
}
return 0;
}
long BSPFindNode(BSP_Node *tree, long node_number, float x, float y, float z) {
float distance;
printf("BSP Find Node, currently in Node %ld\n", node_number);
// Are we at a leaf
if((tree[node_number-1].left==0)&&
(tree[node_number-1].right==0)) {
return tree[node_number-1].region;
}
// No, so determine which side of the split plane we are on
//
distance = (x * tree[node_number-1].normal[0]) +
(y * tree[node_number-1].normal[1]) +
(z * tree[node_number-1].normal[2]) +
tree[node_number-1].splitdistance;
printf("Distance is %4.3f\n", distance);
// Guess which side to go down
if(distance == 0.0f) {
printf("Distance is 0, don't know what to do!\n");
exit(1);
}
if(distance >0.0f) {
if(tree[node_number-1].left==0) {
printf("Pos and no left node, abort!\n");
exit(1);
}
return BSPFindNode(tree, tree[node_number-1].left,
x, y, z);
}
if(tree[node_number-1].right==0) {
printf("Neg and no right node, abort!\n");
exit(1);
}
return BSPFindNode(tree, tree[node_number-1].right,
x, y, z);
}
long BSPMarkRegion(BSP_Node *tree, long node_number, long region, int region_type) {
//printf("Find Region %ld in node %ld\n", region, node_number);
if(node_number<1) {
printf("Something went wrong\n");
exit(1);
}
if((tree[node_number-1].left==0)&&
(tree[node_number-1].right==0)) {
if(tree[node_number-1].region==region) {
tree[node_number-1].special=region_type;
return node_number;
}
}
long retnode ;
if(tree[node_number-1].left!=0) {
retnode = BSPMarkRegion(tree, tree[node_number-1].left, region, region_type);
if(retnode != 0) return retnode ;
}
if(tree[node_number-1].right!=0) {
return BSPMarkRegion(tree, tree[node_number-1].right, region, region_type);
}
return 0;
}
+16
View File
@@ -0,0 +1,16 @@
typedef enum {
RegionTypeUnsupported = -2,
RegionTypeUntagged = -1,
RegionTypeNormal = 0,
RegionTypeWater = 1,
RegionTypeLava = 2,
RegionTypeZoneLine = 3,
RegionTypePVP = 4,
RegionTypeSlime = 5,
RegionTypeIce = 6,
RegionTypeVWater =7
} WaterRegionType;
File diff suppressed because it is too large Load Diff
+200
View File
@@ -0,0 +1,200 @@
#ifndef AZONE_H
#define AZONE_H
//pull in datatypes from zone's map.h
#include "../../zone/map.h"
#include "file_loader.hpp"
/*
Father Nitwit's zone to map file converter.
*/
#include <stdio.h>
#include <vector>
#include <map>
using namespace std;
#define COUNT_MACTHES 1
//this is the version number to put in the map header
#undef MAP_VERSION //override this from map.h with our version
#define MAP_VERSION 0x01000000
//quadtree stopping criteria, comment any to disable them
#define MAX_QUADRENT_FACES 50 //if box has fewer than this, stop
#define MIN_QUADRENT_SIZE 100.0f //if box has a dimention smaller than this, stop
#define MIN_QUADRENT_GAIN 0.3f //minimum split ratio before stopping
#define MAX_QUADRENT_MISSES 2 //maximum number of quads which can miss their gains
//1 or 2 make sense, others are less useful
//attepmt to trim the data a little
#define MAX_Z 3000.0 //seems to be a lot of points above this
//if all points on poly are, kill it.
/*
This is used for the recursive node structure
unsigned shorts are adequate because, worst case
even in a zone that is 6000x6000 with a small node
size of 30x30, there are only 40000 nodes.
quadrent definitions:
quad 1 (nodes[0]):
x>=0, y>=0
quad 2 (nodes[1]):
x<0, y>=0
quad 3 (nodes[2]):
x<0, y<0
quad 4 (nodes[3]):
x>=0, y<0
*/
#define MAX_POLY_VTX 24 //arbitrary, im too lazy to figure it out
//cut a triangle at most 6 times....
enum EQFileType { S3D, EQG, UNKNOWN };
struct POLYGON {
VERTEX /*w[MAX_POLY_VTX], */c[MAX_POLY_VTX];
int count; // w is world points, c is for camera points
};
class GPoint {
public:
GPoint();
GPoint(VERTEX &v);
GPoint(float x, float y, float z);
inline void operator()(float nx, float ny, float nz) { x = nx; y = ny; z = nz; }
GPoint cross(const GPoint &them) const;
float dot3(const GPoint &them) const;
float x;
float y;
float z;
};
GPoint operator-(const GPoint &v1, const GPoint &v2);
class GVector : public GPoint {
public:
GVector();
GVector(const GPoint &them);
GVector(float x, float y, float z, float w = 1.0f);
inline void operator()(float nx, float ny, float nz, float nw) { x = nx; y = ny; z = nz; W = nw; }
float dot4(const GVector &them) const;
float dot4(const GPoint &them) const;
void normalize();
float length();
float W;
};
struct FaceRecord {
FACE *face;
unsigned long index;
};
class QTNode;
class QTBuilder {
public:
QTBuilder();
~QTBuilder();
bool build(const char *shortname);
bool build_eqg(const char *shortname);
void AddPlaceable(FileLoader *fileloader, char *ZoneFileName, bool ListPlaceable=false);
void AddPlaceableV4(FileLoader *fileloader, char *ZoneFileName, bool ListPlaceable=false);
void RotateVertex(VERTEX &v, float XRotation, float YRotation, float ZRotation);
void ScaleVertex(VERTEX &v, float XScale, float YScale, float ZScale);
void TranslateVertex(VERTEX &v, float XOffset, float YOffset, float ZOffset);
bool writeMap(const char *file);
bool FaceInNode(const QTNode *q, const FACE *f);
protected:
void AddFace(VERTEX &v1, VERTEX &v2, VERTEX &v3);
int ClipPolygon(POLYGON *poly, GVector *plane);
//dynamic during load
// vector<VERTEX> _VertexList;
vector<FACE> _FaceList;
//static once loaded
// unsigned long vertexCount;
unsigned long faceCount;
// VERTEX * vertexBlock;
FACE * faceBlock;
VERTEX tempvtx[MAX_POLY_VTX];
QTNode *_root;
static void NormalizeN(FACE *p);
#ifdef COUNT_MACTHES
unsigned long gEasyMatches;
unsigned long gEasyExcludes;
unsigned long gHardMatches;
unsigned long gHardExcludes;
#endif
};
//quadtree node container
class QTNode {
public:
QTNode(QTBuilder *builder, float Tminx, float Tmaxx, float Tminy, float Tmaxy);
~QTNode();
void clearNodes();
void doSplit();
void divideYourself(int depth);
void buildVertexes();
// bool writeFile(FILE *out);
unsigned long countNodes() const;
unsigned long countFacelists() const;
void fillBlocks(nodeHeader *heads, unsigned long *flist, unsigned long &hindex, unsigned long &findex);
float minx;
float miny;
float maxx;
float maxy;
unsigned long nfaces;
vector<FaceRecord> faces;
/*
quadrent definitions:
quad 1 (node1):
x>=0, y>=0
quad 2 (node2):
x<0, y>=0
quad 3 (node3):
x<0, y<0
quad 4 (node4):
x>=0, y<0
*/
QTNode *node1;
QTNode *node2;
QTNode *node3;
QTNode *node4;
GPoint v[8];
bool final;
protected:
QTBuilder *builder;
};
#endif
+10
View File
@@ -0,0 +1,10 @@
# Include huts, houses dock and bridge from tox
tox.s3d,7,17,20,26
# Include two bridges from Tutorialb
tutorialb.eqg,17,47
# Include prison, ramp and a couple of towers in Anguish
anguish.eqg,5,7,8,119
# Include ruined buildings in LOIO
lakeofillomen.s3d,49,50,51,52,53,54,55,56,57
# Include bridges in thundercrest
thundercrest.eqg,14,51
File diff suppressed because it is too large Load Diff
+61
View File
@@ -0,0 +1,61 @@
#ifndef __OPENEQ_DAT__
#define __OPENEQ_DAT__
#include "global.hpp"
#include "file_loader.hpp"
#pragma pack(1)
struct dat_header {
unsigned long version, list_len, mat_count, vert_count, tri_count;
} typedef dat_header;
struct dat_vertex {
float x, y, z;
float i, j, k;
float u, v;
} typedef dat_vertex;
struct dat_vertexV3 {
float x, y, z;
float i, j, k;
long unk1;
float unk2, unk3;
float u, v;
} typedef dat_vertexV3;
struct dat_triangle {
long v1, v2, v3;
long group;
long unk;
} typedef dat_triangle;
struct dat_object {
long index;
long name_offset, another_name_offset;
long property_count;
} typedef dat_object;
struct dat_property {
long name_offset, type, value;
} typedef dat_property;
struct dat_material {
char *name;
char *basetex;
char var_count;
char **var_names;
char **var_vals;
} typedef dat_material;
#pragma pack()
class DATLoader : public FileLoader {
public:
DATLoader();
~DATLoader();
virtual int Open(char *base_path, char *zone_name, Archive *archive);
virtual int Close();
};
#endif
+31
View File
@@ -0,0 +1,31 @@
#include <stdio.h>
#include <string.h>
#include "file.hpp"
int GetFile(uchar **buffer, int *buf_len, char *base_path, char *file_name, Archive *archive) {
FILE *fp;
char *temp;
if(base_path) {
temp = new char[strlen(base_path) + strlen(file_name) + 2];
sprintf(temp, "%s/%s", base_path, file_name);
fp = fopen(temp, "rb");
delete[] temp;
if(!fp)
return 0;
fseek(fp, 0, SEEK_END);
*buf_len = ftell(fp);
fseek(fp, 0, SEEK_SET);
*buffer = new uchar[*buf_len];
fread(*buffer, 1, *buf_len, fp);
fclose(fp);
return 1;
}
else
return archive->GetFile(file_name, buffer, buf_len);
}
+8
View File
@@ -0,0 +1,8 @@
#ifndef __OPENEQ_FILE__
#define __OPENEQ_FILE__
#include "archive.hpp"
int GetFile(uchar **buffer, int *buf_len, char *base_path, char *file_name, Archive *archive);
#endif
+24
View File
@@ -0,0 +1,24 @@
#ifndef __OPENEQ_FL_API__
#define __OPENEQ_FL_API__
#include "archive.hpp"
#include "3d.hpp"
class FileLoader {
public:
FileLoader() {}
virtual ~FileLoader() {}
virtual int Open(char *base_path, char *zone_name, Archive *archive) = 0;
virtual int Close() = 0;
Content_3D model_data;
protected:
uchar *buffer;
int buf_len;
Archive *archive;
int status;
};
#endif
+16
View File
@@ -0,0 +1,16 @@
#include "global.hpp"
#define swapl
#define swaps
uint16 GetUint16(uchar **buf) {
uint16 ret = swaps(*((uint16 *) *buf));
*buf += 2;
return ret;
}
uint32 GetUint32(uchar **buf) {
uint32 ret = swapl(*((uint32 *) *buf));
*buf += 4;
return ret;
}
+30
View File
@@ -0,0 +1,30 @@
#ifndef __OPENEQ_GLOBALS__
#define __OPENEQ_GLOBALS__
#ifdef WIN32
#define Polygon Polygon_Win32
#include <winsock.h>
#undef Polygon
#else
#include <netinet/in.h>
#endif
typedef unsigned int uint32;
typedef int int32;
typedef unsigned short uint16;
typedef short int16;
typedef unsigned char uint8;
typedef unsigned char uchar;
typedef char int8;
uint16 GetUint16(uchar **buf);
uint32 GetUint32(uchar **buf);
#define uint16(buf) \
GetUint16((uchar **) &buf)
#define uint32(buf) \
GetUint32((uchar **) &buf)
#endif
+214
View File
@@ -0,0 +1,214 @@
/*
List Placeable Objects in an S3D or EQG.
By Derision, based on OpenEQ File Loaders by Daeken et al.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY except by those people which sell it, which
are required to give you total support for your newly bought product;
without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
typedef unsigned char BYTE;
typedef unsigned short WORD;
typedef short SHORT;
typedef unsigned long DWORD;
#include <stdio.h>
#include <string.h>
#include <math.h>
#include "types.h"
#include "wld.hpp"
#include "archive.hpp"
#include "pfs.hpp"
#include "file_loader.hpp"
#include "zon.hpp"
#include "ter.hpp"
#include "zonv4.hpp"
bool ProcessZoneFile(const char *shortname);
void ListPlaceable(FileLoader *fileloader, char *ZoneFileName);
void ListPlaceableV4(FileLoader *fileloader, char *ZoneFileName);
enum EQFileType { S3D, EQG, UNKNOWN };
int main(int argc, char *argv[]) {
printf("LISTOBJ: List Placeable Objects in .S3D or .EQG zone files.\n");
if(argc != 2) {
printf("Usage: %s (zone short name)\n", argv[0]);
return(1);
}
return(ProcessZoneFile(argv[1]));
}
bool ProcessZoneFile(const char *shortname) {
char bufs[96];
Archive *archive;
FileLoader *fileloader;
Zone_Model *zm;
FILE *fff;
EQFileType FileType = UNKNOWN;
sprintf(bufs, "%s.s3d", shortname);
archive = new PFSLoader();
fff = fopen(bufs, "rb");
if(fff != nullptr)
FileType = S3D;
else {
sprintf(bufs, "%s.eqg", shortname);
fff = fopen(bufs, "rb");
if(fff != nullptr)
FileType = EQG;
}
if(FileType == UNKNOWN) {
printf("Unable to locate %s.s3d or %s.eqg\n", shortname, shortname);
return(false);
}
if(archive->Open(fff) == 0) {
printf("Unable to open container file '%s'\n", bufs);
return(false);
}
bool V4Zone = false;
switch(FileType) {
case S3D:
fileloader = new WLDLoader();
if(fileloader->Open(nullptr, (char *) shortname, archive) == 0) {
printf("Error reading WLD from %s\n", bufs);
return(false);
}
break;
case EQG:
fileloader = new ZonLoader();
if(fileloader->Open(nullptr, (char *) shortname, archive) == 0) {
delete fileloader;
fileloader = new Zonv4Loader();
if(fileloader->Open(nullptr, (char *) shortname, archive) == 0) {
printf("Error reading ZON/TER from %s\n", bufs);
return(false);
}
V4Zone = true;
}
break;
case UNKNOWN:
break;
}
zm = fileloader->model_data.zone_model;
if(!V4Zone)
ListPlaceable(fileloader, bufs);
else
ListPlaceableV4(fileloader, bufs);
return(true);
}
void ListPlaceable(FileLoader *fileloader, char *ZoneFileName) {
for(int i = 0; i < fileloader->model_data.plac_count; ++i) {
if(fileloader->model_data.placeable[i]->model==-1) continue;
if(fileloader->model_data.models[fileloader->model_data.placeable[i]->model] == nullptr) continue;
printf("Placeable Object %4d @ (%9.2f, %9.2f, %9.2f uses model %4d %s\n",i,
fileloader->model_data.placeable[i]->y,
fileloader->model_data.placeable[i]->x,
fileloader->model_data.placeable[i]->z,
fileloader->model_data.placeable[i]->model,
fileloader->model_data.models[fileloader->model_data.placeable[i]->model]->name);
}
}
void ListPlaceableV4(FileLoader *fileloader, char *ZoneFileName)
{
float XOffset, YOffset, ZOffset;
float RotX, RotY, RotZ;
float XScale, YScale, ZScale;
vector<ObjectGroupEntry>::iterator Iterator;
int OGNum = 0;
Iterator = fileloader->model_data.ObjectGroups.begin();
while(Iterator != fileloader->model_data.ObjectGroups.end())
{
printf("ObjectGroup Number: %i\n", OGNum++);
printf("ObjectGroup Coordinates: %8.3f, %8.3f, %8.3f\n",
(*Iterator).x, (*Iterator).y, (*Iterator).z);
printf("Tile: %8.3f, %8.3f, %8.3f\n",
(*Iterator).TileX, (*Iterator).TileY, (*Iterator).TileZ);
printf("ObjectGroup Rotations : %8.3f, %8.3f, %8.3f\n",
(*Iterator).RotX, (*Iterator).RotY, (*Iterator).RotZ);
printf("ObjectGroup Scale : %8.3f, %8.3f, %8.3f\n",
(*Iterator).ScaleX, (*Iterator).ScaleY, (*Iterator).ScaleZ);
list<int>::iterator ModelIterator;
ModelIterator = (*Iterator).SubObjects.begin();
while(ModelIterator != (*Iterator).SubObjects.end())
{
int SubModel = (*ModelIterator);
Model *model = fileloader->model_data.models[fileloader->model_data.placeable[SubModel]->model];
printf(" SubModel: %i [Model: %i, %s] ", SubModel, fileloader->model_data.placeable[SubModel]->model, model->name );
printf("Default to include in map: %s\n", model->IncludeInMap ? "YES" : "NO");
XOffset = fileloader->model_data.placeable[SubModel]->x;
YOffset = fileloader->model_data.placeable[SubModel]->y;
ZOffset = fileloader->model_data.placeable[SubModel]->z;
printf(" Translations: %8.3f, %8.3f, %8.3f\n", XOffset, YOffset, ZOffset);
printf(" Rotations : %8.3f, %8.3f, %8.3f\n", fileloader->model_data.placeable[SubModel]->rx,
fileloader->model_data.placeable[SubModel]->ry, fileloader->model_data.placeable[SubModel]->rz);
printf(" Scale : %8.3f, %8.3f, %8.3f\n", fileloader->model_data.placeable[SubModel]->scale[0],
fileloader->model_data.placeable[SubModel]->scale[1], fileloader->model_data.placeable[SubModel]->scale[2]);
RotX = fileloader->model_data.placeable[SubModel]->rx * 3.14159 / 180; // Convert from degrees to radians
RotY = fileloader->model_data.placeable[SubModel]->ry * 3.14159 / 180;
RotZ = fileloader->model_data.placeable[SubModel]->rz * 3.14159 / 180;
XScale = fileloader->model_data.placeable[SubModel]->scale[0];
YScale = fileloader->model_data.placeable[SubModel]->scale[1];
ZScale = fileloader->model_data.placeable[SubModel]->scale[2];
++ModelIterator;
}
printf("\n");
Iterator++;
}
}
+43
View File
@@ -0,0 +1,43 @@
#ifndef __OPENEQ_OCTREE__
#define __OPENEQ_OCTREE__
#ifdef WIN32
#define Polygon Polygon_win32
#include <windows.h>
#undef Polygon
#endif
#include "3d_base.hpp"
class Octree_Node {
public:
Octree_Node();
Octree_Node(int poly_count, Polygon **polys, Vertex **verts, int plac_count, Placeable **plac);
Octree_Node(int poly_count, Polygon **polys, Vertex **verts, int plac_count, Placeable **plac, float min[3], float max[3]);
~Octree_Node();
void FindMinMax();
void Split(char level);
float min[3], max[3];
float x, y, z, size, sizes[3];
int poly_count;
Vertex **verts;
Polygon **polys;
int plac_count;
Placeable **plac;
GLuint li;
Octree_Node *nodes[8];
};
#define in_box(obj, x, y, z) \
( \
(x) >= (obj)->min[0] && (x) <= (obj)->max[0] && \
(y) >= (obj)->min[1] && (y) <= (obj)->max[1] &&\
(z) >= (obj)->min[2] && (z) <= (obj)->max[2] \
)
#endif
+253
View File
@@ -0,0 +1,253 @@
// This source is from OpenEQ by Daeken et al. Modified a bit by Derision, some bug fixes etc.
#include <string.h>
#include <zlib.h>
#include "pfs.hpp"
#pragma pack(1)
//#define DEBUGPFS
struct struct_header {
uint32 offset;
char magicCookie[4];
uint32 unknown;
} typedef struct_header;
struct struct_directory_header {
uint32 count;
} typedef struct_directory_header;
struct struct_directory {
uint32 crc, offset, size;
} typedef struct_directory;
struct struct_data_block {
uint32 deflen, inflen;
} typedef struct_data_block;
struct struct_fn_header {
uint32 fncount;
} typedef struct_fn_header;
struct struct_fn_entry {
uint32 fnlen;
} typedef struct_fn_entry;
#pragma pack()
inline void decompress(char *p, char *p2, int len, int uLen) {
int status;
z_stream d_stream;
d_stream.zalloc = (alloc_func)0;
d_stream.zfree = (free_func)0;
d_stream.opaque = (voidpf)0;
d_stream.next_in = (Bytef *) p;
d_stream.avail_in = len;
d_stream.next_out = (Bytef *) p2;
d_stream.avail_out = uLen;
inflateInit(&d_stream);
status = inflate(&d_stream, Z_NO_FLUSH);
inflateEnd(&d_stream);
}
inline void Lower(char *str) {
while(*str) {
if(*str >= 'A' && *str <= 'Z')
*str += 'a' - 'A';
++str;
}
}
PFSLoader::PFSLoader() {
// Set the status of the loader that nothing is loaded.
this->buffer = nullptr;
this->buf_len = -1;
this->status = 0;
}
PFSLoader::~PFSLoader() {
this->Close();
}
int PFSLoader::Open(FILE *fp)
{
struct_header s3d_header;
struct_directory_header s3d_dir_header;
struct_directory s3d_dir;
struct_data_block s3d_data;
struct_fn_header *s3d_fn_header;
struct_fn_entry *s3d_fn_entry;
uint32 *offsets;
char *temp, *temp2;
int i, j, pos, inf, tmp, running = 0;
if(!fp)
return 0;
fread(&s3d_header, sizeof(struct_header), 1, fp);
if(s3d_header.magicCookie[0] != 'P' || s3d_header.magicCookie[1] != 'F'
|| s3d_header.magicCookie[2] != 'S' || s3d_header.magicCookie[3] != ' ')
return 0;
this->fp = fp;
#ifdef DEBUGPFS
printf("Offset: %d\n", s3d_header.offset);
#endif
fseek(fp, s3d_header.offset, SEEK_SET);
fread(&s3d_dir_header, sizeof(struct_directory_header), 1, fp);
this->count = s3d_dir_header.count - 1;
this->filenames = new char *[s3d_dir_header.count];
this->files = new uint32[s3d_dir_header.count - 1];
offsets = new uint32[s3d_dir_header.count - 1];
for(i = 0; i < (int)s3d_dir_header.count; ++i)
{
fread(&s3d_dir, sizeof(struct_directory), 1, fp);
if(s3d_dir.crc == ntohl(0xC90A5861))
{
pos = ftell(fp);
fseek(fp, s3d_dir.offset, SEEK_SET);
temp = new char[s3d_dir.size];
memset(temp, 0, s3d_dir.size);
inf = 0;
while(inf < (int)s3d_dir.size)
{
fread(&s3d_data, sizeof(struct_data_block), 1, fp);
temp2 = new char[s3d_data.deflen];
fread(temp2, s3d_data.deflen, 1, fp);
decompress(temp2, temp + inf, s3d_data.deflen, s3d_data.inflen);
delete[] temp2;
inf += s3d_data.inflen;
}
fseek(fp, pos, SEEK_SET);
s3d_fn_header = (struct_fn_header *) temp;
pos = sizeof(struct_fn_header);
for(j = 0; j < (int)s3d_fn_header->fncount; ++j)
{
s3d_fn_entry = (struct_fn_entry *) &temp[pos];
this->filenames[j] = new char[s3d_fn_entry->fnlen + 1];
this->filenames[j][s3d_fn_entry->fnlen] = 0;
memcpy(this->filenames[j], &temp[pos + sizeof(struct_fn_entry)], s3d_fn_entry->fnlen);
pos += sizeof(struct_fn_entry) + s3d_fn_entry->fnlen;
}
delete [] temp;
}
else
{
this->files[running] = ftell(fp) - 12;
offsets[running] = s3d_dir.offset;
++running;
}
}
for(i = s3d_dir_header.count - 2; i > 0; i--)
{
for(j = 0; j < i; j++)
{
if(offsets[j] > offsets[j+1])
{
tmp = offsets[j];
offsets[j] = offsets[j + 1];
offsets[j + 1] = tmp;
tmp = this->files[j];
this->files[j] = this->files[j + 1];
this->files[j + 1] = tmp;
}
}
}
delete [] offsets;
this->status = 1;
return 1;
}
int PFSLoader::Close()
{
if(this->status)
{
while(this->count > 0)
{
delete [] this->filenames[this->count - 1];
--this->count;
}
delete[] this->filenames;
delete[] this->files;
}
else
return 0;
this->buffer = nullptr;
this->buf_len = -1;
this->status = 0;
return 1;
}
const char *PFSLoader::FindExtension(const char *ext) {
int i;
int elen = strlen(ext);
for(i = 0; i < this->count; ++i) {
int flen = strlen(this->filenames[i]);
if(flen <= elen)
continue;
if(!strcmp(this->filenames[i]+(flen-elen), ext))
return(this->filenames[i]);
}
return(nullptr);
}
int PFSLoader::GetFile(char *name, uchar **buf, int *len) {
struct_directory s3d_dir;
struct_data_block s3d_data;
char *temp2;
long inf;
int i;
Lower(name);
for(i = 0; i < this->count; ++i) {
// Derision: Added basic wildcard ability as .ZON filenames don't always match the EQG name
if(!strcmp(this->filenames[i], name) ||
((name[0]=='*') && !strcmp(this->filenames[i]+strlen(filenames[i])-strlen(name)+2, name+2))) {
fseek(this->fp, this->files[i], SEEK_SET);
fread(&s3d_dir, sizeof(struct_directory), 1, this->fp);
fseek(this->fp, s3d_dir.offset, SEEK_SET);
*buf = new uchar[s3d_dir.size];
inf = 0;
while(inf < (int)s3d_dir.size) {
fread(&s3d_data, sizeof(struct_data_block), 1, this->fp);
temp2 = new char[s3d_data.deflen];
fread(temp2, s3d_data.deflen, 1, this->fp);
decompress(temp2, (char *) *buf + inf, s3d_data.deflen, s3d_data.inflen);
delete [] temp2;
inf += s3d_data.inflen;
}
*len = inf;
return 1;
}
}
return 0;
}
+21
View File
@@ -0,0 +1,21 @@
#ifndef __OPENEQ_PFS__
#define __OPENEQ_PFS__
#include <stdio.h>
#include "global.hpp"
#include "archive.hpp"
class PFSLoader : public Archive {
public:
PFSLoader();
~PFSLoader();
virtual int Open(FILE *fp);
virtual int Close();
virtual int GetFile(char *name, uchar **buf, int *len);
virtual const char *FindExtension(const char *ext);
};
#endif
+51
View File
@@ -0,0 +1,51 @@
#ifndef __EQCLIENT_S3D_H_
#define __EQCLIENT_S3D_H_
#include <stdio.h>
#include "types.h"
typedef struct struct_header {
uint32 offset;
char magicCookie[4];
uint32 unknown;
} struct_header;
typedef struct struct_directory_header {
uint32 count;
} struct_directory_header;
typedef struct struct_directory {
uint32 crc, offset, size;
} struct_directory;
typedef struct struct_data_block {
uint32 deflen, inflen;
} struct_data_block;
typedef struct struct_fn_header {
uint32 fncount;
} struct_fn_header;
typedef struct struct_fn_entry {
uint32 fnlen;
} struct_fn_entry;
typedef struct s3d_object {
FILE *fp;
long count;
char **filenames;
uint32 *files;
} s3d_object;
#ifdef __cplusplus
extern "C" {
#endif
int S3D_Init(s3d_object *obj, FILE *fp);
size_t S3D_GetFile(s3d_object *obj, char *filename, uchar **out);
#ifdef __cplusplus
}
#endif
#endif
+243
View File
@@ -0,0 +1,243 @@
// This source is from OpenEQ by Daeken et al. Modified a bit by Derision, some bug fixes etc.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "file.hpp"
#include "ter.hpp"
//#define DEBUGTER
TERLoader::TERLoader() {
this->buffer = nullptr;
this->buf_len = -1;
this->archive = nullptr;
this->status = 0;
}
TERLoader::~TERLoader() {
this->Close();
}
int TERLoader::Open(char *base_path, char *zone_name, Archive *archive) {
#ifdef DEBUGTER
printf("TERLoader::Open %s, [%s]\n", base_path, zone_name);
fflush(stdout);
#endif
ter_header *thdr;
ter_vertex *tver;
ter_vertexV3 *tverV3;
ter_triangle *ttri;
uchar *ter_orig, *ter_tmp, *StartOfNameList;
int model = 0;
unsigned int i, j, mat_count = 0;
Zone_Model *zm;
material *mlist;
uchar *buffer;
int buf_len, bone_count;
char *filename;
if(zone_name[strlen(zone_name) - 4] == '.')
filename = zone_name;
else {
filename = new char[strlen(zone_name) + 5];
sprintf(filename, "%s.ter", zone_name);
}
if(!GetFile(&buffer, &buf_len, base_path, filename, archive)) {
if(filename != zone_name)
delete[] filename;
return 0;
}
if(filename != zone_name)
delete[] filename;
thdr = (ter_header *) buffer;
mlist = new material[thdr->mat_count];
ter_orig = buffer;
if(thdr->magic[0] != 'E' || thdr->magic[1] != 'Q' || thdr->magic[2] != 'G')
return 0;
if(thdr->magic[3] == 'M') {
model = 1;
buffer += sizeof(ter_header);
bone_count = *((uint32 *) buffer);
buffer += sizeof(uint32);
}
else if(thdr->magic[3] == 'T')
buffer += sizeof(ter_header);
else
return 0;
ter_tmp = buffer + thdr->list_len;
if(sizeof(ter_header) + thdr->list_len + (thdr->vert_count * sizeof(ter_vertex)) + (thdr->tri_count * sizeof(ter_triangle)) > (unsigned int)buf_len)
return 0;
for(i = 0; i < thdr->mat_count; ++i) {
mlist[i].name = nullptr;
mlist[i].basetex = nullptr;
}
StartOfNameList = buffer;
buffer = buffer + thdr->list_len;
#ifdef DEBUGTER
printf("Offset is %X\n", buffer - ter_orig);
#endif
for(j=0; j< thdr->mat_count; j++) {
struct ter_object *tobj = (struct ter_object *)buffer;
buffer += sizeof(struct ter_object);
for (unsigned int i=0; i<(unsigned int)tobj->property_count; i++) {
struct ter_property *tprop = (struct ter_property *)buffer;
buffer += sizeof(struct ter_property);
}
}
this->model_data.zone_model = new Zone_Model;
zm = this->model_data.zone_model;
zm->vert_count = thdr->vert_count;
zm->poly_count = thdr->tri_count;
zm->verts = new Vertex *[zm->vert_count];
zm->polys = new Polygon *[zm->poly_count];
this->model_data.plac_count = 0;
this->model_data.model_count = 0;
buffer = ter_orig + thdr->list_len + sizeof(ter_header);
if(thdr->magic[3] == 'M') buffer = buffer + 4;
#ifdef DEBUGTER
printf("Starting offset is %8X\n", buffer-ter_orig);
#endif
for(unsigned int b=0; b<thdr->mat_count; b++) {
unsigned long property_count = *((unsigned long *)(buffer+12));
#ifdef DEBUGTER
printf("Property count is %d\n", property_count); fflush(stdout);
#endif
buffer += 16;
for (unsigned int a=0; a<property_count; a++)
buffer += 12;
}
#ifdef DEBUGTER
printf("Offset is %8X\n", buffer - ter_orig);
#endif
for(i = 0; i < (unsigned int)zm->vert_count; ++i) {
if(thdr->version<3) {
tver = (ter_vertex *) buffer;
zm->verts[i] = new Vertex;
zm->verts[i]->x = tver->x;
zm->verts[i]->y = tver->y;
zm->verts[i]->z = tver->z;
zm->verts[i]->u = tver->u;
zm->verts[i]->v = tver->v;
buffer += sizeof(ter_vertex);
}
else {
tverV3 = (ter_vertexV3 *) buffer;
zm->verts[i] = new Vertex;
zm->verts[i]->x = tverV3->x;
zm->verts[i]->y = tverV3->y;
zm->verts[i]->z = tverV3->z;
zm->verts[i]->u = tverV3->u;
zm->verts[i]->v = tverV3->v;
buffer += sizeof(ter_vertexV3);
}
}
j = 0;
for(i = 0; i < (unsigned int)zm->poly_count; ++i) {
ttri = (ter_triangle *) buffer;
if(ttri->group == -1) {
buffer += sizeof(ter_triangle);
continue;
}
zm->polys[j] = new Polygon;
/*
zm->polys[j]->v1 = ttri->v1;
zm->polys[j]->v2 = ttri->v2;
zm->polys[j]->v3 = ttri->v3;
*/
// Change the order of the vertices to keep the normals consistent with map files generated for S3Ds in prior versions of azone.
#ifndef KEEP_OLD_EQG_VERTEX_ORDER
zm->polys[j]->v1 = ttri->v3;
zm->polys[j]->v2 = ttri->v2;
zm->polys[j]->v3 = ttri->v1;
#else
zm->polys[j]->v1 = ttri->v1;
zm->polys[j]->v2 = ttri->v2;
zm->polys[j]->v3 = ttri->v3;
#endif
zm->polys[j]->flags = ttri->unk;
if(ttri->group == -1) {
#ifdef DEBUGTER
printf("TERLoader:: zm->poly[%d]->tex = mat_count%d\n", j, thdr->mat_count);
fflush(stdout);
#endif
zm->polys[j]->tex = thdr->mat_count;
}
else {
#ifdef DEBUGTER
printf("TERLoader:: zm->poly[%d]->tex = ttri->group %d, Unk=%d\n", j, ttri->group, ttri->unk);
fflush(stdout);
#endif
zm->polys[j]->tex = ttri->group;
}
++j;
buffer += sizeof(ter_triangle);
}
zm->poly_count = j;
zm->tex_count = 0;
delete[] mlist;
delete [] ter_orig;
this->status = 1;
return 1;
}
int TERLoader::Close() {
Zone_Model *zm = this->model_data.zone_model;
int i;
//return 1;
if(!this->status)
return 1;
for(i = 0; i < zm->vert_count; ++i)
delete zm->verts[i];
for(i = 0; i < zm->poly_count; ++i)
delete zm->polys[i];
delete[] zm->verts;
delete[] zm->polys;
delete this->model_data.zone_model;
status = 0;
return 1;
}
+62
View File
@@ -0,0 +1,62 @@
#ifndef __OPENEQ_TER__
#define __OPENEQ_TER__
#include "global.hpp"
#include "file_loader.hpp"
#pragma pack(1)
struct ter_header {
char magic[4];
unsigned long version, list_len, mat_count, vert_count, tri_count;
} typedef ter_header;
struct ter_vertex {
float x, y, z;
float i, j, k;
float u, v;
} typedef ter_vertex;
struct ter_vertexV3 {
float x, y, z;
float i, j, k;
long unk1;
float unk2, unk3;
float u, v;
} typedef ter_vertexV3;
struct ter_triangle {
long v1, v2, v3;
long group;
long unk;
} typedef ter_triangle;
struct ter_object {
long index;
long name_offset, another_name_offset;
long property_count;
} typedef ter_object;
struct ter_property {
long name_offset, type, value;
} typedef ter_property;
struct material {
char *name;
char *basetex;
char var_count;
char **var_names;
char **var_vals;
} typedef material;
#pragma pack()
class TERLoader : public FileLoader {
public:
TERLoader();
~TERLoader();
virtual int Open(char *base_path, char *zone_name, Archive *archive);
virtual int Close();
};
#endif
+16
View File
@@ -0,0 +1,16 @@
#ifndef __EQCLIENT_TYPES_H_
#define __EQCLIENT_TYPES_H_
typedef unsigned int uint32;
typedef int int32;
typedef unsigned short uint16;
typedef short int16;
typedef unsigned char uint8;
typedef unsigned char uchar;
typedef char int8;
#define null 0
#endif
+758
View File
@@ -0,0 +1,758 @@
// This source is from OpenEQ by Daeken et al. Modified a bit by Derision, some bug fixes etc.
#include "wld.hpp"
#include "file.hpp"
#include "pfs.hpp"
#include <string.h>
#include <stdlib.h>
//#define DEBUGWLD
static uchar encarr[] = {0x95, 0x3A, 0xC5, 0x2A, 0x95, 0x7A, 0x95, 0x6A};
inline void decode(uchar *str, int len) { int i; for(i = 0; i < len; ++i) str[i] ^= encarr[i % 8]; }
FRAG_CONSTRUCTOR(Data03) {
int i, count, fnlen;
Texture *tex;
count = uint32(buf);
if(!count) count = 1;
tex = new Texture;
tex->filenames = new char *[count];
tex->frame_count = count;
tex->current_frame = 0;
tex->archive = nullptr;
tex->flags = 0;
for(i = 0; i < count; ++i) {
fnlen = uint16(buf);
tex->filenames[i] = new char[fnlen];
memcpy(tex->filenames[i], buf, fnlen);
decode((uchar *) tex->filenames[i], fnlen);
//printf("fnlen is %d, %s\n", fnlen, tex->filenames[i]);
// Derision: Not sure why this check is here, but need to check fnlen is >=18
if(fnlen>=18) {
if(tex->filenames[i][fnlen - 8] == '.')
tex->filenames[i][fnlen - 17] = '\0';
}
buf += fnlen;
}
this->frag = (void *) tex;
}
FRAG_CONSTRUCTOR(Data04) {
int flags, count, i;
Texture *tex, *texref;
flags = uint32(buf);
count = uint32(buf);
if(flags & (1 << 2))
buf += 4;
if(flags & (1 << 3))
buf += 4;
if(count == 0 || count == 1)
this->frag = wld->frags[uint32(buf) - 1]->frag;
else {
tex = new Texture;
tex->frame_count = count;
tex->current_frame = 0;
tex->archive = nullptr;
tex->filenames = new char *[count];
tex->flags = 0;
for(i = 0; i < count; ++i) {
texref = (Texture *) wld->frags[uint32(buf) - 1]->frag;
tex->filenames[i] = texref->filenames[texref->frame_count - 1];
}
this->frag = tex;
}
}
FRAG_CONSTRUCTOR(Data05) {
this->frag = wld->frags[uint32(buf) - 1]->frag;
}
FRAG_CONSTRUCTOR(Data15) {
struct_Data15 *hdr = (struct_Data15 *) buf;
Placeable *plac = new Placeable;
Placeable **pl;
plac->x = hdr->trans[0];
plac->y = hdr->trans[1];
plac->z = hdr->trans[2];
plac->rx = hdr->rot[2] / 512.f * 360.f;
plac->ry = hdr->rot[1] / 512.f * 360.f;
plac->rz = hdr->rot[0] / 512.f * 360.f;
plac->scale[0] = hdr->scale[2];
plac->scale[1] = hdr->scale[1];
plac->scale[2] = hdr->scale[1];
plac->model = atoi((const char*)&wld->sHash[-(int)hdr->ref]);
pl = new Placeable *[wld->model_data.plac_count + 1];
memcpy(pl, wld->model_data.placeable, sizeof(Placeable *) * wld->model_data.plac_count);
if(wld->model_data.plac_count)
delete[] wld->model_data.placeable;
pl[wld->model_data.plac_count] = plac;
wld->model_data.placeable = pl;
++wld->model_data.plac_count;
}
FRAG_CONSTRUCTOR(Data1B) {
struct_Data1B *data = (struct_Data1B *) buf;
Light *light = new Light;
this->frag = light;
light->x = light->y = light->z = light->rad = 0;
if(data->flags & (1 << 3)) {
light->r = data->color[0];
light->g = data->color[1];
light->b = data->color[2];
}
else
light->r = light->g = light->b = 1.0f;
}
FRAG_CONSTRUCTOR(Data1C) {
this->frag = wld->frags[uint32(buf) - 1]->frag;
}
FRAG_CONSTRUCTOR(Data21) {
struct_Data21 *data;
long count = *((long *) buf);
long i;
wld->tree = (BSP_Node *) malloc(count * sizeof(BSP_Node));
// Build the BSP Tree
//
for(i = 0; i < count; ++i) {
wld->tree[i].node_number=i;
data = (struct_Data21 *) (buf + (i * sizeof(struct_Data21)) + 4);
wld->tree[i].normal[0] = data->normal[0];
wld->tree[i].normal[1] = data->normal[1];
wld->tree[i].normal[2] = data->normal[2];
wld->tree[i].splitdistance = data->splitdistance;
wld->tree[i].region = data->region;
wld->tree[i].left = data->node[0];
wld->tree[i].right = data->node[1];
}
}
FRAG_CONSTRUCTOR(Data22) {
int pos;
uchar *data6area ;
struct_Data22 *data = (struct_Data22 *) buf;
pos = sizeof(struct_Data22) + (12 * data->size1) + (8 * data->size2);
data6area = buf + pos;
if((data->size3!=0)||(data->size4!=0)) {
printf("Size 3 and 4 not zero, we can't handle that yet\n");
exit(1);
}
data6area = data6area + ((data->size5) * 7 * 4);
unsigned short d6size = *((unsigned short *) data6area);
data6area = data6area + 2; // Move past d6 size
data6area = data6area + d6size; // Move past RLE data ? Hopefully;
float f1, f2, f3, f4;
f1 = *((float *) data6area);
f2 = *((float *) (data6area+4));
f3 = *((float *) (data6area+8));
f4 = *((float *) (data6area+12));
long Frag36Ref;
if(data->flags==0x181) {
Frag36Ref = *((long *) (data6area+20));
//printf("Frag 36 reference?: %ld\n", *((long *) (data6area+20)));
}
}
FRAG_CONSTRUCTOR(Data29) {
long a,flags, numregions, lenstr;
struct_Data29 *data29 = (struct_Data29 *) malloc(sizeof(struct_Data29));
data29->region_type = -1; // Start of by flagging type as unknown
if(!strncmp((char *) &wld->sHash[-frag_name], "WT", 2)) data29->region_type = 1; // Water
else if(!strncmp((char *) &wld->sHash[-frag_name], "LA", 2)) data29->region_type = 2; // Lava
else if(!strncmp((char *) &wld->sHash[-frag_name], "DRNTP", 5)) data29->region_type = 3; // Zone Line
else if(!strncmp((char *) &wld->sHash[-frag_name], "DRP_", 4)) data29->region_type = 4; // PVP
else if(!strncmp((char *) &wld->sHash[-frag_name], "SL", 2)) data29->region_type = 5; // Slippery/Slime ?
else if(!strncmp((char *) &wld->sHash[-frag_name], "DRN", 3)) data29->region_type = 6; // Ice/Ice Water
else if(!strncmp((char *) &wld->sHash[-frag_name], "VWA", 3)) data29->region_type = 7; // VWater ?
this->frag = (void *) data29;
flags = *buf;
numregions = *((long *)(buf+4));
data29->region_count = numregions ;
data29->region_array = (long *)malloc(numregions * sizeof(long));
for(a=0;a<numregions;a++) {
data29->region_array[a] = *((long *)(buf+8+(a*4)));
}
lenstr = *((long *)(buf+8+(numregions*4)));
data29->strlen=lenstr;
if(lenstr==0) return;
data29->str = (char *)malloc(lenstr);
char *encstr;
encstr = (char *)buf+8+(++a*4);
decode((uchar *)encstr, lenstr);
strcpy(data29->str, encstr);
// printf(" data2 name is %s\n", data29->str);
if(lenstr>=5)
if(!strncmp(encstr,"WT",2)) data29->region_type = 1; // Water
else if(!strncmp(encstr,"LA",2)) data29->region_type = 2; // Lava
else if(!strncmp(encstr,"DRNTP",5)) data29->region_type = 3; // Zone Line ?
else if(!strncmp(encstr,"DRP_",4)) data29->region_type = 4; //PVP
else if(!strncmp(encstr,"SL",2)) data29->region_type = 5; // Slippery/Slime ?
else if(!strncmp(encstr,"DRN",3)) data29->region_type = 6; // Ice/Ice Water ?
else if(!strncmp(encstr,"VWN",3)) data29->region_type = 7; // Ice/Ice Water ?
else data29->region_type = -2; // Flag this so that it doesn't get set to the default water or lava
// later, because it is neither.
//
}
FRAG_CONSTRUCTOR(Data28) {
// struct_Data28 *data = (struct_Data28 *) buf; // obviously unused for now.
}
FRAG_CONSTRUCTOR(Data30) {
struct_Data30 *data;
uint32 ref;
Texture *tex;
data = (struct_Data30 *) buf;
buf += sizeof(struct_Data30);
if(!data->flags)
buf += 8;
ref = uint32(buf);
if(!data->params1 || !ref) {
tex = new Texture;
tex->frame_count = 1;
tex->current_frame = 0;
tex->filenames = new char *[1];
tex->filenames[0] = "collide.dds";
tex->archive = nullptr;
tex->flags = 1;
this->frag = (void *) tex;
return;
}
tex = (Texture *) wld->frags[ref - 1]->frag;
if(data->params1 & (1 << 1) || data->params1 & (1 << 2) || data->params1 & (1 << 3) || data->params1 & (1 << 4))
tex->flags = 1;
else
tex->flags = 0;
this->frag = (void *) tex;
}
FRAG_CONSTRUCTOR(Data31) {
TexRef *tr;
int i, count;
buf += 4;
count = uint32(buf);
tr = new TexRef;
tr->tex_count = count;
tr->tex = new Texture *[count];
for(i = 0; i < count; ++i)
tr->tex[i] = (Texture *) wld->frags[uint32(buf) - 1]->frag;
this->frag = (void *) tr;
}
FRAG_CONSTRUCTOR(Data36) {
struct_Data36 *header = (struct_Data36 *) buf;
Poly *p;
TexCoordsNew *tex_new;
TexCoordsOld *tex_old;
VertexNormal *vn;
Vert *v;
TexRef *tr;
Model *model;
Vertex *vert;
Polygon *poly;
float scale = 1.0f / (float) (1 << header->scale);
int i, j, pc;
TexMap *tm;
float recip_255 = 1.0f / 256.0f, recip_127 = 1.0f / 127.0f;
buf += sizeof(struct_Data36);
model = new Model;
model->vert_count = header->vertexCount;
model->poly_count = header->PolygonsCount;
model->verts = new Vertex *[model->vert_count];
model->polys = new Polygon *[model->poly_count];
tr = (TexRef *) wld->frags[header->fragment1 - 1]->frag;
model->tex = tr->tex; // Reference to type 0x31 Texture List fragment
model->tex_count = tr->tex_count;
model->name = (char *) &wld->sHash[-frag_name];
#ifdef DEBUGWLD
printf("Frag 0x36, %4d Vertices, %4d Polys, %4d TexCoords, %4d Normals, %3d Colors, %3d Polytex, %3d VertexTex, Name %s\n",
header->vertexCount, header->PolygonsCount, header->texCoordsCount, header->normalsCount, header->colorCount, header->PolygonTexCount, header->vertexTexCount, model->name);
#endif
for(i = 0; i < header->vertexCount; ++i) {
v = (Vert *) buf;
vert = model->verts[i] = new Vertex;
vert->x = header->centerX + v->x * scale;
vert->y = header->centerY + v->y * scale;
vert->z = header->centerZ + v->z * scale;
#ifdef DEBUGWLD2
printf(" Vertex %4d: X=%4.2f, Y=%4.2f, Z=%4.2f\n", i, vert->x, vert->y, vert->z);
#endif
buf += sizeof(Vert);
}
if(wld->old) {
for(i = 0; i < header->texCoordsCount; ++i) {
tex_old = (TexCoordsOld *) buf;
vert = model->verts[i];
vert->u = (float) tex_old->tx * recip_255;
vert->v = (float) tex_old->tz * recip_255;
#ifdef DEBUGWLD2
printf(" TexCoord %4d: U=%4.2f, V=%4.2f\n", i, vert->u, vert->v);
#endif
buf += sizeof(TexCoordsOld);
}
}
else {
for(i = 0; i < header->texCoordsCount; ++i) {
tex_new = (TexCoordsNew *) buf;
vert = model->verts[i];
vert->u = tex_new->tx;
vert->v = tex_new->tz;
#ifdef DEBUGWLD2
printf(" TexCoord %4d: U=%4.2f, V=%4.2f\n", i, vert->u, vert->v);
#endif
buf += sizeof(TexCoordsNew);
}
}
for(i = 0; i < header->normalsCount; ++i) {
if(i<header->vertexCount) {
vn = (VertexNormal *) buf;
vert = model->verts[i];
vert->i = (float) vn->nx * recip_127;
vert->j = (float) vn->ny * recip_127;
vert->k = (float) vn->nz * recip_127;
}
buf += sizeof(VertexNormal);
}
buf += 4 * header->colorCount;
for(i = 0; i < header->PolygonsCount; ++i) {
p = (Poly *) buf;
poly = model->polys[i] = new Polygon;
poly->flags = p->flags;
// Derision: 16/06/08
// Previously, this was assigning v1=v1, v2=v3, v3=v2. This is different to how it was done
// in the WLD loader in the stock azone, and has the effect of screwing up the normals,
// Changed to keep things consistent with prior versions.
poly->v1 = p->v1;
poly->v2 = p->v2;
poly->v3 = p->v3;
#ifdef DEBUGWLD2
printf("Frag36: Polygon: %5d Vertices: %5d, %5d, %5d\n", i, poly->v1, poly->v2, poly->v3);
#endif
buf += sizeof(Poly);
}
buf += 4 * header->size6;
pc = 0;
// For each polygontex entry ...
for(i = 0; i < header->PolygonTexCount; ++i) {
tm = (TexMap *) buf;
for(j = 0; j < tm->polycount; ++j) {
if(pc>=(model->poly_count)) {
break; // Derision: Crashing here in acrylia because of this. TODO: Find root cause, for now, this lets zone load
}
// there are tm->polycount consecutive polys that use this tex
model->polys[pc++]->tex = tm->tex;
}
buf += 4;
}
#ifdef DEBUGWLD
fflush(stdout);
#endif
this->frag = (void *) model;
}
WLDLoader::WLDLoader() {
}
WLDLoader::~WLDLoader() {
this->Close();
}
int WLDLoader::Open(char *base_path, char *zone_name, Archive *archive) {
uchar *buffer;
int buf_len;
int i, j, vc, pc, bc, mlen, *pmap;
Zone_Model *zm;
Model *m;
Archive *obj_archive;
char *filename, *model_name;
struct_wld_header *header;
struct_wld_basic_frag *frag;
#ifdef DEBUGWLD
printf("Zone: %s\n", zone_name);
#endif
this->model_data.zone_model = nullptr;
this->model_data.plac_count = 0;
this->model_data.placeable = 0;
this->obj_loader = this->plac_loader = nullptr;
this->clear_plac = 0;
filename = new char[strlen(zone_name) + 5];
sprintf(filename, "%s.wld", zone_name);
if(!GetFile(&buffer, &buf_len, nullptr, filename, archive)) {
delete[] filename;
return 0;
}
delete[] filename;
header = (struct_wld_header *) buffer;
if(header->magic != 0x54503d02)
return 0;
buffer += sizeof(struct_wld_header);
this->sHash = buffer;
decode(this->sHash, header->stringHashSize);
buffer += header->stringHashSize;
if(header->version == 0x00015500)
this->old = 1;
else
this->old = 0;
this->fragcount = header->fragmentCount;
this->frags = new Fragment *[header->fragmentCount];
for(i = 0; i < this->fragcount; ++i) {
frag = (struct_wld_basic_frag *) buffer;
buffer += sizeof(struct_wld_basic_frag);
switch(frag->id) {
case 0x03: FRAGMENT(Data03); break;
case 0x04: FRAGMENT(Data04); break;
case 0x05: FRAGMENT(Data05); break;
case 0x15: FRAGMENT(Data15); break;
case 0x1B: FRAGMENT(Data1B); break;
case 0x1C: FRAGMENT(Data1C); break;
case 0x21: FRAGMENT(Data21); break;
case 0x22: FRAGMENT(Data22); break;
case 0x29: FRAGMENT(Data29); break;
case 0x28: FRAGMENT(Data28); break;
case 0x30: FRAGMENT(Data30); break;
case 0x31: FRAGMENT(Data31); break;
case 0x36: FRAGMENT(Data36); break;
default: this->frags[i] = new Fragment; break;
}
this->frags[i]->type = frag->id;
this->frags[i]->name = frag->nameRef;
buffer += frag->size - 4;
}
if(!strcmp(&zone_name[strlen(zone_name) - 4], "_obj")) {
this->model_data.plac_count = 0;
this->model_data.model_count = 0;
// for an obj_s3d file, find out how many placeabale objects there are (each 0x36 Frag is a placeable object in an obj_s3d file
for(i = 0; i < this->fragcount; ++i) {
if(this->frags[i]->type == 0x36)
++this->model_data.model_count;
}
// allocate space for this many models
this->model_data.models = new Model *[this->model_data.model_count];
this->model_data.model_count = 0;
for(i = 0; i < this->fragcount; ++i) {
if(this->frags[i]->type == 0x36)
this->model_data.models[this->model_data.model_count++] = (Model *) this->frags[i]->frag;
}
}
else if(!strcmp(&zone_name[strlen(zone_name) - 4], "_chr")) {
}
else if(!strcmp(zone_name, "objects")) {
this->clear_plac = 1;
}
else {
// We are procesing the zone mesh S3D
zm = this->model_data.zone_model = new Zone_Model;
zm->vert_count = 0;
zm->poly_count = 0;
for(i = 0; i < this->fragcount; ++i) {
if(this->frags[i]->type != 0x36)
continue;
m = (Model *) this->frags[i]->frag;
zm->vert_count += m->vert_count;
zm->poly_count += m->poly_count;
zm->tex_count = m->tex_count; // The texcount and tex fields are the same for every 0x36 frag in the zone mesh S3D
zm->tex = m->tex;
}
zm->verts = new Vertex *[zm->vert_count];
zm->polys = new Polygon *[zm->poly_count];
vc = pc = 0;
for(i = 0; i < this->fragcount; ++i) {
if(this->frags[i]->type != 0x36)
continue;
m = (Model *) this->frags[i]->frag;
bc = vc;
// Copy the vertexes from the 0x36 frag into our zone model
for(j = 0; j < m->vert_count; ++j)
zm->verts[vc++] = m->verts[j];
// Adjust the polygon vertices indices to match the indices in our zone model vertex array
for(j = 0; j < m->poly_count; ++j) {
m->polys[j]->v1 += bc;
m->polys[j]->v2 += bc;
m->polys[j]->v3 += bc;
#ifdef DEBUGWLD
printf("Polygon: %5d Vertices %5d, %5d, %5d\n", j,
m->polys[j]->v1, m->polys[j]->v2, m->polys[j]->v3);
#endif
#ifdef DEBUGWLD
printf("Zone Frag36 No. %5d: Poly %5d V3 = %4.3f, %4.3f, %4.3f\n", i, j, zm->verts[m->polys[j]->v3]->x, zm->verts[m->polys[j]->v3]->y, zm->verts[m->polys[j]->v3]->z);
fflush(stdout);
#endif
zm->polys[pc++] = m->polys[j];
}
}
this->model_data.plac_count = 0;
this->model_data.model_count = 0;
filename = new char[strlen(zone_name) + 10];
sprintf(filename, "%s_obj.s3d",zone_name);
obj_archive = new PFSLoader;
if(!obj_archive->Open(fopen(filename, "rb"))) {
// printf("_obj.s3d file not found.\n");
return 1;
}
delete[] filename;
filename = new char[strlen(zone_name) + 5];
sprintf(filename, "%s_obj", zone_name);
this->obj_loader = new WLDLoader();
this->obj_loader->Open(nullptr, filename, obj_archive);
delete[] filename;
this->model_data.model_count = this->obj_loader->model_data.model_count;
this->model_data.models = this->obj_loader->model_data.models;
this->plac_loader = new WLDLoader();
this->plac_loader->Open(nullptr, "objects", archive);
if(this->model_data.plac_count) {
delete this->model_data.placeable[0];
delete[] this->model_data.placeable;
}
this->model_data.plac_count = this->plac_loader->model_data.plac_count;
this->model_data.placeable = this->plac_loader->model_data.placeable;
for(i = 0; i < this->model_data.plac_count; ++i) {
mlen = strlen((char *) this->model_data.placeable[i]->model) - 8;
model_name = new char[mlen + 12];
memcpy(model_name, (char *) this->model_data.placeable[i]->model, mlen);
model_name[mlen] = 0;
sprintf(model_name, "%sDMSPRITEDEF", model_name);
this->model_data.placeable[i]->model = -1;
for(j = 0; j < this->model_data.model_count; ++j) {
if(!strcmp(this->model_data.models[j]->name, model_name)) {
this->model_data.placeable[i]->model = j;
// printf("Placeable object %d name is %s\n", j, model_name);
break;
}
}
delete[] model_name;
}
for(i = 0; i < this->model_data.model_count; ++i) {
for(j = 0; j < this->model_data.models[i]->tex_count; ++j)
this->model_data.models[i]->tex[j]->archive = obj_archive;
}
for(i = 0; i < this->model_data.model_count; ++i) {
pmap = new int[this->model_data.models[i]->poly_count];
memset(pmap, 0, sizeof(int) * this->model_data.models[i]->poly_count);
for(j = 0; j < this->model_data.models[i]->tex_count; ++j) {
filename = this->model_data.models[i]->tex[j]->filenames[0];
for(bc = 0; bc < this->model_data.zone_model->tex_count; ++bc) {
if(!strcmp(filename, this->model_data.zone_model->tex[bc]->filenames[0])) {
for(pc = 0; pc < this->model_data.models[i]->poly_count; ++pc) {
if(!pmap[pc] && this->model_data.models[i]->polys[pc]->tex == j) {
this->model_data.models[i]->polys[pc]->tex = bc;
pmap[pc] = 1;
}
}
break;
}
}
}
delete[] pmap;
}
}
return 1;
}
int WLDLoader::Close() {
int i, j;
Zone_Model *zm = this->model_data.zone_model;
Model *m;
return -1;
if(zm) {
for(j = 0; j < zm->tex_count; ++j)
delete zm->tex[j];
delete[] zm->tex;
delete[] zm->verts;
delete[] zm->polys;
}
for(i = 0; i < this->fragcount; ++i) {
if(this->frags[i]->type == 0x36) {
m = (Model *) this->frags[i]->frag;
for(j = 0; j < m->vert_count; ++j)
delete m->verts[j];
for(j = 0; j < m->poly_count; ++j)
delete m->polys[j];
if(!zm) {
for(j = 0; j < m->tex_count; ++j)
delete m->tex[j];
delete[] m->tex;
}
delete[] m->verts;
delete[] m->polys;
delete m;
}
else
delete this->frags[i];
}
delete[] this->frags;
if(this->clear_plac) {
// for(i = 0; i < this->model_data.plac_count; ++i)
// delete[] this->model_data.placeable[i];
}
delete[] this->model_data.placeable;
delete this->obj_loader;
delete this->plac_loader;
return 1;
}
+84
View File
@@ -0,0 +1,84 @@
#ifndef __OPENEQ_WLD__
#define __OPENEQ_WLD__
#include <stdio.h>
#include "global.hpp"
#include "file_loader.hpp"
#include "wld_structs.hpp"
#include "3d.hpp"
#define FRAGMENT(name) \
this->frags[i] = new name(this, buffer, frag->size, frag->nameRef);
class TexRef {
public:
Texture **tex;
int tex_count;
};
class Fragment {
public:
Fragment() {}
virtual ~Fragment() {}
int type, name;
void *frag;
};
class WLDLoader : public FileLoader {
public:
WLDLoader();
~WLDLoader();
virtual int Open(char *base_path, char *zone_name, Archive *archive);
virtual int Close();
int fragcount;
Fragment **frags;
BSP_Node *tree;
uchar *sHash;
char old;
WLDLoader *obj_loader;
WLDLoader *plac_loader;
char clear_plac;
};
#define FRAG_CLASS(name) \
class name : public Fragment { \
public: \
name(WLDLoader *wld, uchar *buf, int len, int frag_name); \
~name() {}; \
}
#define FRAG_CONSTRUCTOR(name) \
name::name(WLDLoader *wld, uchar *buf, int len, int frag_name)
#define FRAG_DECONSTRUCTOR(name) \
name::~name()
FRAG_CLASS(Data03);
FRAG_CLASS(Data04);
FRAG_CLASS(Data05);
FRAG_CLASS(Data15);
FRAG_CLASS(Data1B);
FRAG_CLASS(Data1C);
FRAG_CLASS(Data21);
FRAG_CLASS(Data22);
FRAG_CLASS(Data29);
FRAG_CLASS(Data28);
FRAG_CLASS(Data30);
FRAG_CLASS(Data31);
FRAG_CLASS(Data36);
void DoubleLinkBSP(BSP_Node *tree, long node_number, long parent);
long BSPMarkRegion(BSP_Node *tree, long node_number, long region, int region_type);
#endif
+137
View File
@@ -0,0 +1,137 @@
#ifndef __OPENEQ_WLD_STRUCTS__
#define __OPENEQ_WLD_STRUCTS__
#pragma pack(1)
struct struct_wld_header {
long magic;
long version;
long fragmentCount;
long header3;
long header4;
long stringHashSize;
long header6;
} typedef struct_wld_header;
struct struct_wld_basic_frag {
long size;
long id;
long nameRef;
} typedef struct_wld_basic_frag;
struct struct_Data15 {
uint32 ref, flags, fragment1;
float trans[3], rot[3];
float scale[3];
uint32 fragment2, flags2;
} typedef struct_Data15;
struct struct_Data36 {
long flags;
long fragment1;
long fragment2;
long fragment3;
long fragment4;
float centerX;
float centerY;
float centerZ;
long params2[3]; // 48
float maxDist;
float minX;
float minY;
float minZ;
float maxX;
float maxY;
float maxZ; // 24
short int vertexCount;
short int texCoordsCount;
short int normalsCount;
short int colorCount;
short int PolygonsCount;
short int size6;
short int PolygonTexCount;
short int vertexTexCount;
short int size9;
short int scale; // 20
} typedef struct_Data36;
struct struct_Data10 {
long flags, size1, fragment;
} typedef struct_Data10;
struct struct_Data1B {
uint32 flags, params1;
uint32 params3b;
float color[3];
} typedef struct_Data1B;
struct struct_Data21 {
float normal[3], splitdistance;
long region, node[2];
} typedef struct_Data21;
struct struct_Data22 {
long flags, fragment1, size1, size2, params1, size3, size4, params2, size5, size6;
} typedef struct_Data22;
struct struct_Data28 {
uint32 flags;
float x, y, z, rad;
} typedef struct_Data28;
typedef struct struct_Data29 {
long region_count;
long *region_array;
long strlen;
char *str;
int region_type; // We fill this in with -1 for unknown, 1 for water, 2 for lava
} struct_Data29;
struct struct_Data30 {
uint32 flags, params1, params2;
float params3[2];
} typedef struct_Data30;
typedef struct BSP_Node {
long node_number;
float normal[3], splitdistance;
long region;
int special;
long left, right;
} BSP_Node;
struct Vert {
signed short int x, y, z;
} typedef Vert;
struct TexCoordsNew {
float tx, tz;
} typedef TexCoordsNew;
struct TexCoordsOld {
signed short int tx, tz;
} typedef TexCoordsOld;
struct VertexNormal {
signed char nx, ny, nz;
} typedef VertexNormal;
struct VertexColor {
char color[4];
} typedef VertexColor;
struct Poly {
short int flags, v1, v2, v3;
} typedef Poly;
struct TexMap {
uint16 polycount;
uint16 tex;
} typedef TexMap;
#pragma pack()
#endif
+433
View File
@@ -0,0 +1,433 @@
// This source is from OpenEQ by Daeken et al. Modified a bit by Derision, some bug fixes etc.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include "3d.hpp"
#include "zon.hpp"
//#define DEBUGEQG
//#define DEBUGPLAC
ZonLoader::ZonLoader() {
this->buffer = nullptr;
this->buf_len = -1;
this->archive = nullptr;
this->status = 0;
}
ZonLoader::~ZonLoader() {
this->Close();
}
int ZonLoader::Open(char *base_path, char *zone_name, Archive *archive) {
uchar *buffer, *orig_buffer;
int buf_len;
Texture **tex;
int tex_count, tex_tmp, *tex_map;
int i, j, k, l;
char **model_names;
char *filename;
uchar *zon_tmp, *zon_orig;
float rot_change = 180.0f / 3.14159f;
// float rot_change = 1.0f;
float base[3];
#ifdef DEBUGEQG
printf("Attempting to load EQG %s\n", zone_name);
#endif
filename = new char[strlen(zone_name) + 5];
//sprintf(filename, "%s.zon", zone_name);
// Derision: .zon name is not always the same as the EQG base name. Added wildcard ability to the PFS GetFile
// routine.
sprintf(filename, "*.zon");
#ifdef DEBUGEQG
printf("Looking for ZON file %s\n", filename);
archive->GetFile("*.zon", &buffer, &buf_len);
#endif
if(!archive->GetFile(filename, &buffer, &buf_len)) {
#ifdef DEBUGEQG
printf("Couldn't find ZON file\n");
printf("%s\n", zone_name);
#endif
// Look in the filesystem for the .ZON file.
char *FSZonName = new char[strlen(zone_name) + 6];
sprintf(FSZonName, "%s.zon", zone_name);
// Hack incoming for westkorlach zones because the zon filename for e.g. westkorlacha is westkorlachA
if(!strncmp(FSZonName, "westkorlach", 11))
FSZonName[11] = toupper(FSZonName[11]);
printf(".ZON file not found inside EQG. Looking for %s in filesystem. ", FSZonName);
FILE *FSZon = fopen(FSZonName, "rb");
delete [] FSZonName;
if(FSZon) {
printf("Found.\n");
fseek(FSZon, 0, SEEK_END);
long FSZonSize = ftell(FSZon);
fseek(FSZon, 0, SEEK_SET);
// printf("File size is %d\n", FSZonSize);
buffer = new uchar[FSZonSize];
fread(buffer, FSZonSize, 1, FSZon);
// printf("Read file\n");
}
else {
printf("\n.ZON file not present inside EQG file. Did not find it in the filesystem either.\n");
return 0;
}
}
delete[] filename;
orig_buffer = buffer;
zon_header *hdr = (zon_header *) buffer;
zon_placeable *plac;
if(hdr->magic[0] != 'E' || hdr->magic[1] != 'Q' || hdr->magic[2] != 'G' || hdr->magic[3] != 'Z')
return 0;
buffer += sizeof(zon_header);
// The original OpenEQ code I found assumed the first filename was the .TER file. This
// is not always the case.
//
#ifdef DEBUGEQG
printf("Seeking .TER file\n");
#endif
uchar *StartOfModelNames = buffer;
while(strcmp((char *)(buffer+strlen((char *)buffer))-3, "TER"))
buffer += strlen((char *)buffer) + 1;
#ifdef DEBUGEQG
printf("Found .TER file %s\n", (char *)buffer);
#endif
this->terloader.Open(nullptr, (char *) buffer, archive);
buffer = StartOfModelNames;
this->model_data.zone_model = terloader.model_data.zone_model;
// Derision:
// After the ZON header, there is a list of strings like this (using guildhall.EQG as an example)
// TER_GuildHall.TER
// TER_GuildHall
// OBJ_sun_frame.MOD
// OBJ_sun_frame
// OBJ_chandelier.MOD
// OBJ_chandelier
// OBJ_key_door_open_.MOD
// OBJ_key_door_open_01
// OBJ_key_door_open_02
// OBJ_key_door_.MOD
// OBJ_key_door_01
// OBJ_key_door_02
// OBJ_key_door_03
//
// This format appears to be Mesh (model) filename, followed by a list of objects that use that model.
// So we have the zone model (ground mesh), i.e. the .TER file, which is used by object 'TER_Guildhall',
// then a list of placeable models. It would appear that one .MOD file can be used by multiple objects,
// i.e. the key_door_open and key_door models in the example above.
//
// After this list, there is a list of hdr->NumberOfModels longs, one for each Model. Each long is an offset into
// the list above, pointing to the .MOD file for that model.
zon_orig = buffer;
zon_tmp = buffer + hdr->list_len;
// Create an array of Model filenames and populate it using the offsets
//
buffer = zon_orig + hdr->list_len;
model_names = new char *[hdr->NumberOfModels];
for(int ModelNumber=0; ModelNumber< hdr->NumberOfModels; ModelNumber++) {
long offset = *((long *)(buffer+ModelNumber*4));
model_names[ModelNumber] = (char *)(zon_orig + offset);
//
// Derision: 23/06/08
// dranikcatacombsa.eqg has a couple of model names with a left parenthesis where there should
// be an underscore. E.g. OBP_DZ_Lbanner0)_00.MOD instead of OBP_DZ_Lbanner0__00.MOD
// This is the only zone I have seen this in, but is the reason for the follow code to replace
// the parenthesis with an underscore.
//
for(unsigned int i=0; i<strlen(model_names[ModelNumber]); i++)
if(model_names[ModelNumber][i] == ')') {
model_names[ModelNumber][i] = '_';
printf("***** Replacing parenthesis with underscore in model name %s\n", model_names[ModelNumber]);
}
// printf("Model name %d is %s\n", ModelNumber, model_names[ModelNumber]);
}
this->model_data.model_count = hdr->NumberOfModels;
#if defined(DEBUGEQG) || defined(DEBUGPLAC)
printf("model_data.model_count is %d\n", this->model_data.model_count);
fflush(stdout);
#endif
this->model_data.models = new Model *[this->model_data.model_count];
// Skip over the
buffer = zon_orig + hdr->list_len + hdr->NumberOfModels * 4;
this->model_data.plac_count = hdr->obj_count - 1;
/*
if(hdr->version > 1) {
// Don't understand the complete format of version 2 zons
this->model_data.plac_count = 0;
}
*/
#ifdef DEBUGPLAC
printf(" Placeable count is %d\n", this->model_data.plac_count);
#endif
this->model_data.placeable = new Placeable *[this->model_data.plac_count];
plac = (zon_placeable *) buffer;
base[0] = plac->x;
base[1] = plac->y;
base[2] = plac->z;
// printf("(%f %f %f) (%f %f %f)\n", plac->x, plac->y, plac->z, plac->rz, plac->ry, plac->rx);
buffer += sizeof(zon_placeable);
if(hdr->version > 1) {
long UnknownSize = *((long *)(buffer));
// printf("Unknown Size is %d\n", UnknownSize);
buffer = buffer + 4 + (UnknownSize * 4);
}
#ifdef DEBUGEQG
printf("TER.CPP:107 model_data.plac_count is %d\n", this->model_data.plac_count);
#endif
for(i = 0; i < this->model_data.plac_count; ++i) {
plac = (zon_placeable *) buffer;
zon_tmp = zon_orig + plac->loc;
this->model_data.placeable[i] = new Placeable;
this->model_data.placeable[i]->model = plac->id ;
this->model_data.placeable[i]->x = plac->x;
this->model_data.placeable[i]->y = plac->y;
this->model_data.placeable[i]->z = plac->z;
this->model_data.placeable[i]->rx = plac->rz * rot_change;
this->model_data.placeable[i]->ry = plac->ry * rot_change;
this->model_data.placeable[i]->rz = plac->rx * rot_change;
this->model_data.placeable[i]->scale[0] = plac->scale;
this->model_data.placeable[i]->scale[1] = plac->scale;
this->model_data.placeable[i]->scale[2] = plac->scale;
#ifdef DEBUG_MODE
printf("%s (%f %f %f) (%f %f %f) %f\n",
zon_tmp,
this->model_data.placeable[i]->x,
this->model_data.placeable[i]->y,
this->model_data.placeable[i]->z,
this->model_data.placeable[i]->rx,
this->model_data.placeable[i]->ry,
this->model_data.placeable[i]->rz,
this->model_data.placeable[i]->scale);
#endif
if(this->model_data.placeable[i]->model == -1) {
printf("Unable to find model for offset %5ld\n", plac->loc);
}
#ifdef DEBUGPLAC
printf(" Placeable object %i Model no. %d at (%4.2f, %4.2f, %4.2f)\n", i, this->model_data.placeable[i]->model, plac->x,plac->y, plac->z);
#endif
buffer += sizeof(zon_placeable);
if(hdr->version > 1) {
long UnknownSize = *((long *)(buffer));
buffer = buffer + 4 + (UnknownSize * 4);
}
}
model_loaders = new TERLoader[this->model_data.model_count];
tex_count = this->model_data.zone_model->tex_count;
#ifdef DEBUGEQG
printf("zon.cpp line 154 zm tex count is %d\n", this->model_data.zone_model->tex_count);
#endif
for(j = 0; j < this->model_data.model_count; ++j) {
// We have already loaded the zone mesh, so skip the .TER file when processing models.
//
if(!(strcmp(model_names[j]+strlen(model_names[j])-3, "ter"))) {
// printf("Skipping .TER file at model number %d\n", j);
this->model_data.models[j] = nullptr;
continue;
}
// printf("Attempting to open MOD file %s\n", model_names[j]); fflush(stdout);
if(model_loaders[j].Open(nullptr, model_names[j], archive)) {
this->model_data.models[j] = new Model;
this->model_data.models[j]->vert_count = model_loaders[j].model_data.zone_model->vert_count;
this->model_data.models[j]->poly_count = model_loaders[j].model_data.zone_model->poly_count;
this->model_data.models[j]->tex_count = model_loaders[j].model_data.zone_model->tex_count;
this->model_data.models[j]->verts = model_loaders[j].model_data.zone_model->verts;
this->model_data.models[j]->polys = model_loaders[j].model_data.zone_model->polys;
this->model_data.models[j]->tex = model_loaders[j].model_data.zone_model->tex;
this->model_data.models[j]->name = new char[strlen(model_names[j])+1];
strcpy(this->model_data.models[j]->name, model_names[j]);
tex_tmp = 1;
// I think this is looking to see if the placeable model textures already exist in the zone model.
//
for(i = 0; i < this->model_data.models[j]->tex_count; ++i) {
tex_tmp = 1; // Derision
for(k = 0; k < this->model_data.zone_model->tex_count; ++k) {
// printf(" Checking zm tex filename %s againt model filename %s\n", this->model_data.zone_model->tex[k]->filenames[0],
// this->model_data.models[j]->tex[i]->filenames[0]);
if((!this->model_data.zone_model->tex[k]->filenames[0] && !this->model_data.models[j]->tex[i]->filenames[0]) ||
(this->model_data.zone_model->tex[k]->filenames[0] &&
this->model_data.models[j]->tex[i]->filenames[0] &&
!strcmp(this->model_data.zone_model->tex[k]->filenames[0], this->model_data.models[j]->tex[i]->filenames[0]))) {
tex_tmp = 0;
break;
}
}
if(tex_tmp)
++tex_count;
else {
for(k = 0; k < j; ++k) {
if(!this->model_data.models[k]) {
#ifdef DEBUGEQG
printf("nullptr this->model_data.models[k])\n");
#endif
continue;
}
for(l = 0; l < this->model_data.models[k]->tex_count; ++l) {
if(this->model_data.models[k]->tex[l]->filenames[0] == this->model_data.models[j]->tex[i]->filenames[0] ||
(this->model_data.models[k]->tex[l]->filenames[0] &&
this->model_data.models[j]->tex[i]->filenames[0] &&
!strcmp(this->model_data.models[k]->tex[l]->filenames[0], this->model_data.models[j]->tex[i]->filenames[0]))) {
tex_tmp = 0;
break;
}
}
}
if(tex_tmp)
++tex_count;
}
}
}
else this->model_data.models[j] = nullptr;
}
// printf("Tex count is %i %X\n", tex_count, tex_count);
// Allocate a new Texture array
tex_count = 0;
tex_tmp = 1;
// Set the first tex_count textures in the new Texture array to the textures from the zone model
// For i in each model
for(i = 0; i < this->model_data.model_count; ++i) {
if(!this->model_data.models[i]) {
#ifdef DEBUGEQG
printf("nullptr this->model_data.models[i])\n");
#endif
continue;
}
// For j = each texture in this model
for(j = 0; j < this->model_data.models[i]->tex_count; ++j) {
tex_tmp = 1; // Derision
// for k = each texture in the zone model
for(k = 0; k < tex_count; ++k) {
// if the texture filenames are at the same address or, the texture filenames are the same, we set tex_tmp to 0
if(tex[k]->filenames[0] == this->model_data.models[i]->tex[j]->filenames[0] ||
(tex[k]->filenames[0] &&
this->model_data.models[i]->tex[j]->filenames[0] &&
!strcmp(tex[k]->filenames[0], this->model_data.models[i]->tex[j]->filenames[0]))) {
tex_tmp = 0;
break;
}
}
// if tex_tmp is 0, i.e. this texture is not in the zone model, we add this texture to our new Texture array, at the end
if(tex_tmp) {
tex[tex_count] = this->model_data.models[i]->tex[j];
++tex_count;
}
}
}
for(i = 0; i < this->model_data.model_count; ++i) {
if(!this->model_data.models[i]) {
#ifdef DEBUGEQG
printf(">nullptr this->model_data.models[i])\n");
#endif
continue;
}
tex_map = new int[this->model_data.models[i]->tex_count];
for(j = 0; j < this->model_data.models[i]->tex_count; ++j) {
tex_map[j] = 0;
for(k = 0; k < tex_count; ++k) {
if(tex[k]->filenames[0] == this->model_data.models[i]->tex[j]->filenames[0] ||
(tex[k]->filenames[0] &&
this->model_data.models[i]->tex[j]->filenames[0] &&
!strcmp(tex[k]->filenames[0], this->model_data.models[i]->tex[j]->filenames[0]))) {
tex_map[j] = k;
break;
}
}
}
delete[] tex_map;
}
delete [] model_names;
this->model_data.zone_model->tex = 0;
this->model_data.zone_model->tex_count = 0;
delete [] orig_buffer;
this->status = 1;
return 1;
}
int ZonLoader::Close() {
int i;
if(!this->status)
return 1;
this->terloader.Close();
for(i = 0; i < this->model_data.model_count; ++i)
this->model_loaders[i].Close();
for(i = 0; i < this->model_data.model_count; ++i)
{
if(this->model_data.models[i])
{
delete [] this->model_data.models[i]->name;
delete this->model_data.models[i];
}
}
for(i = 0; i < this->model_data.plac_count; ++i)
delete this->model_data.placeable[i];
delete [] this->model_data.placeable;
delete [] this->model_data.models;
delete[] this->model_loaders;
status = 0;
return 1;
}
+47
View File
@@ -0,0 +1,47 @@
#ifndef __OPENEQ_ZON__
#define __OPENEQ_ZON__
#include "ter.hpp"
/* Big thanks to jbb on the ZON stuff! */
#pragma pack(1)
struct zon_header {
char magic[4]; // Constant at EQGZ
long version; // Constant at 2
long list_len; // Length of the list to follow.
long NumberOfModels;
long obj_count; // Placeable object count.
long unk[2]; // Unknown.
} typedef zon_header;
struct zon_placeable {
long id;
long loc;
float x, y, z;
float rx, ry, rz;
float scale;
} typedef zon_placeable;
struct zon_object {
long offset;
long id;
} typedef zon_object;
#pragma pack()
class ZonLoader : public FileLoader {
public:
ZonLoader();
~ZonLoader();
virtual int Open(char *base_path, char *zone_name, Archive *archive);
virtual int Close();
private:
TERLoader terloader;
TERLoader *model_loaders;
};
#endif
+255
View File
@@ -0,0 +1,255 @@
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include "3d.hpp"
#include "zonv4.hpp"
//#define DEBUGEQG
//#define DEBUGPLAC
string GetToken(uchar *&Buffer, int &Position);
Zonv4Loader::Zonv4Loader()
{
this->buffer = nullptr;
this->buf_len = -1;
this->archive = nullptr;
this->status = 0;
}
Zonv4Loader::~Zonv4Loader()
{
this->Close();
}
int Zonv4Loader::Open(char *base_path, char *zone_name, Archive *archive)
{
uchar *buffer;
int position;
int buf_len;
Texture **tex;
int tex_count, tex_tmp, *tex_map;
int i, j, k, l;
char **model_names;
char *filename;
uchar *zon_tmp, *zon_orig;
float rot_change = 180.0f / 3.14159f;
float base[3];
printf("Attempting to load EQG %s\n", zone_name);
filename = new char[strlen(zone_name) + 5];
sprintf(filename, "*.zon");
#ifdef DEBUGEQG
printf("Looking for ZON file %s\n", filename);
archive->GetFile("*.zon", &buffer, &buf_len);
#endif
if(!archive->GetFile(filename, &buffer, &buf_len))
{
printf("Couldn't find ZON file %s\n", zone_name);
return 0;
}
delete[] filename;
zonv4_header *hdr = (zonv4_header *) buffer;
zonv4_placeable *plac;
if(hdr->magic[0] != 'E' || hdr->magic[1] != 'Q' || hdr->magic[2] != 'T' || hdr->magic[3] != 'Z')
return 0;
#ifdef DEBUGEQG
printf("Found V4 EQG.\n"); fflush(stdout);
printf("Seeking .DAT file\n");
#endif
buffer += sizeof(zonv4_header);
position = 0;
char ZonName[255];
while(position < buf_len)
{
string Token = GetToken(buffer, position);
if(Token == "*NAME")
{
Token = GetToken(buffer, position);
#ifdef DEBUGEQG
printf(".zon name is %s\n", Token.c_str());
#endif
sprintf(ZonName, "%s.dat", Token.c_str());
break;
}
}
this->datloader.Open(nullptr, ZonName, archive);
this->model_data.zone_model = datloader.model_data.zone_model;
model_loaders = new TERLoader[this->datloader.model_data.ModelNames.size() + 1];
this->model_data.models = new Model *[this->datloader.model_data.ModelNames.size() + 1];
this->model_data.placeable = new Placeable *[this->datloader.model_data.PlaceableList.size()];
for(unsigned int i = 0; i < this->datloader.model_data.ModelNames.size(); ++i)
{
char tmp[200];
//printf("Opening %s.mod\n", this->datloader.model_data.ModelNames[i].c_str());
sprintf(tmp, "%s.mod", this->datloader.model_data.ModelNames[i].c_str());
char *str = tmp;
while(*str) {
if(*str >= 'A' && *str <= 'Z')
*str += 'a' - 'A';
++str;
}
if(model_loaders[i].Open(nullptr, tmp, archive))
{
this->model_data.models[i] = new Model;
this->model_data.models[i]->vert_count = model_loaders[i].model_data.zone_model->vert_count;
this->model_data.models[i]->poly_count = model_loaders[i].model_data.zone_model->poly_count;
this->model_data.models[i]->tex_count = model_loaders[i].model_data.zone_model->tex_count;
this->model_data.models[i]->verts = model_loaders[i].model_data.zone_model->verts;
this->model_data.models[i]->polys = model_loaders[i].model_data.zone_model->polys;
this->model_data.models[i]->tex = model_loaders[i].model_data.zone_model->tex;
this->model_data.models[i]->name = new char[100];
strcpy(this->model_data.models[i]->name, tmp);
this->model_data.models[i]->IncludeInMap = true;
// Attempt to cut down on the .map file size by defaulting some objects to not be included. The user can
// always change this in the azone.ini
//
// For example, taking out all the tak_braziers from elddar saves around 30MB
//
if(strstr(tmp, "tree") || strstr(tmp, "pine") || strstr(tmp, "palm") || strstr(tmp, "rock") ||
strstr(tmp, "shrub") || strstr(tmp, "fern") || strstr(tmp, "bamboo") || strstr(tmp, "coral") ||
strstr(tmp, "camp_bones") || strstr(tmp, "sponge") || strstr(tmp, "plant") || strstr(tmp, "shortplm") ||
strstr(tmp, "tak_brazier") || strstr(tmp, "tak_banner") || strstr(tmp, "fung") || strstr(tmp, "bolete") ||
strstr(tmp, "amanita") || strstr(tmp, "leopita"))
{
if(!strstr(tmp, "arch"))
{
this->model_data.models[i]->IncludeInMap = false;
}
}
}
else
{
printf("Unable to open model %s, but continuing.\n", tmp);
this->model_data.models[i] = new Model;
this->model_data.models[i]->IncludeInMap = false;
}
}
#ifdef DEBUGPLAC
printf("Placeable list:\n");
for(int i = 0; i < this->datloader.model_data.ObjectGroups.size(); ++i)
{
printf("ObjectGroup: %i\n", i);
printf(" XYZ: %8.3f, %8.3f, %8.3f Tile: (%8.3f, %8.3f, %8.3f) Rots: (%8.3f, %8.3f, %8.3f) Scale: %8.3f\n",
this->datloader.model_data.ObjectGroups[i].x,
this->datloader.model_data.ObjectGroups[i].y,
this->datloader.model_data.ObjectGroups[i].z,
this->datloader.model_data.ObjectGroups[i].TileX,
this->datloader.model_data.ObjectGroups[i].TileY,
this->datloader.model_data.ObjectGroups[i].TileZ,
this->datloader.model_data.ObjectGroups[i].RotX,
this->datloader.model_data.ObjectGroups[i].RotY,
this->datloader.model_data.ObjectGroups[i].RotZ,
this->datloader.model_data.ObjectGroups[i].ScaleX);
list<int>::iterator ModelIterator;
ModelIterator = this->datloader.model_data.ObjectGroups[i].SubObjects.begin();
while(ModelIterator != this->datloader.model_data.ObjectGroups[i].SubObjects.end())
{
printf(" Uses Placeable: %i\n", (*ModelIterator));
printf(" %s\n",
this->datloader.model_data.ModelNames[this->datloader.model_data.PlaceableList[(*ModelIterator)].model].c_str());
printf(" Model: %3i XYZ: (%8.3f, %8.3f, %8.3f) ROT: (%8.3f, %8.3f, %8.3f) SCALE: (%8.3f, %8.3f, %8.3f)\n",
this->datloader.model_data.PlaceableList[(*ModelIterator)].model,
this->datloader.model_data.PlaceableList[(*ModelIterator)].x,
this->datloader.model_data.PlaceableList[(*ModelIterator)].y,
this->datloader.model_data.PlaceableList[(*ModelIterator)].z,
this->datloader.model_data.PlaceableList[(*ModelIterator)].rx,
this->datloader.model_data.PlaceableList[(*ModelIterator)].ry,
this->datloader.model_data.PlaceableList[(*ModelIterator)].rz,
this->datloader.model_data.PlaceableList[(*ModelIterator)].scale[0],
this->datloader.model_data.PlaceableList[(*ModelIterator)].scale[1],
this->datloader.model_data.PlaceableList[(*ModelIterator)].scale[2]);
++ModelIterator;
}
}
#endif
for(unsigned int i = 0; i < this->datloader.model_data.PlaceableList.size(); ++i)
{
this->model_data.placeable[i] = new Placeable;
this->model_data.placeable[i]->model = this->datloader.model_data.PlaceableList[i].model;
this->model_data.placeable[i]->x = this->datloader.model_data.PlaceableList[i].x;
this->model_data.placeable[i]->y = this->datloader.model_data.PlaceableList[i].y;
this->model_data.placeable[i]->z = this->datloader.model_data.PlaceableList[i].z;
this->model_data.placeable[i]->rx = this->datloader.model_data.PlaceableList[i].rx;
this->model_data.placeable[i]->ry = this->datloader.model_data.PlaceableList[i].ry;
this->model_data.placeable[i]->rz = this->datloader.model_data.PlaceableList[i].rz;
this->model_data.placeable[i]->scale[0] = this->datloader.model_data.PlaceableList[i].scale[0];
this->model_data.placeable[i]->scale[1] = this->datloader.model_data.PlaceableList[i].scale[1];
this->model_data.placeable[i]->scale[2] = this->datloader.model_data.PlaceableList[i].scale[2];
}
this->model_data.ObjectGroups = this->datloader.model_data.ObjectGroups;
this->model_data.plac_count = this->datloader.model_data.PlaceableList.size();
this->model_data.model_count = this->datloader.model_data.ModelNames.size();
this->status = 1;
return 1;
}
int Zonv4Loader::Close()
{
int i;
if(!this->status)
return 1;
//TODO: Free up all the memory we used
this->datloader.Close();
for(i = 0; i < this->model_data.model_count; ++i)
this->model_loaders[i].Close();
delete[] this->model_loaders;
this->status = 0;
return 1;
}
+43
View File
@@ -0,0 +1,43 @@
#ifndef __OPENEQ_ZONV4__
#define __OPENEQ_ZONV4__
#include "dat.hpp"
#include "ter.hpp"
/* Big thanks to jbb on the ZON stuff! */
#pragma pack(1)
struct zonv4_header {
char magic[4]; // Constant at EQGZ
} typedef zonv4_header;
struct zonv4_placeable {
long id;
long loc;
float x, y, z;
float rx, ry, rz;
float scale;
} typedef zonv4_placeable;
struct zonv4_object {
long offset;
long id;
} typedef zonv4_object;
#pragma pack()
class Zonv4Loader : public FileLoader {
public:
Zonv4Loader();
~Zonv4Loader();
virtual int Open(char *base_path, char *zone_name, Archive *archive);
virtual int Close();
private:
DATLoader datloader;
TERLoader *model_loaders;
};
#endif
+19
View File
@@ -0,0 +1,19 @@
CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
PROJECT(PFSUtil)
IF(NOT CMAKE_BUILD_TYPE)
SET(CMAKE_BUILD_TYPE "Debug")
ENDIF(NOT CMAKE_BUILD_TYPE)
IF(WIN32)
ADD_DEFINITIONS(/D _CRT_SECURE_NO_WARNINGS)
ENDIF(WIN32)
SET(ZLIB_ROOT, "${CMAKE_CURRENT_SOURCE_DIR}/zlib")
FIND_PACKAGE(ZLIB REQUIRED)
INCLUDE_DIRECTORIES("${ZLIB_INCLUDE_DIRS}")
ADD_SUBDIRECTORY(Common)
ADD_SUBDIRECTORY(PFSList)
@@ -0,0 +1,17 @@
CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
SET(common_sources
Source/PFSArchive.cpp
Source/Compression.cpp
)
SET(common_headers
Include/Archive.h
Include/PFSArchive.h
Include/PFSDataStructs.h
Include/Compression.h
)
INCLUDE_DIRECTORIES(Include)
ADD_LIBRARY(Common ${common_sources} ${common_headers})
@@ -0,0 +1,20 @@
#ifndef __AZONE_COMMON_ARCHIVE_H
#define __AZONE_COMMON_ARCHIVE_H
#include <list>
#include <string>
#include <stdint.h>
class Archive {
public:
Archive() { }
virtual ~Archive() { }
virtual bool Open(std::string filename) = 0;
virtual bool Close() = 0;
virtual bool Get(std::string filename, char** buffer, size_t& buffer_size) = 0;
virtual bool Exists(std::string filename) = 0;
virtual bool GetFiles(std::string ext, std::list<std::string>& files) = 0;
};
#endif
@@ -0,0 +1,9 @@
#ifndef __AZONE_COMMON_COMPRESSION_H
#define __AZONE_COMMON_COMPRESSION_H
#include <string>
#include <zlib.h>
void decompress(const char* in, size_t in_len, char* out, size_t out_len);
#endif
@@ -0,0 +1,35 @@
#ifndef __AZONE_COMMON_PFSARCHIVE_H
#define __AZONE_COMMON_PFSARCHIVE_H
#include <stdio.h>
#include <string.h>
#include <list>
#include <vector>
#ifdef WIN32
#include <Winsock2.h>
#else
#include <arpa/inet.h>
#endif
#include "Archive.h"
#include "PFSDataStructs.h"
#include "Compression.h"
class PFSArchive : public Archive {
public:
PFSArchive();
virtual ~PFSArchive();
virtual bool Open(std::string filename);
virtual bool Close();
virtual bool Get(std::string filename, char **buffer, size_t& buffer_size);
virtual bool Exists(std::string filename);
virtual bool GetFiles(std::string ext, std::list<std::string>& files);
private:
bool ReadIntoBuffer(std::string filename);
std::vector<std::string> _filenames;
std::vector<size_t> _files;
char* _buffer;
size_t _buffer_size;
};
#endif
@@ -0,0 +1,36 @@
#ifndef __AZONE_COMMON_PFSDATASTRUCTS_H
#define __AZONE_COMMON_PFSDATASTRUCTS_H
#include <stdint.h>
#pragma pack(1)
struct PFSHeader {
uint32_t offset;
char magic[4];
uint32_t unknown;
};
struct PFSDirectoryHeader {
uint32_t count;
};
struct PFSDirectory {
uint32_t crc, offset, size;
};
struct PFSDataBlock {
uint32_t deflate_length, inflate_length;
};
struct PFSFilenameHeader {
uint32_t filename_count;
};
struct PFSFilenameEntry {
uint32_t filename_length;
};
#pragma pack()
#endif
@@ -0,0 +1,19 @@
#include "Compression.h"
void decompress(const char* in, size_t in_len, char* out, size_t out_len) {
int status;
z_stream d_stream;
d_stream.zalloc = (alloc_func)0;
d_stream.zfree = (free_func)0;
d_stream.opaque = (voidpf)0;
d_stream.next_in = (Bytef*)in;
d_stream.avail_in = in_len;
d_stream.next_out = (Bytef*)out;
d_stream.avail_out = out_len;
inflateInit(&d_stream);
status = inflate(&d_stream, Z_NO_FLUSH);
inflateEnd(&d_stream);
}
@@ -0,0 +1,220 @@
#include "PFSArchive.h"
#define BufferRead(x, y) x = (y*)&_buffer[position]; position += sizeof(y);
#define BufferReadLength(x, y) memcpy(x, &_buffer[position], y); position += y;
#define MAX_FILENAME_SIZE 1024
PFSArchive::PFSArchive()
:_buffer(NULL), _buffer_size(0)
{
}
PFSArchive::~PFSArchive() {
Close();
}
bool PFSArchive::Open(std::string filename)
{
if(!ReadIntoBuffer(filename)) {
Close();
return false;
}
PFSHeader *header = NULL;
PFSDirectoryHeader *directory_header = NULL;
PFSDirectory *directory = NULL;
PFSDataBlock *data_block = NULL;
PFSFilenameHeader *filename_header = NULL;
PFSFilenameEntry *filename_entry = NULL;
size_t position = 0;
BufferRead(header, PFSHeader);
if(header->magic[0] != 'P' ||
header->magic[1] != 'F' ||
header->magic[2] != 'S' ||
header->magic[3] != ' ')
{
Close();
return false;
}
position = header->offset;
BufferRead(directory_header, PFSDirectoryHeader);
std::vector<uint32_t> offsets(directory_header->count, 0);
_filenames.resize(directory_header->count);
_files.resize(directory_header->count);
size_t i = 0;
size_t j = 0;
size_t running = 0;
size_t temp_position = 0;
size_t inflate = 0;
char temp_buffer[32768];
char temp_buffer2[32768];
char temp_string[MAX_FILENAME_SIZE];
for(; i < directory_header->count; ++i) {
BufferRead(directory, PFSDirectory);
if(directory->crc == ntohl(0xC90A5861)) {
temp_position = position;
position = directory->offset;
memset(temp_buffer, 0, directory->size);
inflate = 0;
while(inflate < directory->size) {
BufferRead(data_block, PFSDataBlock);
BufferReadLength(temp_buffer2, data_block->deflate_length);
decompress(temp_buffer2, data_block->deflate_length, temp_buffer + inflate, data_block->inflate_length);
inflate += data_block->inflate_length;
}
position = temp_position;
filename_header = (PFSFilenameHeader*)&temp_buffer[0];
temp_position = sizeof(PFSFilenameHeader);
for(j = 0; j < filename_header->filename_count; ++j)
{
filename_entry = (PFSFilenameEntry*)&temp_buffer[temp_position];
if(filename_entry->filename_length + 1 >= MAX_FILENAME_SIZE) {
Close();
return false;
}
temp_string[filename_entry->filename_length] = 0;
memcpy(temp_string, &temp_buffer[temp_position + sizeof(PFSFilenameEntry)], filename_entry->filename_length);
_filenames[j] = temp_string;
temp_position += sizeof(PFSFilenameEntry) + filename_entry->filename_length;
}
} else {
_files[running] = position - 12;
offsets[running] = directory->offset;
++running;
}
}
uint32_t temp = 0;
for(i = directory_header->count - 2; i > 0; i--) {
for(j = 0; j < i; j++) {
if(offsets[j] > offsets[j + 1]) {
temp = offsets[j];
offsets[j] = offsets[j + 1];
offsets[j + 1] = temp;
temp = _files[j];
_files[j] = _files[j + 1];
_files[j + 1] = temp;
}
}
}
return true;
}
bool PFSArchive::Close()
{
if(_buffer) {
delete[] _buffer;
_buffer = 0;
_buffer_size = 0;
_filenames.resize(0);
_files.resize(0);
return true;
}
return false;
}
//I would love to get rid of the allocations in the while loop below but sadly
//I can't predict the size of data blocks well enough to be able to and feel
//comfortable with it (I could however reduce the number of times I need to
//reallocate with a little clever logic which i think I will do
bool PFSArchive::Get(std::string filename, char **buffer, size_t& buffer_size) {
size_t sz = _filenames.size();
for(size_t index = 0; index < sz; ++index) {
if(!_filenames[index].compare(filename)) {
PFSDirectory* directory = NULL;
PFSDataBlock* data_block = NULL;
char *temp = NULL;
size_t position = _files[index];
BufferRead(directory, PFSDirectory);
position = directory->offset;
*buffer = new char[directory->size];
buffer_size = directory->size;
size_t inflate = 0;
while(inflate < directory->size) {
BufferRead(data_block, PFSDataBlock);
temp = new char[data_block->deflate_length];
memcpy(temp, &_buffer[position], data_block->deflate_length);
position += data_block->deflate_length;
decompress(temp, data_block->deflate_length, *buffer + inflate, data_block->inflate_length);
delete[] temp;
inflate += data_block->inflate_length;
}
buffer_size = inflate;
return true;
}
}
return false;
}
bool PFSArchive::Exists(std::string filename) {
size_t count = _filenames.size();
for(size_t i = 0; i < count; ++i) {
if(!_filenames[i].compare(filename.c_str()))
return true;
}
return false;
}
bool PFSArchive::GetFiles(std::string ext, std::list<std::string>& files) {
int elen = ext.length();
bool all_files = !ext.compare("*");
files.clear();
size_t count = _filenames.size();
for(size_t i = 0; i < count; ++i) {
int flen = _filenames[i].length();
if(flen <= elen)
continue;
if(!strcmp(_filenames[i].c_str() + (flen - elen), ext.c_str()) || all_files)
files.push_back(_filenames[i]);
}
return files.size() > 0;
}
bool PFSArchive::ReadIntoBuffer(std::string filename) {
FILE* f = fopen(filename.c_str(), "rb");
if(!f) {
return false;
}
fseek(f, 0, SEEK_END);
size_t total_size = ftell(f);
rewind(f);
if(!total_size) {
fclose(f);
return false;
}
if(_buffer) {
delete[] _buffer;
}
_buffer = new char[total_size];
size_t bytes_read = fread(_buffer, 1, total_size, f);
if(bytes_read != total_size) {
return false;
}
_buffer_size = total_size;
fclose(f);
return true;
}
@@ -0,0 +1,23 @@
CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
SET(pfslist_sources
Source/main.cpp
)
SET(pfslist_headers
)
INCLUDE_DIRECTORIES(Include
../Common/Include
)
ADD_EXECUTABLE(PFSList ${pfslist_sources} ${pfslist_headers})
TARGET_LINK_LIBRARIES(PFSList Common ${ZLIB_LIBRARY} "Ws2_32.lib")
IF(MSVC)
ADD_DEFINITIONS(/D _CONSOLE)
SET_TARGET_PROPERTIES(PFSList PROPERTIES LINK_FLAGS_RELEASE "/OPT:REF /OPT:ICF")
ENDIF(MSVC)
SET(EXECUTABLE_OUTPUT_PATH ../Build/PFSList)
@@ -0,0 +1,35 @@
#include <stdio.h>
#include <string>
#include "PFSArchive.h"
int main(int argc, char **argv) {
if(argc < 3) {
printf("Usage: %s ext file1 [file2...]\n", argv[0]);
return 1;
}
for(int i = 2; i < argc; ++i) {
PFSArchive archive;
if(!archive.Open(argv[i])) {
printf("Error: couldn't open %s\n", argv[i]);
continue;
}
std::list<std::string> files;
if(!archive.GetFiles(argv[1], files)) {
printf("Error: couldn't return the files with ext: %s\n", argv[1]);
continue;
}
printf("Files in %s:\n", argv[i]);
std::list<std::string>::const_iterator iter = files.begin();
while(iter != files.end()) {
printf("%s\n", (*iter).c_str());
iter++;
}
printf("\n");
archive.Close();
}
return 0;
}
@@ -0,0 +1 @@
Simple utility to modify fields in player profile... far from complete. Right now just sets ldon points to 0 but going to expand it.
@@ -0,0 +1,4 @@
host=localhost
user=root
password=pass
db=eq
@@ -0,0 +1,20 @@
Microsoft Visual Studio Solution File, Format Version 10.00
# Visual C++ Express 2008
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "player_profile_set", "player_profile_set\player_profile_set.vcproj", "{3307DA97-CDDB-4C89-AAE7-BC0AF03D3D6D}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
Release|Win32 = Release|Win32
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{3307DA97-CDDB-4C89-AAE7-BC0AF03D3D6D}.Debug|Win32.ActiveCfg = Debug|Win32
{3307DA97-CDDB-4C89-AAE7-BC0AF03D3D6D}.Debug|Win32.Build.0 = Debug|Win32
{3307DA97-CDDB-4C89-AAE7-BC0AF03D3D6D}.Release|Win32.ActiveCfg = Release|Win32
{3307DA97-CDDB-4C89-AAE7-BC0AF03D3D6D}.Release|Win32.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal
@@ -0,0 +1,331 @@
#include "misc_functions.h"
#include <string.h>
#include <time.h>
#include <math.h>
#ifndef WIN32
#include <netinet/in.h>
#include <sys/socket.h>
#endif
#include <iostream>
#include <iomanip>
#ifdef WIN32
#include <io.h>
#endif
using namespace std;
#ifdef WIN32
#include <windows.h>
#define snprintf _snprintf
#if (_MSC_VER < 1500)
#define vsnprintf _vsnprintf
#endif
#define strncasecmp _strnicmp
#define strcasecmp _stricmp
#else
#include <stdlib.h>
#include <ctype.h>
#include <stdarg.h>
#include <sys/types.h>
#include <sys/time.h>
#ifdef FREEBSD //Timothy Whitman - January 7, 2003
#include <sys/socket.h>
#include <netinet/in.h>
#endif
#include <sys/stat.h>
#include <unistd.h>
#include <netdb.h>
#include <errno.h>
#endif
char* strn0cpy(char* dest, const char* source, int32 size) {
if (!dest)
return 0;
if (size == 0 || source == 0) {
dest[0] = 0;
return dest;
}
strncpy(dest, source, size);
dest[size - 1] = 0;
return dest;
}
// String N w/null Copy Truncated?
// return value =true if entire string(source) fit, false if it was truncated
bool strn0cpyt(char* dest, const char* source, int32 size) {
if (!dest)
return 0;
if (size == 0 || source == 0) {
dest[0] = 0;
return dest;
}
strncpy(dest, source, size);
dest[size - 1] = 0;
return (bool) (source[strlen(dest)] == 0);
}
const char *MakeUpperString(const char *source) {
static char str[128];
if (!source)
return NULL;
MakeUpperString(source, str);
return str;
}
void MakeUpperString(const char *source, char *target) {
if (!source || !target) {
*target=0;
return;
}
while (*source)
{
*target = toupper(*source);
target++;source++;
}
*target = 0;
}
const char *MakeLowerString(const char *source) {
static char str[128];
if (!source)
return NULL;
MakeLowerString(source, str);
return str;
}
void MakeLowerString(const char *source, char *target) {
if (!source || !target) {
*target=0;
return;
}
while (*source)
{
*target = tolower(*source);
target++;source++;
}
*target = 0;
}
int MakeAnyLenString(char** ret, const char* format, ...) {
int buf_len = 128;
int chars = -1;
va_list argptr;
va_start(argptr, format);
while (chars == -1 || chars >= buf_len) {
safe_delete_array(*ret);
if (chars == -1)
buf_len *= 2;
else
buf_len = chars + 1;
*ret = new char[buf_len];
chars = vsnprintf(*ret, buf_len, format, argptr);
}
va_end(argptr);
return chars;
}
int32 AppendAnyLenString(char** ret, int32* bufsize, int32* strlen, const char* format, ...) {
if (*bufsize == 0)
*bufsize = 256;
if (*ret == 0)
*strlen = 0;
int chars = -1;
char* oldret = 0;
va_list argptr;
va_start(argptr, format);
while (chars == -1 || chars >= (sint32)(*bufsize-*strlen)) {
if (chars == -1)
*bufsize += 256;
else
*bufsize += chars + 25;
oldret = *ret;
*ret = new char[*bufsize];
if (oldret) {
if (*strlen)
memcpy(*ret, oldret, *strlen);
safe_delete_array(oldret);
}
chars = vsnprintf(&(*ret)[*strlen], (*bufsize-*strlen), format, argptr);
}
va_end(argptr);
*strlen += chars;
return *strlen;
}
int32 hextoi(char* num) {
int len = strlen(num);
if (len < 3)
return 0;
if (num[0] != '0' || (num[1] != 'x' && num[1] != 'X'))
return 0;
int32 ret = 0;
int mul = 1;
for (int i=len-1; i>=2; i--) {
if (num[i] >= 'A' && num[i] <= 'F')
ret += ((num[i] - 'A') + 10) * mul;
else if (num[i] >= 'a' && num[i] <= 'f')
ret += ((num[i] - 'a') + 10) * mul;
else if (num[i] >= '0' && num[i] <= '9')
ret += (num[i] - '0') * mul;
else
return 0;
mul *= 16;
}
return ret;
}
int64 hextoi64(char* num) {
int len = strlen(num);
if (len < 3)
return 0;
if (num[0] != '0' || (num[1] != 'x' && num[1] != 'X'))
return 0;
int64 ret = 0;
int mul = 1;
for (int i=len-1; i>=2; i--) {
if (num[i] >= 'A' && num[i] <= 'F')
ret += ((num[i] - 'A') + 10) * mul;
else if (num[i] >= 'a' && num[i] <= 'f')
ret += ((num[i] - 'a') + 10) * mul;
else if (num[i] >= '0' && num[i] <= '9')
ret += (num[i] - '0') * mul;
else
return 0;
mul *= 16;
}
return ret;
}
bool atobool(char* iBool) {
if (!strcasecmp(iBool, "true"))
return true;
if (!strcasecmp(iBool, "false"))
return false;
if (!strcasecmp(iBool, "yes"))
return true;
if (!strcasecmp(iBool, "no"))
return false;
if (!strcasecmp(iBool, "on"))
return true;
if (!strcasecmp(iBool, "off"))
return false;
if (!strcasecmp(iBool, "enable"))
return true;
if (!strcasecmp(iBool, "disable"))
return false;
if (!strcasecmp(iBool, "enabled"))
return true;
if (!strcasecmp(iBool, "disabled"))
return false;
if (!strcasecmp(iBool, "y"))
return true;
if (!strcasecmp(iBool, "n"))
return false;
if (atoi(iBool))
return true;
return false;
}
/*
* solar: generate a random integer in the range low-high
* this should be used instead of the rand()%limit method
*/
int MakeRandomInt(int low, int high)
{
if(low >= high)
return(low);
return (rand()%(high-low+1) + (low));
}
double MakeRandomFloat(double low, double high)
{
if(low >= high)
return(low);
return (rand() / (double)RAND_MAX * (high - low) + low);
}
// solar: removes the crap and turns the underscores into spaces.
char *CleanMobName(const char *in, char *out)
{
unsigned i, j;
for(i = j = 0; i < strlen(in); i++)
{
// convert _ to space.. any other conversions like this? I *think* this
// is the only non alpha char that's not stripped but converted.
if(in[i] == '_')
{
out[j++] = ' ';
}
else
{
if(isalpha(in[i]) || (in[i] == '`')) // numbers, #, or any other crap just gets skipped
out[j++] = in[i];
}
}
out[j] = 0; // terimnate the string before returning it
return out;
}
const char *ConvertArray(int input, char *returnchar)
{
sprintf(returnchar, "%i" ,input);
return returnchar;
}
const char *ConvertArrayF(float input, char *returnchar)
{
sprintf(returnchar, "%0.2f", input);
return returnchar;
}
float EQ13toFloat(int d)
{
return ( float(d)/float(1<<2));
}
float NewEQ13toFloat(int d)
{
return ( float(d)/float(1<<6));
}
float EQ19toFloat(int d)
{
return ( float(d)/float(1<<3));
}
int FloatToEQ13(float d)
{
return int(d*float(1<<2));
}
int NewFloatToEQ13(float d)
{
return int(d*float(1<<6));
}
int FloatToEQ19(float d)
{
return int(d*float(1<<3));
}
/*
Heading of 0 points in the pure positive Y direction
*/
int FloatToEQH(float d)
{
return(int((360.0f - d) * float(1<<11)) / 360);
}
float EQHtoFloat(int d)
{
return(360.0f - float((d * 360) >> 11));
}
@@ -0,0 +1,79 @@
/* EQEMu: Everquest Server Emulator
Copyright (C) 2001-2002 EQEMu Development Team (http://eqemu.org)
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY except by those people which sell it, which
are required to give you total support for your newly bought product;
without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef MISCFUNCTIONS_H
#define MISCFUNCTIONS_H
#include "types.h"
#include <stdio.h>
#include <ctype.h>
#ifndef ERRBUF_SIZE
#define ERRBUF_SIZE 1024
#endif
// These are helper macros for dealing with packets of variable length, typically those that contain
// variable length strings where it is not convenient to use a fixed length struct.
//
#define VARSTRUCT_DECODE_TYPE(Type, Buffer) *(Type *)Buffer; Buffer += sizeof(Type);
#define VARSTRUCT_DECODE_STRING(String, Buffer) strcpy(String, Buffer); Buffer += strlen(String)+1;
#define VARSTRUCT_ENCODE_STRING(Buffer, String) sprintf(Buffer, String); Buffer += strlen(String) + 1;
#define VARSTRUCT_ENCODE_INTSTRING(Buffer, Number) sprintf(Buffer, "%i", Number); Buffer += strlen(Buffer) + 1;
#define VARSTRUCT_ENCODE_TYPE(Type, Buffer, Value) *(Type *)Buffer = Value; Buffer += sizeof(Type);
//////////////////////////////////////////////////////////////////////
//
// MakeUpperString
// i : source - allocated null-terminated string
// return: pointer to static buffer with the target string
const char *MakeUpperString(const char *source);
const char *MakeLowerString(const char *source);
//////////////////////////////////////////////////////////////////////
//
// MakeUpperString
// i : source - allocated null-terminated string
// io: target - allocated buffer, at least of size strlen(source)+1
void MakeUpperString(const char *source, char *target);
void MakeLowerString(const char *source, char *target);
int MakeAnyLenString(char** ret, const char* format, ...);
int32 AppendAnyLenString(char** ret, int32* bufsize, int32* strlen, const char* format, ...);
int32 hextoi(char* num);
int64 hextoi64(char* num);
bool atobool(char* iBool);
void CoutTimestamp(bool ms = true);
char* strn0cpy(char* dest, const char* source, int32 size);
// return value =true if entire string(source) fit, false if it was truncated
bool strn0cpyt(char* dest, const char* source, int32 size);
int MakeRandomInt(int low, int high);
double MakeRandomFloat(double low, double high);
char *CleanMobName(const char *in, char *out);
const char *ConvertArray(int input, char *returnchar);
const char *ConvertArrayF(float input, char *returnchar);
float EQ13toFloat(int d);
float NewEQ13toFloat(int d);
float EQ19toFloat(int d);
float EQHtoFloat(int d);
int FloatToEQ13(float d);
int NewFloatToEQ13(float d);
int FloatToEQ19(float d);
int FloatToEQH(float d);
#endif
@@ -0,0 +1,133 @@
#include "database.h"
#include "main.h"
#include "eq_player_structs.h"
#include <vector>
extern std::vector<player_entry> player_list;
EQEmuDatabase::EQEmuDatabase(std::string ServerName, std::string DatabaseName, std::string DBUsername, std::string DBPassword) {
SetServerName(ServerName);
SetDatabaseName(DatabaseName);
SetDBUsername(DBUsername);
SetDBPassword(DBPassword);
_mysql = mysql_init(NULL);
if(_mysql)
{
if (!mysql_real_connect(_mysql, GetServerName().c_str(), GetDBUsername().c_str(),
GetDBPassword().c_str(), GetDatabaseName().c_str(), 0, NULL, 0))
{
cout << "MYSQL CONNECT FAILED: " << endl;
cout << GetServerName() << endl;
cout << GetDBUsername() << endl;
cout << GetDBPassword() << endl;
cout << GetDatabaseName() << endl;
mysql_close(_mysql);
_mysql = 0;
}
}
}
EQEmuDatabase::~EQEmuDatabase()
{
if(_mysql)
{
mysql_close(_mysql);
}
}
void EQEmuDatabase::GetPlayer(std::string name)
{
bool result = false;
if(!_mysql)
{
cout << "NOT CONNECTED TO MYQSL: " << endl;
return;
}
MYSQL_RES *res;
MYSQL_ROW row;
char * mQuery = 0;
MakeAnyLenString(&mQuery, "SELECT profile, id FROM character_ WHERE name='%s'", name.c_str());
if (mysql_query(_mysql, mQuery)) {
cout << "Query failed: " << mQuery << endl;
return;
}
res = mysql_use_result(_mysql);
if(res)
{
while ((row = mysql_fetch_row(res)) != NULL)
{
player_entry pe;
pe.id = atoi(row[1]);
pe.data = new char[sizeof(PlayerProfile_Struct)];
memcpy(pe.data, row[0], sizeof(PlayerProfile_Struct));
player_list.push_back(pe);
PlayerProfile_Struct *m_pp = (PlayerProfile_Struct*)pe.data;
}
mysql_free_result(res);
}
delete[] mQuery;
mQuery = 0;
}
void EQEmuDatabase::GetPlayers()
{
bool result = false;
if(!_mysql)
{
cout << "NOT CONNECTED TO MYQSL: " << endl;
return;
}
MYSQL_RES *res;
MYSQL_ROW row;
char * mQuery = 0;
MakeAnyLenString(&mQuery, "SELECT profile, id FROM character_");
if (mysql_query(_mysql, mQuery)) {
cout << "Query failed: " << mQuery << endl;
return;
}
res = mysql_use_result(_mysql);
if(res)
{
while ((row = mysql_fetch_row(res)) != NULL)
{
player_entry pe;
pe.id = atoi(row[1]);
pe.data = new char[sizeof(PlayerProfile_Struct)];
memcpy(pe.data, row[0], sizeof(PlayerProfile_Struct));
player_list.push_back(pe);
PlayerProfile_Struct *m_pp = (PlayerProfile_Struct*)pe.data;
}
mysql_free_result(res);
}
delete[] mQuery;
mQuery = 0;
}
void EQEmuDatabase::StorePlayer(int32 charid, char* data)
{
if(!_mysql)
{
cout << "NOT CONNECTED TO MYQSL: " << endl;
return;
}
char *outbuffer = new char[2*sizeof(PlayerProfile_Struct) + 512];
char *bptr = outbuffer;
bptr += snprintf(bptr, 128, "UPDATE character_ SET profile='");
bptr += mysql_real_escape_string(_mysql, bptr, (const char *) data, sizeof(PlayerProfile_Struct));
snprintf(bptr, 128, "' WHERE id=%lu", charid);
if (mysql_query(_mysql, outbuffer)) {
cout << "Query failed: " << outbuffer << endl;
}
delete[] outbuffer;
outbuffer = 0;
}
@@ -0,0 +1,45 @@
#if !defined(_L__EQDATAB__H)
#define _L__EQDATAB__H
#include "misc_functions.h"
#ifdef WIN32
#include <windows.h>
#endif
#include <mysql.h>
#include <string>
#include <ctime>
#include <iostream>
using namespace std;
#pragma comment ( lib, "libmysql" )
class EQEmuDatabase {
public:
EQEmuDatabase(string serverName, string databaseName, string dbUsername, string dbPassword);
~EQEmuDatabase();
bool Connected() { if(_mysql){ return true; }else{ return false; } }
void SetDBUsername(string dbUsername) { _dbUsername = dbUsername; };
void SetDBPassword(string dbPassword) { _dbPassword = dbPassword; };
void SetDatabaseName(string databaseName) { _databaseName = databaseName; };
void SetServerName(string serverName) { _serverName = serverName; };
string GetDBUsername() { return _dbUsername; };
string GetDBPassword() { return _dbPassword; };
string GetDatabaseName() { return _databaseName; };
string GetServerName() { return _serverName; };
void GetPlayer(std::string name);
void GetPlayers();
void StorePlayer(int32 charid, char* data);
private:
string _dbUsername;
string _dbPassword;
string _databaseName;
string _serverName;
MYSQL *_mysql;
};
#endif
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,21 @@
#ifndef EQEMU_STRING_H
#define EQEMU_STRING_H
#include <string>
#include <cctype>
namespace EQEmuString
{
std::string ToUpper(std::string in_string)
{
std::string out_string = in_string;
for(unsigned int i = 0; i < in_string.size(); ++i)
{
out_string[i] = std::toupper(in_string[i]);
}
return out_string;
}
};
#endif
@@ -0,0 +1,118 @@
#include "ini.h"
INIParser::INIParser(const char *filename)
{
memset(file, 0, 128);
if(strlen(filename) > 128)
{
strncpy(file, filename, 128);
}
else
{
strncpy(file, filename, strlen(filename));
}
Parse();
}
INIParser::~INIParser()
{
}
void INIParser::Parse()
{
FILE *fp;
if(fp = fopen(file, "r"))
{
char Option[255], Param[255];
while(!feof(fp))
{
ReadLine(fp, Option, Param);
AddOption(std::string(Option), std::string(Param));
}
fclose(fp);
}
}
void INIParser::ReadLine(FILE *fp, char *Option, char *Param)
{
typedef enum ReadingState { ReadingOption, ReadingParameter };
ReadingState State = ReadingOption;
int StrIndex = 0;
char ch;
strcpy(Option, "");
strcpy(Param, "");
while(true) {
ch = fgetc(fp);
if((ch=='#')&&(StrIndex==0)) { // Discard comment lines beginning with a hash
while((ch!=EOF)&&(ch!='\n'))
ch = fgetc(fp);
continue;
}
if(ch=='\r') continue;
if((ch==EOF)||(ch=='\n')) {
switch(State) {
case ReadingOption: {
Option[StrIndex]='\0';
break;
}
case ReadingParameter: {
Param[StrIndex] = '\0';
break;
}
}
break;
}
if(ch=='=') {
if(State==ReadingOption) {
Option[StrIndex] = '\0';
State = ReadingParameter;
StrIndex = 0;
continue;
}
}
switch(State) {
case ReadingOption: {
Option[StrIndex++]=tolower(ch);
break;
}
case ReadingParameter: {
Param[StrIndex++]=ch;
break;
}
}
}
if(!strcmp(Param,"true")) strcpy(Param,"1");
if(!strcmp(Param,"false")) strcpy(Param,"0");
}
void INIParser::AddOption(std::string option, std::string param)
{
for(unsigned int x = 0; x < options.size(); ++x)
{
if(options[x].option == option)
return;
}
iniData d;
d.option = option;
d.param = param;
options.push_back(d);
}
std::string INIParser::GetOption(std::string option)
{
for(unsigned int x = 0; x < options.size(); ++x)
{
if(options[x].option == option)
return options[x].param;
}
return std::string("Not Found");
}
@@ -0,0 +1,32 @@
#ifndef INI__H
#define INI__H
#include <string>
#include <stdio.h>
#include <stdlib.h>
#include <vector>
struct iniData
{
std::string option;
std::string param;
};
class INIParser
{
public:
INIParser(const char *filename);
~INIParser();
void Parse();
void ReadLine(FILE *fp, char *Option, char *Param);
void AddOption(std::string option, std::string param);
std::string GetOption(std::string option);
protected:
char file[128];
std::vector<iniData> options;
};
#endif
@@ -0,0 +1,143 @@
#include <iostream>
#include <sstream>
#include <vector>
#include "eq_player_structs.h"
#include "database.h"
#include "ini.h"
#include "main.h"
#include "eqemu_string.h"
EQEmuDatabase *emu_db;
std::vector<player_entry> player_list;
//player_profile_set [SET/VIEW] [Field] [Name/*]
//ex: player_profile_set VIEW LDON_MMC Jess
int main(int argc, char* argv[])
{
INIParser *ini = new INIParser("database.ini");
std::string host = ini->GetOption("host");
std::string user = ini->GetOption("user");
std::string pass = ini->GetOption("password");
std::string datab = ini->GetOption("db");
if(argc != 5)
{
std::cout << "Usage: player_profile_set [SET/VIEW] [Field] [Value] [Name/*]" << std::endl;
std::cout << "Ex: player_profile_set VIEW LDON_MMC 0 Jess" << std::endl;
std::cout << "Would view the number of LDoN MMC points earned by Jess" << std::endl << std::endl;
std::cout << "Ex: player_profile_set SET LDON_TOTAL 0 *" << std::endl;
std::cout << "Would view the number of LDoN MMC points earned by All players to 0" << std::endl;
delete ini;
ini = 0;
exit(1);
}
std::string program_action = argv[1];
std::string program_field = argv[2];
std::string program_value = argv[3];
std::string player_name = argv[4];
program_action = EQEmuString::ToUpper(program_action);
program_field = EQEmuString::ToUpper(program_field);
emu_db = new EQEmuDatabase(host.c_str(), datab.c_str(), user.c_str(), pass.c_str());
if(!emu_db->Connected())
{
delete ini;
ini = 0;
delete emu_db;
emu_db = 0;
exit(1);
}
if(player_name == "*")
emu_db->GetPlayers();
else
emu_db->GetPlayer(player_name);
std::vector<player_entry>::iterator iter = player_list.begin();
while(iter != player_list.end())
{
player_entry pe = (*iter);
PlayerProfile_Struct *m_pp = (PlayerProfile_Struct*)pe.data;
if(program_action == "SET")
{
m_pp->ldon_points_available = 0;
m_pp->ldon_points_guk = 0;
m_pp->ldon_points_mir = 0;
m_pp->ldon_points_mmc = 0;
m_pp->ldon_points_ruj = 0;
m_pp->ldon_points_tak = 0;
emu_db->StorePlayer(pe.id, pe.data);
}
else if(program_action == "VIEW")
{
std::cout << m_pp->name << std::endl;
std::cout << m_pp->ldon_points_available << std::endl;
std::cout << m_pp->ldon_points_guk << std::endl;
std::cout << m_pp->ldon_points_mir << std::endl;
std::cout << m_pp->ldon_points_mmc << std::endl;
std::cout << m_pp->ldon_points_ruj << std::endl;
std::cout << m_pp->ldon_points_tak << std::endl;
}
else
{
std::cout << "Unknown action specified" << std::endl;
}
delete[] pe.data;
pe.data = 0;
iter++;
}
player_list.clear();
delete ini;
ini = 0;
delete emu_db;
emu_db = 0;
std::cout << "Press enter to exit...";
std::cin.get();
exit(0);
}
std::string ConvertFieldToValue(PlayerProfile_Struct *m_pp, std::string field)
{
if(!m_pp)
{
return std::string("Unable to convert field to value");
}
std::stringstream ss(std::stringstream::out | std::stringstream::in);
if(field == "LASTNAME")
{
ss << m_pp->last_name;
return ss.str();
}
if(field == "GENDER")
{
ss << m_pp->gender;
return ss.str();
}
if(field == "RACE")
{
ss << m_pp->race;
return ss.str();
}
if(field == "CLASS")
{
ss << m_pp->class_;
return ss.str();
}
return std::string("Unable to convert field to value");
}
void ConvertValueToField(PlayerProfile_Struct *m_pp, std::string field, std::string value)
{
}
@@ -0,0 +1,16 @@
#ifndef EQ_MAIN_H
#define EQ_MAIN_H
#include "types.h"
#include "eq_player_structs.h"
struct player_entry
{
int32 id;
char *data;
};
std::string ConvertFieldToValue(PlayerProfile_Struct *m_pp, std::string field);
void ConvertValueToField(PlayerProfile_Struct *m_pp, std::string field, std::string value);
#endif
@@ -0,0 +1,233 @@
<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="9.00"
Name="player_profile_set"
ProjectGUID="{3307DA97-CDDB-4C89-AAE7-BC0AF03D3D6D}"
RootNamespace="player_profile_set"
Keyword="Win32Proj"
TargetFrameworkVersion="196613"
>
<Platforms>
<Platform
Name="Win32"
/>
</Platforms>
<ToolFiles>
</ToolFiles>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="1"
CharacterSet="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="0"
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS"
MinimalRebuild="true"
BasicRuntimeChecks="3"
RuntimeLibrary="3"
UsePrecompiledHeader="0"
WarningLevel="3"
DebugInformationFormat="4"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
LinkIncremental="2"
GenerateDebugInformation="true"
SubSystem="1"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="1"
CharacterSet="1"
WholeProgramOptimization="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="2"
EnableIntrinsicFunctions="true"
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
RuntimeLibrary="2"
EnableFunctionLevelLinking="true"
UsePrecompiledHeader="0"
WarningLevel="3"
DebugInformationFormat="3"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
LinkIncremental="1"
GenerateDebugInformation="true"
SubSystem="1"
OptimizeReferences="2"
EnableCOMDATFolding="2"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<Filter
Name="Source Files"
Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
>
<File
RelativePath=".\database.cpp"
>
</File>
<File
RelativePath=".\ini.cpp"
>
</File>
<File
RelativePath=".\main.cpp"
>
</File>
<File
RelativePath=".\MiscFunctions.cpp"
>
</File>
</Filter>
<Filter
Name="Header Files"
Filter="h;hpp;hxx;hm;inl;inc;xsd"
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
>
<File
RelativePath=".\database.h"
>
</File>
<File
RelativePath=".\eq_player_structs.h"
>
</File>
<File
RelativePath=".\eqemu_string.h"
>
</File>
<File
RelativePath=".\ini.h"
>
</File>
<File
RelativePath=".\main.h"
>
</File>
<File
RelativePath=".\MiscFunctions.h"
>
</File>
<File
RelativePath=".\types.h"
>
</File>
</Filter>
<Filter
Name="Resource Files"
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
>
</Filter>
</Files>
<Globals>
</Globals>
</VisualStudioProject>
@@ -0,0 +1,110 @@
/* EQEMu: Everquest Server Emulator
Copyright (C) 2001-2002 EQEMu Development Team (http://eqemu.org)
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY except by those people which sell it, which
are required to give you total support for your newly bought product;
without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef TYPES_H
#define TYPES_H
// TODO: If we require signed or unsigned we should the s and u types..
typedef unsigned char int8;
typedef unsigned char byte;
typedef unsigned short int16;
typedef unsigned int int32;
typedef unsigned char uint8;
typedef signed char sint8;
typedef unsigned short uint16;
typedef signed short sint16;
typedef unsigned int uint32;
typedef signed int sint32;
#ifdef WIN32
#if defined(_INTEGRAL_MAX_BITS) && _INTEGRAL_MAX_BITS >= 64
typedef unsigned __int64 int64;
typedef unsigned __int64 uint64;
typedef signed __int64 sint64;
#else
#error __int64 not supported
#endif
#else
typedef unsigned long long int64;
typedef unsigned long long uint64;
typedef signed long long sint64;
//typedef __u64 int64;
//typedef __u64 uint64;
//typedef __s64 sint64;
#endif
#ifndef __cplusplus
typedef enum { true, false } bool;
#endif
typedef unsigned long ulong;
typedef unsigned short ushort;
typedef unsigned char uchar;
typedef const char Const_char; //for perl XS
#ifdef WIN32
#define snprintf _snprintf
#if (_MSC_VER < 1500)
#define vsnprintf _vsnprintf
#endif
#define strncasecmp _strnicmp
#define strcasecmp _stricmp
typedef void ThreadReturnType;
// #define THREAD_RETURN(x) return;
#define THREAD_RETURN(x) _endthread(); return;
#else
typedef void* ThreadReturnType;
// typedef int SOCKET;
#define THREAD_RETURN(x) return(x);
#endif
#define safe_delete(d) if(d) { delete d; d=0; }
#define safe_delete_array(d) if(d) { delete[] d; d=0; }
#define L32(i) ((int32) i)
#define H32(i) ((int32) (i >> 32))
#define L16(i) ((int16) i)
#ifndef WIN32
// More WIN32 compatability
typedef unsigned long DWORD;
typedef unsigned char BYTE;
typedef char CHAR;
typedef unsigned short WORD;
typedef float FLOAT;
typedef FLOAT *PFLOAT;
typedef BYTE *PBYTE,*LPBYTE;
typedef int *PINT,*LPINT;
typedef WORD *PWORD,*LPWORD;
typedef long *LPLONG, LONG;
typedef DWORD *PDWORD,*LPDWORD;
typedef int INT;
typedef unsigned int UINT,*PUINT,*LPUINT;
#endif
#ifdef WIN32
#define DLLFUNC extern "C" __declspec(dllexport)
#else
#define DLLFUNC extern "C"
#endif
#endif