Compare commits

...

71 Commits

Author SHA1 Message Date
Marco Tylus
826f20ef04
Merge 8935c520c0 into 553a59c808 2026-01-18 06:32:29 +01:00
fallenoak
553a59c808
chore(object): tidy up return type for ClntObjMgrAllocObject
Some checks are pending
Push / ${{ matrix.build.system_name }} / ${{ matrix.build.build_type }} / ${{ matrix.build.compiler_name }} (map[build_type:Release cc:cl compiler_name:MSVC cxx:cl os:windows-latest system_name:Windows test_path:WhoaTest]) (push) Waiting to run
Push / ${{ matrix.build.system_name }} / ${{ matrix.build.build_type }} / ${{ matrix.build.compiler_name }} (map[build_type:Release cc:clang compiler_name:Clang cxx:clang++ os:macos-latest system_name:macOS test_path:WhoaTest]) (push) Waiting to run
Push / ${{ matrix.build.system_name }} / ${{ matrix.build.build_type }} / ${{ matrix.build.compiler_name }} (map[build_type:Release cc:gcc compiler_name:GCC cxx:g++ os:ubuntu-latest system_name:Linux test_path:WhoaTest]) (push) Waiting to run
2026-01-17 20:34:46 -06:00
fallenoak
2efef87898
feat(object): set disable time in CGObject_C::Disable 2026-01-17 20:29:40 -06:00
fallenoak
c92f1b8de8
feat(world): add time handling functions to CWorld 2026-01-17 19:20:30 -06:00
fallenoak
c9aaa245c9
feat(event): dispatch tick events in main processing loop
Some checks are pending
Push / ${{ matrix.build.system_name }} / ${{ matrix.build.build_type }} / ${{ matrix.build.compiler_name }} (map[build_type:Release cc:cl compiler_name:MSVC cxx:cl os:windows-latest system_name:Windows test_path:WhoaTest]) (push) Waiting to run
Push / ${{ matrix.build.system_name }} / ${{ matrix.build.build_type }} / ${{ matrix.build.compiler_name }} (map[build_type:Release cc:clang compiler_name:Clang cxx:clang++ os:macos-latest system_name:macOS test_path:WhoaTest]) (push) Waiting to run
Push / ${{ matrix.build.system_name }} / ${{ matrix.build.build_type }} / ${{ matrix.build.compiler_name }} (map[build_type:Release cc:gcc compiler_name:GCC cxx:g++ os:ubuntu-latest system_name:Linux test_path:WhoaTest]) (push) Waiting to run
2026-01-16 19:33:17 -06:00
fallenoak
43dcfae6b0
feat(object): add type-specific cleanup queues to ClntObjMgr 2026-01-16 16:56:27 -06:00
fallenoak
0b0b7927aa
feat(object): set disabled flag in CGObject_C::Disable
Some checks are pending
Push / ${{ matrix.build.system_name }} / ${{ matrix.build.build_type }} / ${{ matrix.build.compiler_name }} (map[build_type:Release cc:cl compiler_name:MSVC cxx:cl os:windows-latest system_name:Windows test_path:WhoaTest]) (push) Waiting to run
Push / ${{ matrix.build.system_name }} / ${{ matrix.build.build_type }} / ${{ matrix.build.compiler_name }} (map[build_type:Release cc:clang compiler_name:Clang cxx:clang++ os:macos-latest system_name:macOS test_path:WhoaTest]) (push) Waiting to run
Push / ${{ matrix.build.system_name }} / ${{ matrix.build.build_type }} / ${{ matrix.build.compiler_name }} (map[build_type:Release cc:gcc compiler_name:GCC cxx:g++ os:ubuntu-latest system_name:Linux test_path:WhoaTest]) (push) Waiting to run
2026-01-16 08:41:50 -06:00
fallenoak
de2bea7129
feat(object): implement UpdateOutOfRangeObjects 2026-01-15 22:49:24 -06:00
fallenoak
ccca191048
feat(object): implement OnObjectDestroy 2026-01-15 21:41:06 -06:00
fallenoak
cd3585ca42
feat(object): add HandleObjectOutOfRangePass2 2026-01-15 21:24:45 -06:00
fallenoak
13ec1d7eef
feat(object): add HandleObjectOutOfRangePass1 2026-01-15 21:04:43 -06:00
fallenoak
f4ca99ac15
feat(object): add OUT_OF_RANGE_TYPE 2026-01-15 20:15:29 -06:00
fallenoak
ca3888f38e
feat(object): add CGObject_C::SetObjectLocked 2026-01-15 16:31:42 -06:00
fallenoak
a1541725f2
feat(object): add CGObject_C::IsObjectLocked 2026-01-15 16:27:40 -06:00
fallenoak
ba0baf1688
feat(object): add CGObject_C::IsInReenable 2026-01-15 16:24:45 -06:00
fallenoak
a43ab56644
feat(object): partially implement CGObject_C::Reenable 2026-01-15 16:21:41 -06:00
fallenoak
e2bfef907a
chore(object): rename parameter for clarity 2026-01-15 16:00:30 -06:00
fallenoak
361d327f30
feat(object): implement CGObject_C::SetDisablePending 2026-01-15 15:57:17 -06:00
fallenoak
8a062e5631
chore(object): correct params for ClntObjMgrObjectPtr 2026-01-14 23:43:56 -06:00
fallenoak
2bb8da6971
feat(object): add ClntObjMgrObjectPtr 2026-01-14 23:37:40 -06:00
fallenoak
7e994ff195
feat(object): add remaining members to CGPlayerData 2026-01-14 16:42:07 -06:00
fallenoak
3332062f86
feat(object): handle disabled objects in GetUpdateObject 2026-01-13 23:04:21 -06:00
fallenoak
56f645fe3b
feat(object): link newly created objects to visible list 2026-01-13 22:34:44 -06:00
fallenoak
72d5247563
feat(object): implement UpdateInRangeObjects 2026-01-13 21:36:53 -06:00
fallenoak
ae911d94ad
chore(object): move InitObject to util 2026-01-13 21:18:34 -06:00
fallenoak
d18a479bfb
chore(object): move GetUpdateObject to util 2026-01-13 21:05:29 -06:00
fallenoak
8615757d54
feat(object): implement UpdateObject 2026-01-13 21:03:07 -06:00
fallenoak
b7c3735e7f
fix(object): correct types for various members of CGUnitData 2026-01-13 20:41:59 -06:00
fallenoak
f44ba4bf63
fix(object): properly skip move updates in ObjectUpdateFirstPass 2026-01-13 19:54:53 -06:00
fallenoak
082bc06c69
feat(object): handle existing objects in CreateObject 2026-01-13 19:54:04 -06:00
fallenoak
1e13e33f2a
feat(object): add CClientMoveUpdate::Skip 2026-01-13 19:50:39 -06:00
fallenoak
31fca17064
fix(object): correct read in CClientObjCreate::Get 2026-01-13 19:24:35 -06:00
fallenoak
97d386f745
feat(object): add CClientObjCreate::Skip 2026-01-13 19:21:56 -06:00
fallenoak
b26db42994
feat(object): stub CGObject_C::Reenable 2026-01-13 19:21:19 -06:00
fallenoak
e29b584da3
feat(object): partially implement GetUpdateObject 2026-01-13 17:45:59 -06:00
fallenoak
f722040986
feat(object): stub CGObject_C::SetDisablePending 2026-01-13 17:45:37 -06:00
fallenoak
4f9cceda79
feat(object): add FindActiveObject 2026-01-13 17:44:48 -06:00
fallenoak
a90933f635
feat(util): add operator== overloads to CHashKeyGUID 2026-01-13 15:53:39 -06:00
fallenoak
4dd9921a4f
feat(object): add ClntObjMgrLinkInNewObject 2026-01-13 15:52:50 -06:00
fallenoak
2fc113d5b0
feat(object): partially implement ObjectUpdateHandler 2026-01-12 21:43:35 -06:00
fallenoak
43ad9fc8a6
feat(object): add ctors to base object classes 2026-01-12 21:42:13 -06:00
fallenoak
be264e22bf
feat(object): add CClientObjCreate 2026-01-12 21:17:23 -06:00
fallenoak
775320a7fc
feat(object): add CClientMoveUpdate 2026-01-12 20:34:21 -06:00
fallenoak
8333530d65
fix(object): correct flag check in spline reader 2026-01-12 20:32:49 -06:00
fallenoak
4114f1ee16
feat(object): add CMovementStatus 2026-01-12 20:27:55 -06:00
fallenoak
1cc8c3ce40
feat(object): add CMoveSpline 2026-01-12 19:59:53 -06:00
fallenoak
c59d0de8b5
feat(util): add wip C3Spline class to util 2026-01-12 19:45:31 -06:00
fallenoak
364fba9f34
chore(util): restructure guid code and add WOWGUID typedef 2026-01-12 09:00:56 -06:00
fallenoak
5e4ca1980d
feat(object): add FillInPartialObjectData 2026-01-11 23:49:49 -06:00
fallenoak
6d8510b4a7
feat(util): add SmartGUID 2026-01-11 23:48:16 -06:00
fallenoak
9162978b4f
feat(object): add CGObject_C::SetBlock 2026-01-11 22:36:12 -06:00
fallenoak
8066b4c053
chore(build): update common 2026-01-11 22:18:26 -06:00
fallenoak
abdb5c364c
chore(build): update common 2026-01-11 22:08:20 -06:00
fallenoak
47e0dbb028
chore(object): tidy up ExtractDirtyMasks 2026-01-11 20:38:20 -06:00
fallenoak
d1b764903c
feat(object): add ExtractDirtyMasks 2026-01-11 20:26:59 -06:00
fallenoak
8ab88329bb
chore(object): restructure mirror-oriented util functions 2026-01-11 20:00:44 -06:00
fallenoak
860d6978fd
feat(object): add GetNumDwordBlocks 2026-01-11 16:01:28 -06:00
Tristan Cormier
bd0d7c63d2 feat(connection): implement character deletion message handlers 2026-01-11 15:57:29 -06:00
fallenoak
68ab5ccced
feat(object): add IncTypeID 2026-01-11 14:15:44 -06:00
fallenoak
2695b584fd
feat(object): add partial layout for CGPlayerData 2026-01-11 13:15:18 -06:00
fallenoak
e9cb989eb7
fix(glue): name IDLE_DELETE_CHARACTER in GLUE_IDLE_STATE 2026-01-11 11:50:38 -06:00
Tristan Cormier
92adcefef8 feat(glue): add CGlueMgr::PollDeleteCharacter 2026-01-10 23:18:55 -06:00
fallenoak
0c3bbc4336
feat(object): add storage management functions to base object classes 2026-01-10 23:05:43 -06:00
aomizu
8935c520c0 feat: Add texture matrix transform support to Metal shaders for animated textures 2025-12-26 17:03:37 +09:00
aomizu
7cf7127810 feat: Implement color animation in Metal shaders by using diffuse and emissive vertex constants for output color. 2025-12-25 15:11:18 +09:00
aomizu
8fb51991e0 revert: remove non-metal shader init from Client.cpp 2025-12-25 13:24:07 +09:00
aomizu
7fdd22545f feat: Convert GxTex_Argb4444 textures to RGBA8 during Metal upload to simplify handling 2025-12-25 13:10:25 +09:00
aomizu
15eafe92d7 feat: Implement fog and point size in Metal shaders and refine render state processing for textures and other states. 2025-12-25 13:10:25 +09:00
aomizu
1ad3679f90 feat: Implement initial Metal graphics device with comprehensive shader system and pipeline management. 2025-12-25 13:10:25 +09:00
aomizu
81970958a8 feat: Add debug rendering pipeline to draw a triangle in the Metal backend. 2025-12-25 13:10:25 +09:00
aomizu
a9cad5238d init metal backend 2025-12-25 13:10:25 +09:00
89 changed files with 4200 additions and 92 deletions

@ -1 +1 @@
Subproject commit 48a78025ef77faac80faa30c116f3ced4bbd9251 Subproject commit 39cf7976a899b4f9a1290d0afdbd5011e4af9ac1

View File

@ -32,6 +32,8 @@ if(WHOA_SYSTEM_MAC)
"-framework AppKit" "-framework AppKit"
"-framework Carbon" "-framework Carbon"
"-framework IOKit" "-framework IOKit"
"-framework Metal"
"-framework QuartzCore"
) )
install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/mac/MainMenu.nib DESTINATION "bin") install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/mac/MainMenu.nib DESTINATION "bin")

View File

@ -0,0 +1,9 @@
#ifndef APP_MAC_ENGINE_MTL_LAYER_VIEW_H
#define APP_MAC_ENGINE_MTL_LAYER_VIEW_H
#include "app/mac/EngineGLLayerView.h"
@interface EngineMTLLayerView : EngineGLLayerView
@end
#endif

View File

@ -0,0 +1,36 @@
#include "app/mac/EngineMTLLayerView.h"
#import <QuartzCore/CAMetalLayer.h>
@implementation EngineMTLLayerView
- (CALayer*)makeBackingLayer {
return [CAMetalLayer layer];
}
- (id)initWithFrame:(NSRect)frame glWindow:(GLWindow*)window {
self = [super initWithFrame:frame glWindow:window];
if (self) {
[self setWantsLayer:YES];
}
return self;
}
- (void)drawRect:(NSRect)dirtyRect {
// Rendering is driven by CGxDeviceMTL.
}
- (void)update {
[super update];
if (![self.layer isKindOfClass:[CAMetalLayer class]]) {
return;
}
CAMetalLayer* layer = (CAMetalLayer*)self.layer;
CGSize size = [self convertSizeToBacking:self.bounds.size];
layer.drawableSize = size;
}
@end

View File

@ -1,7 +1,9 @@
#include "app/mac/View.h" #include "app/mac/View.h"
#include "app/mac/EngineGLLayerView.h" #include "app/mac/EngineGLLayerView.h"
#include "app/mac/EngineMTLLayerView.h"
#include "app/mac/WindowCallbacks.h" #include "app/mac/WindowCallbacks.h"
#include "gx/gll/GLWindow.h" #include "gx/gll/GLWindow.h"
#include "gx/Device.hpp"
GLWindowCallbacks EngineViewCallbacks = { GLWindowCallbacks EngineViewCallbacks = {
&MacOnResized, &MacOnResized,
@ -23,5 +25,9 @@ void AssignEngineViewCallbacks(GLWindowCallbacks* callbacks) {
} }
Class GetEngineViewClass() { Class GetEngineViewClass() {
if (GxDevApi() == GxApi_Metal) {
return [EngineMTLLayerView class];
}
return [EngineGLLayerView class]; return [EngineGLLayerView class];
} }

View File

@ -2,6 +2,7 @@
#include "app/mac/MacClient.h" #include "app/mac/MacClient.h"
#include "event/Input.hpp" #include "event/Input.hpp"
#include "gx/gll/CGxDeviceGLL.hpp" #include "gx/gll/CGxDeviceGLL.hpp"
#include "gx/mtl/CGxDeviceMTL.hpp"
#include "gx/Device.hpp" #include "gx/Device.hpp"
#include "gx/Window.hpp" #include "gx/Window.hpp"
#include <bc/Debug.hpp> #include <bc/Debug.hpp>
@ -171,7 +172,11 @@ void MacOnResized(int32_t width, int32_t height, bool a3) {
return; return;
} }
static_cast<CGxDeviceGLL*>(g_theGxDevicePtr)->Resize(width, height); if (GxDevApi() == GxApi_GLL) {
static_cast<CGxDeviceGLL*>(g_theGxDevicePtr)->Resize(width, height);
} else if (GxDevApi() == GxApi_Metal) {
static_cast<CGxDeviceMTL*>(g_theGxDevicePtr)->Resize(width, height);
}
OsQueuePut(OS_INPUT_SIZE, width, height, 0, 0); OsQueuePut(OS_INPUT_SIZE, width, height, 0, 0);

View File

@ -520,8 +520,9 @@ void WowClientDestroy() {
} }
void WowClientInit() { void WowClientInit() {
EventRegister(EVENT_ID_TICK, reinterpret_cast<EVENTHANDLERFUNC>(&CWorld::OnTick));
// TODO // TODO
// EventRegister(EVENT_ID_5, (int)sub_4020E0);
// _cfltcvt_init_0(); // _cfltcvt_init_0();
ClientRegisterConsoleCommands(); ClientRegisterConsoleCommands();

View File

@ -6,6 +6,7 @@
#include "gx/Adapter.hpp" #include "gx/Adapter.hpp"
#include "gx/Device.hpp" #include "gx/Device.hpp"
#include <storm/Array.hpp> #include <storm/Array.hpp>
#include <cstdlib>
#include <cstring> #include <cstring>
static CGxDevice* s_device; static CGxDevice* s_device;
@ -417,6 +418,13 @@ void ConsoleDeviceInitialize(const char* title) {
api = GxApi_GLL; api = GxApi_GLL;
#endif #endif
#if defined(WHOA_SYSTEM_MAC)
const char* apiOverride = getenv("WHOA_GX_API");
if (apiOverride && !strcmp(apiOverride, "metal")) {
api = GxApi_Metal;
}
#endif
s_device = GxDevCreate(api, OsWindowProc, format); s_device = GxDevCreate(api, OsWindowProc, format);
// TODO // TODO

View File

@ -286,12 +286,10 @@ int32_t SchedulerThreadProcProcess(uint32_t a1) {
} }
} }
uint32_t v9 = (currTime - context->m_schedLastIdle); float elapsedSec = (currTime - context->m_schedLastIdle) * 0.001;
context->m_schedLastIdle = currTime; context->m_schedLastIdle = currTime;
double elapsedSec = v9 * 0.001;
// TODO SynthesizeTick(context, currTime, elapsedSec);
// FrameTime::Update(currTime, elapsedSec);
IEvtTimerDispatch(context); IEvtTimerDispatch(context);

View File

@ -91,3 +91,17 @@ void SynthesizePoll(EvtContext* context) {
IEvtQueueDispatch(context, EVENT_ID_POLL, nullptr); IEvtQueueDispatch(context, EVENT_ID_POLL, nullptr);
} }
void SynthesizeTick(EvtContext* context, uint32_t currTime, float elapsedSec) {
context->m_critsect.Enter();
bool closed = context->m_schedState == EvtContext::SCHEDSTATE_CLOSED;
context->m_critsect.Leave();
if (closed) {
return;
}
EVENT_DATA_TICK data = { elapsedSec, currTime };
IEvtQueueDispatch(context, EVENT_ID_TICK, &data);
}

View File

@ -15,4 +15,6 @@ void SynthesizePaint(EvtContext* context);
void SynthesizePoll(EvtContext* context); void SynthesizePoll(EvtContext* context);
void SynthesizeTick(EvtContext* context, uint32_t currTime, float elapsedSec);
#endif #endif

View File

@ -12,7 +12,7 @@ enum EVENTID {
EVENT_ID_FOCUS = 2, EVENT_ID_FOCUS = 2,
EVENT_ID_CLOSE = 3, EVENT_ID_CLOSE = 3,
EVENT_ID_DESTROY = 4, EVENT_ID_DESTROY = 4,
EVENT_ID_5 = 5, EVENT_ID_TICK = 5,
EVENT_ID_IDLE = 6, EVENT_ID_IDLE = 6,
EVENT_ID_POLL = 7, EVENT_ID_POLL = 7,
EVENT_ID_INITIALIZE = 8, EVENT_ID_INITIALIZE = 8,
@ -259,4 +259,9 @@ struct EVENT_DATA_SIZE {
int32_t h; int32_t h;
}; };
struct EVENT_DATA_TICK {
float tickTimeSec;
uint32_t curTimeMs;
};
#endif #endif

View File

@ -410,6 +410,11 @@ int32_t CGlueMgr::Idle(const void* a1, void* a2) {
break; break;
} }
case IDLE_DELETE_CHARACTER: {
CGlueMgr::PollDeleteCharacter(msg, complete, result);
break;
}
case IDLE_ENTER_WORLD: { case IDLE_ENTER_WORLD: {
CGlueMgr::PollEnterWorld(); CGlueMgr::PollEnterWorld();
break; break;
@ -775,6 +780,34 @@ void CGlueMgr::PollCharacterList(const char* msg, int32_t complete, int32_t resu
} }
} }
void CGlueMgr::PollDeleteCharacter(const char* msg, int32_t complete, int32_t result) {
FrameScript_SignalEvent(UPDATE_STATUS_DIALOG, "%s", msg);
if (CGlueMgr::HandleBattlenetDisconnect()) {
CGlueMgr::SetIdleState(IDLE_NONE);
}
if (!complete) {
return;
}
// Error
if (result == 0) {
FrameScript_SignalEvent(OPEN_STATUS_DIALOG, "%s%s", "OKAY", msg);
CGlueMgr::SetIdleState(IDLE_NONE);
return;
}
// Success
FrameScript_SignalEvent(SELECT_FIRST_CHARACTER, nullptr);
CGlueMgr::GetCharacterList();
}
void CGlueMgr::PollEnterWorld() { void CGlueMgr::PollEnterWorld() {
if (!LoadingScreenDrawing()) { if (!LoadingScreenDrawing()) {
return; return;
@ -1112,7 +1145,7 @@ void CGlueMgr::StatusDialogClick() {
case IDLE_REALM_LIST: case IDLE_REALM_LIST:
case IDLE_5: case IDLE_5:
case IDLE_6: case IDLE_DELETE_CHARACTER:
case IDLE_ENTER_WORLD: { case IDLE_ENTER_WORLD: {
ClientServices::Connection()->Cancel(2); ClientServices::Connection()->Cancel(2);
CGlueMgr::SetIdleState(IDLE_NONE); CGlueMgr::SetIdleState(IDLE_NONE);

View File

@ -21,7 +21,7 @@ class CGlueMgr {
IDLE_CHARACTER_LIST = 3, IDLE_CHARACTER_LIST = 3,
IDLE_REALM_LIST = 4, IDLE_REALM_LIST = 4,
IDLE_5 = 5, IDLE_5 = 5,
IDLE_6 = 6, IDLE_DELETE_CHARACTER = 6,
IDLE_7 = 7, IDLE_7 = 7,
IDLE_8 = 8, IDLE_8 = 8,
IDLE_9 = 9, IDLE_9 = 9,
@ -80,6 +80,7 @@ class CGlueMgr {
static int32_t OnKickReasonMsg(void* param, NETMESSAGE msgId, uint32_t time, CDataStore* msg); static int32_t OnKickReasonMsg(void* param, NETMESSAGE msgId, uint32_t time, CDataStore* msg);
static void PollAccountLogin(int32_t errorCode, const char* msg, int32_t complete, int32_t result, WOWCS_OPS op); static void PollAccountLogin(int32_t errorCode, const char* msg, int32_t complete, int32_t result, WOWCS_OPS op);
static void PollCharacterList(const char* msg, int32_t complete, int32_t result, int32_t errorCode); static void PollCharacterList(const char* msg, int32_t complete, int32_t result, int32_t errorCode);
static void PollDeleteCharacter(const char* msg, int32_t complete, int32_t result);
static void PollEnterWorld(); static void PollEnterWorld();
static void PollLoginServerLogin(); static void PollLoginServerLogin();
static void PollRealmList(const char* msg, int32_t complete, int32_t result, WOWCS_OPS op); static void PollRealmList(const char* msg, int32_t complete, int32_t result, WOWCS_OPS op);

View File

@ -18,6 +18,7 @@
#if defined(WHOA_SYSTEM_MAC) #if defined(WHOA_SYSTEM_MAC)
#include "gx/gll/CGxDeviceGLL.hpp" #include "gx/gll/CGxDeviceGLL.hpp"
#include "gx/mtl/CGxDeviceMTL.hpp"
#include "gx/mac/Display.hpp" #include "gx/mac/Display.hpp"
#include <ApplicationServices/ApplicationServices.h> #include <ApplicationServices/ApplicationServices.h>
#include <OpenGL/OpenGL.h> #include <OpenGL/OpenGL.h>
@ -117,6 +118,8 @@ int32_t CGxDevice::AdapterFormats(EGxApi api, TSGrowableArray<CGxFormat>& adapte
CGxDevice::OpenGlAdapterFormats(adapterFormats); CGxDevice::OpenGlAdapterFormats(adapterFormats);
} else if (api == GxApi_GLL) { } else if (api == GxApi_GLL) {
CGxDevice::GLLAdapterFormats(adapterFormats); CGxDevice::GLLAdapterFormats(adapterFormats);
} else if (api == GxApi_Metal) {
CGxDevice::OpenGlAdapterFormats(adapterFormats);
} }
#elif defined(WHOA_SYSTEM_LINUX) #elif defined(WHOA_SYSTEM_LINUX)
@ -228,6 +231,11 @@ CGxDevice* CGxDevice::NewGLL() {
auto m = SMemAlloc(sizeof(CGxDeviceGLL), __FILE__, __LINE__, 0x0); auto m = SMemAlloc(sizeof(CGxDeviceGLL), __FILE__, __LINE__, 0x0);
return new (m) CGxDeviceGLL(); return new (m) CGxDeviceGLL();
} }
CGxDevice* CGxDevice::NewMTL() {
auto m = SMemAlloc(sizeof(CGxDeviceMTL), __FILE__, __LINE__, 0x0);
return new (m) CGxDeviceMTL();
}
#endif #endif
CGxDevice* CGxDevice::NewOpenGl() { CGxDevice* CGxDevice::NewOpenGl() {

View File

@ -70,6 +70,7 @@ class CGxDevice {
#endif #endif
#if defined(WHOA_SYSTEM_MAC) #if defined(WHOA_SYSTEM_MAC)
static CGxDevice* NewGLL(); static CGxDevice* NewGLL();
static CGxDevice* NewMTL();
#endif #endif
static CGxDevice* NewOpenGl(); static CGxDevice* NewOpenGl();
static void OpenGlAdapterFormats(TSGrowableArray<CGxFormat>& adapterFormats); static void OpenGlAdapterFormats(TSGrowableArray<CGxFormat>& adapterFormats);

View File

@ -20,6 +20,7 @@ if(WHOA_SYSTEM_MAC)
file(GLOB MAC_SOURCES file(GLOB MAC_SOURCES
"gll/*.cpp" "gll/*.cpp"
"gll/*.mm" "gll/*.mm"
"mtl/*.mm"
"mac/*.cpp" "mac/*.cpp"
) )

View File

@ -24,6 +24,8 @@ CGxDevice* GxDevCreate(EGxApi api, int32_t (*windowProc)(void* window, uint32_t
device = CGxDevice::NewOpenGl(); device = CGxDevice::NewOpenGl();
} else if (api == GxApi_GLL) { } else if (api == GxApi_GLL) {
device = CGxDevice::NewGLL(); device = CGxDevice::NewGLL();
} else if (api == GxApi_Metal) {
device = CGxDevice::NewMTL();
} else { } else {
// Error // Error
} }

View File

@ -35,7 +35,8 @@ enum EGxApi {
GxApi_D3d10 = 3, GxApi_D3d10 = 3,
GxApi_D3d11 = 4, GxApi_D3d11 = 4,
GxApi_GLL = 5, GxApi_GLL = 5,
GxApis_Last = 6 GxApi_Metal = 6,
GxApis_Last = 7
}; };
enum EGxBlend { enum EGxBlend {

View File

@ -0,0 +1,81 @@
#ifndef GX_MTL_C_GX_DEVICE_MTL_HPP
#define GX_MTL_C_GX_DEVICE_MTL_HPP
#include "gx/CGxDevice.hpp"
#include "gx/gll/GLWindow.h"
class CGxBatch;
class CGxShader;
class CGxDeviceMTL : public CGxDevice {
public:
// Member variables
GLWindow m_window;
// Virtual member functions
void ITexMarkAsUpdated(CGxTex*) override;
void IRsSendToHw(EGxRenderState) override;
int32_t DeviceCreate(int32_t (*windowProc)(void* window, uint32_t message, uintptr_t wparam, intptr_t lparam), const CGxFormat&) override;
int32_t DeviceSetFormat(const CGxFormat&) override;
void* DeviceWindow() override;
void DeviceWM(EGxWM wm, uintptr_t param1, uintptr_t param2) override {};
void CapsWindowSize(CRect&) override;
void CapsWindowSizeInScreenCoords(CRect& dst) override;
void ScenePresent() override;
void SceneClear(uint32_t, CImVector) override;
void Draw(CGxBatch* batch, int32_t indexed) override;
void PoolSizeSet(CGxPool*, uint32_t) override;
char* BufLock(CGxBuf*) override;
int32_t BufUnlock(CGxBuf*, uint32_t) override;
void BufData(CGxBuf* buf, const void* data, size_t size, uintptr_t offset) override;
void TexDestroy(CGxTex* texId) override;
void IShaderCreate(CGxShader*) override;
void ShaderCreate(CGxShader*[], EGxShTarget, const char*, const char*, int32_t) override;
int32_t StereoEnabled(void) override;
void XformSetProjection(const C44Matrix& matrix) override;
// Member functions
CGxDeviceMTL();
void Resize(uint32_t width, uint32_t height);
private:
void ISetCaps(const CGxFormat& format);
void EnsureLibrary();
void BeginFrame();
void* GetPipeline(EGxVertexBufferFormat format, bool useColor, bool useSkin, bool useTex, int32_t blendMode);
void* GetPoolBuffer(CGxPool* pool);
void ITexCreate(CGxTex* texId);
void ITexUpload(CGxTex* texId);
void* GetTexture(CGxTex* texId);
void* GetSampler(CGxTex* texId);
void EnsureFallbackTexture();
void EnsureDepthTexture(uint32_t width, uint32_t height);
void* GetDepthState(bool depthTest, bool depthWrite, uint32_t depthFunc);
void* m_device = nullptr;
void* m_commandQueue = nullptr;
void* m_layer = nullptr;
void* m_shaderLibrary = nullptr;
void* m_pipelineColor[GxVertexBufferFormats_Last][GxBlends_Last] = {};
void* m_pipelineSolid[GxVertexBufferFormats_Last][GxBlends_Last] = {};
void* m_pipelineSkin[GxVertexBufferFormats_Last][GxBlends_Last] = {};
void* m_pipelineColorTex[GxVertexBufferFormats_Last][GxBlends_Last] = {};
void* m_pipelineSolidTex[GxVertexBufferFormats_Last][GxBlends_Last] = {};
void* m_pipelineSkinTex[GxVertexBufferFormats_Last][GxBlends_Last] = {};
void* m_pipelineColorTex2[GxVertexBufferFormats_Last][GxBlends_Last] = {};
void* m_pipelineSolidTex2[GxVertexBufferFormats_Last][GxBlends_Last] = {};
void* m_pipelineSkinTex2[GxVertexBufferFormats_Last][GxBlends_Last] = {};
void* m_frameCommandBuffer = nullptr;
void* m_frameEncoder = nullptr;
void* m_frameDrawable = nullptr;
uint32_t m_frameHasDraw = 0;
uint32_t m_clearMask = 0;
uint32_t m_clearColor = 0;
void* m_fallbackTexture = nullptr;
void* m_fallbackSampler = nullptr;
void* m_depthTexture = nullptr;
uint32_t m_depthWidth = 0;
uint32_t m_depthHeight = 0;
void* m_depthStates[2][2][4] = {};
};
#endif

1855
src/gx/mtl/CGxDeviceMTL.mm Normal file

File diff suppressed because it is too large Load Diff

View File

@ -104,6 +104,10 @@ void ClientConnection::GetRealmList() {
} }
} }
void ClientConnection::HandleCharacterDelete(uint8_t result) {
this->Complete(result == 71, result);
}
int32_t ClientConnection::HandleConnect() { int32_t ClientConnection::HandleConnect() {
this->Complete(1, 5); this->Complete(1, 5);

View File

@ -22,6 +22,7 @@ class ClientConnection : public RealmConnection {
// Virtual member functions // Virtual member functions
virtual int32_t HandleConnect(); virtual int32_t HandleConnect();
virtual void HandleCharacterDelete(uint8_t result);
// Member functions // Member functions
ClientConnection(RealmResponse* realmResponse) ClientConnection(RealmResponse* realmResponse)

View File

@ -30,7 +30,7 @@ int32_t RealmConnection::MessageHandler(void* param, NETMESSAGE msgId, uint32_t
} }
case SMSG_DELETE_CHAR: { case SMSG_DELETE_CHAR: {
// TODO result = connection->DeleteCharHandler(msgId, time, msg);
break; break;
} }
@ -294,6 +294,15 @@ int32_t RealmConnection::HandleCharEnum(uint32_t msgId, uint32_t time, CDataStor
return 1; return 1;
} }
int32_t RealmConnection::DeleteCharHandler(uint32_t msgId, uint32_t time, CDataStore* msg) {
uint8_t result;
msg->Get(result);
this->HandleCharacterDelete(result);
return 1;
}
void RealmConnection::RequestCharacterEnum() { void RealmConnection::RequestCharacterEnum() {
CDataStore msg; CDataStore msg;

View File

@ -46,11 +46,13 @@ class RealmConnection : public NetClient {
// Virtual member functions // Virtual member functions
virtual int32_t HandleAuthChallenge(AuthenticationChallenge* challenge); virtual int32_t HandleAuthChallenge(AuthenticationChallenge* challenge);
virtual void HandleCharacterDelete(uint8_t result) = 0;
// Member functions // Member functions
RealmConnection(RealmResponse* realmResponse); RealmConnection(RealmResponse* realmResponse);
int32_t HandleAuthResponse(uint32_t msgId, uint32_t time, CDataStore* msg); int32_t HandleAuthResponse(uint32_t msgId, uint32_t time, CDataStore* msg);
int32_t HandleCharEnum(uint32_t msgId, uint32_t time, CDataStore* msg); int32_t HandleCharEnum(uint32_t msgId, uint32_t time, CDataStore* msg);
int32_t DeleteCharHandler(uint32_t msgId, uint32_t time, CDataStore* msg);
void RequestCharacterEnum(); void RequestCharacterEnum();
void RequestCharacterLogin(uint64_t guid, int32_t a2); void RequestCharacterLogin(uint64_t guid, int32_t a2);
void SetSelectedRealm(uint32_t a2, uint32_t a3, uint32_t a4); void SetSelectedRealm(uint32_t a2, uint32_t a3, uint32_t a4);

View File

@ -1,6 +1,7 @@
file(GLOB PRIVATE_SOURCES file(GLOB PRIVATE_SOURCES
"*.cpp" "*.cpp"
"client/*.cpp" "client/*.cpp"
"movement/*.cpp"
) )
add_library(object STATIC add_library(object STATIC

View File

@ -72,6 +72,12 @@ enum OBJECT_TYPE_ID {
// TODO // TODO
}; };
enum OUT_OF_RANGE_TYPE {
OUT_OF_RANGE_0 = 0,
OUT_OF_RANGE_1 = 1,
OUT_OF_RANGE_2 = 2,
};
enum SHEATHE_TYPE { enum SHEATHE_TYPE {
SHEATHE_0 = 0, SHEATHE_0 = 0,
SHEATHE_1 = 1, SHEATHE_1 = 1,

View File

@ -0,0 +1,32 @@
#include "object/client/CClientMoveUpdate.hpp"
void CClientMoveUpdate::Skip(CDataStore* msg) {
uint32_t moveFlags = CMovementStatus::Skip(msg);
void* data;
msg->GetDataInSitu(data, 9 * sizeof(float));
if (moveFlags & 0x8000000) {
CMoveSpline::Skip(msg);
}
}
CDataStore& operator>>(CDataStore& msg, CClientMoveUpdate& move) {
msg >> move.status;
msg.Get(move.float60);
msg.Get(move.float64);
msg.Get(move.float68);
msg.Get(move.float6C);
msg.Get(move.float70);
msg.Get(move.float74);
msg.Get(move.float78);
msg.Get(move.float7C);
msg.Get(move.float80);
if (move.status.moveFlags & 0x8000000) {
msg >> move.spline;
}
return msg;
}

View File

@ -0,0 +1,27 @@
#ifndef OBJECT_CLIENT_C_CLIENT_MOVE_UPDATE_HPP
#define OBJECT_CLIENT_C_CLIENT_MOVE_UPDATE_HPP
#include "object/movement/CMovementStatus.hpp"
#include "object/movement/CMoveSpline.hpp"
#include <common/datastore/CDataStore.hpp>
struct CClientMoveUpdate {
CMovementStatus status;
float float60;
float float64;
float float68;
float float6C;
float float70;
float float74;
float float78;
float float7C;
float float80;
// TODO
CMoveSpline spline;
static void Skip(CDataStore* msg);
};
CDataStore& operator>>(CDataStore& msg, CClientMoveUpdate& move);
#endif

View File

@ -0,0 +1,133 @@
#include "object/client/CClientObjCreate.hpp"
#include "util/DataStore.hpp"
#include "util/GUID.hpp"
#include "util/Unimplemented.hpp"
#include <common/DataStore.hpp>
void CClientObjCreate::Skip(CDataStore* msg) {
uint16_t flags;
msg->Get(flags);
if (flags & 0x20) {
CClientMoveUpdate::Skip(msg);
} else if (flags & 0x100) {
SmartGUID guid;
*msg >> guid;
C3Vector position28;
*msg >> position28;
C3Vector position18;
*msg >> position18;
float facing34;
msg->Get(facing34);
float facing24;
msg->Get(facing24);
} else if (flags & 0x40) {
C3Vector position28;
*msg >> position28;
float facing34;
msg->Get(facing34);
}
if (flags & 0x8) {
uint32_t uint2AC;
msg->Get(uint2AC);
}
if (flags & 0x10) {
uint32_t uint2B0;
msg->Get(uint2B0);
}
if (flags & 0x4) {
SmartGUID guid2B8;
*msg >> guid2B8;
}
if (flags & 0x2) {
uint32_t uint2C0;
msg->Get(uint2C0);
}
if (flags & 0x80) {
uint32_t uint2C4;
msg->Get(uint2C4);
float float2C8;
msg->Get(float2C8);
}
if (flags & 0x200) {
uint64_t uint2D4;
msg->Get(uint2D4);
}
}
int32_t CClientObjCreate::Get(CDataStore* msg) {
uint16_t flags;
msg->Get(flags);
this->flags = flags;
if (this->flags & 0x20) {
*msg >> this->move;
} else if (this->flags & 0x100) {
SmartGUID guid;
*msg >> guid;
this->move.status.transport = guid;
*msg >> this->move.status.position28;
*msg >> this->move.status.position18;
msg->Get(this->move.status.facing34);
msg->Get(this->move.status.facing24);
} else if (this->flags & 0x40) {
this->move.status.transport = 0;
*msg >> this->move.status.position28;
this->move.status.position18 = this->move.status.position28;
msg->Get(this->move.status.facing34);
}
if (this->flags & 0x8) {
msg->Get(this->uint2AC);
} else {
this->uint2AC = 0;
}
if (this->flags & 0x10) {
msg->Get(this->uint2B0);
} else {
this->uint2B0 = 0;
}
if (this->flags & 0x4) {
SmartGUID guid;
*msg >> guid;
this->guid2B8 = guid;
} else {
this->guid2B8 = 0;
}
if (this->flags & 0x2) {
msg->Get(this->uint2C0);
}
if (this->flags & 0x80) {
msg->Get(this->uint2C4);
msg->Get(this->float2C8);
}
if (this->flags & 0x200) {
msg->Get(this->uint2D4);
} else {
this->uint2D4 = 0;
}
return msg->Size() >= msg->Tell();
}

View File

@ -0,0 +1,27 @@
#ifndef OBJECT_CLIENT_C_CLIENT_OBJ_CREATE_HPP
#define OBJECT_CLIENT_C_CLIENT_OBJ_CREATE_HPP
#include "object/client/CClientMoveUpdate.hpp"
#include "util/GUID.hpp"
#include <cstdint>
class CDataStore;
struct CClientObjCreate {
CClientMoveUpdate move;
uint32_t flags = 0x0;
uint32_t uint2AC;
uint32_t uint2B0;
// TODO
WOWGUID guid2B8 = 0;
uint32_t uint2C0;
uint32_t uint2C4;
float float2C8;
// TODO
uint64_t uint2D4 = 0; // TODO guid?
static void Skip(CDataStore* msg);
int32_t Get(CDataStore* msg);
};
#endif

View File

@ -1,10 +1,26 @@
#include "object/client/CGContainer.hpp" #include "object/client/CGContainer.hpp"
#include "object/client/CGItem.hpp" #include "object/client/CGItem.hpp"
uint32_t CGContainer::GetBaseOffset() {
return CGItem::TotalFields();
}
uint32_t CGContainer::GetBaseOffsetSaved() {
return CGItem::TotalFieldsSaved();
}
uint32_t CGContainer::GetDataSize() {
return CGContainer::TotalFields() * sizeof(uint32_t);
}
uint32_t CGContainer::GetDataSizeSaved() {
return CGContainer::TotalFieldsSaved() * sizeof(uint32_t);
}
uint32_t CGContainer::TotalFields() { uint32_t CGContainer::TotalFields() {
return CGItem::TotalFields() + 74; return CGContainer::GetBaseOffset() + 74;
} }
uint32_t CGContainer::TotalFieldsSaved() { uint32_t CGContainer::TotalFieldsSaved() {
return CGItem::TotalFieldsSaved() + 72; return CGContainer::GetBaseOffsetSaved() + 72;
} }

View File

@ -1,17 +1,28 @@
#ifndef OBJECT_CLIENT_CG_CONTAINER_HPP #ifndef OBJECT_CLIENT_CG_CONTAINER_HPP
#define OBJECT_CLIENT_CG_CONTAINER_HPP #define OBJECT_CLIENT_CG_CONTAINER_HPP
#include "util/GUID.hpp"
#include <cstdint> #include <cstdint>
struct CGContainerData { struct CGContainerData {
// TODO uint32_t numSlots;
uint32_t pad;
WOWGUID slots[36];
}; };
class CGContainer { class CGContainer {
public: public:
// Public static functions // Public static functions
static uint32_t GetBaseOffset();
static uint32_t GetBaseOffsetSaved();
static uint32_t GetDataSize();
static uint32_t GetDataSizeSaved();
static uint32_t TotalFields(); static uint32_t TotalFields();
static uint32_t TotalFieldsSaved(); static uint32_t TotalFieldsSaved();
// Public member variables
CGContainerData* m_cont;
uint32_t* m_contSaved;
}; };
#endif #endif

View File

@ -0,0 +1,12 @@
#include "object/client/CGContainer_C.hpp"
CGContainer_C::CGContainer_C(uint32_t time, CClientObjCreate& objCreate) : CGItem_C(time, objCreate) {
// TODO
}
void CGContainer_C::SetStorage(uint32_t* storage, uint32_t* saved) {
this->CGItem_C::SetStorage(storage, saved);
this->m_cont = reinterpret_cast<CGContainerData*>(&storage[CGContainer::GetBaseOffset()]);
this->m_contSaved = &saved[CGContainer::GetBaseOffsetSaved()];
}

View File

@ -1,12 +1,15 @@
#ifndef OBJECT_CLIENT_CG_CONTAINER_C_HPP #ifndef OBJECT_CLIENT_CG_CONTAINER_C_HPP
#define OBJECT_CLIENT_CG_CONTAINER_C_HPP #define OBJECT_CLIENT_CG_CONTAINER_C_HPP
#include "object/client/CClientObjCreate.hpp"
#include "object/client/CGContainer.hpp" #include "object/client/CGContainer.hpp"
#include "object/client/CGItem_C.hpp" #include "object/client/CGItem_C.hpp"
class CGContainer_C : public CGItem_C, public CGContainer { class CGContainer_C : public CGItem_C, public CGContainer {
public: public:
// TODO // Public member functions
CGContainer_C(uint32_t time, CClientObjCreate& objCreate);
void SetStorage(uint32_t* storage, uint32_t* saved);
}; };
#endif #endif

View File

@ -1,10 +1,26 @@
#include "object/client/CGCorpse.hpp" #include "object/client/CGCorpse.hpp"
#include "object/client/CGObject.hpp" #include "object/client/CGObject.hpp"
uint32_t CGCorpse::GetBaseOffset() {
return CGObject::TotalFields();
}
uint32_t CGCorpse::GetBaseOffsetSaved() {
return CGObject::TotalFieldsSaved();
}
uint32_t CGCorpse::GetDataSize() {
return CGCorpse::TotalFields() * sizeof(uint32_t);
}
uint32_t CGCorpse::GetDataSizeSaved() {
return CGCorpse::TotalFieldsSaved() * sizeof(uint32_t);
}
uint32_t CGCorpse::TotalFields() { uint32_t CGCorpse::TotalFields() {
return CGObject::TotalFields() + 30; return CGCorpse::GetBaseOffset() + 30;
} }
uint32_t CGCorpse::TotalFieldsSaved() { uint32_t CGCorpse::TotalFieldsSaved() {
return CGObject::TotalFieldsSaved() + 3; return CGCorpse::GetBaseOffsetSaved() + 3;
} }

View File

@ -10,8 +10,16 @@ struct CGCorpseData {
class CGCorpse { class CGCorpse {
public: public:
// Public static functions // Public static functions
static uint32_t GetBaseOffset();
static uint32_t GetBaseOffsetSaved();
static uint32_t GetDataSize();
static uint32_t GetDataSizeSaved();
static uint32_t TotalFields(); static uint32_t TotalFields();
static uint32_t TotalFieldsSaved(); static uint32_t TotalFieldsSaved();
// Public member variables
CGCorpseData* m_corpse;
uint32_t* m_corpseSaved;
}; };
#endif #endif

View File

@ -0,0 +1,12 @@
#include "object/client/CGCorpse_C.hpp"
CGCorpse_C::CGCorpse_C(uint32_t time, CClientObjCreate& objCreate) : CGObject_C(time, objCreate) {
// TODO
}
void CGCorpse_C::SetStorage(uint32_t* storage, uint32_t* saved) {
this->CGObject_C::SetStorage(storage, saved);
this->m_corpse = reinterpret_cast<CGCorpseData*>(&storage[CGCorpse::GetBaseOffset()]);
this->m_corpseSaved = &saved[CGCorpse::GetBaseOffsetSaved()];
}

View File

@ -1,12 +1,15 @@
#ifndef OBJECT_CLIENT_CG_CORPSE_C_HPP #ifndef OBJECT_CLIENT_CG_CORPSE_C_HPP
#define OBJECT_CLIENT_CG_CORPSE_C_HPP #define OBJECT_CLIENT_CG_CORPSE_C_HPP
#include "object/client/CClientObjCreate.hpp"
#include "object/client/CGCorpse.hpp" #include "object/client/CGCorpse.hpp"
#include "object/client/CGObject_C.hpp" #include "object/client/CGObject_C.hpp"
class CGCorpse_C : public CGObject_C, public CGCorpse { class CGCorpse_C : public CGObject_C, public CGCorpse {
public: public:
// TODO // Public member functions
CGCorpse_C(uint32_t time, CClientObjCreate& objCreate);
void SetStorage(uint32_t* storage, uint32_t* saved);
}; };
#endif #endif

View File

@ -1,10 +1,26 @@
#include "object/client/CGDynamicObject.hpp" #include "object/client/CGDynamicObject.hpp"
#include "object/client/CGObject.hpp" #include "object/client/CGObject.hpp"
uint32_t CGDynamicObject::GetBaseOffset() {
return CGObject::TotalFields();
}
uint32_t CGDynamicObject::GetBaseOffsetSaved() {
return CGObject::TotalFieldsSaved();
}
uint32_t CGDynamicObject::GetDataSize() {
return CGDynamicObject::TotalFields() * sizeof(uint32_t);
}
uint32_t CGDynamicObject::GetDataSizeSaved() {
return CGDynamicObject::TotalFieldsSaved() * sizeof(uint32_t);
}
uint32_t CGDynamicObject::TotalFields() { uint32_t CGDynamicObject::TotalFields() {
return CGObject::TotalFields() + 6; return CGDynamicObject::GetBaseOffset() + 6;
} }
uint32_t CGDynamicObject::TotalFieldsSaved() { uint32_t CGDynamicObject::TotalFieldsSaved() {
return CGObject::TotalFieldsSaved(); return CGDynamicObject::GetBaseOffsetSaved() + 0;
} }

View File

@ -10,8 +10,16 @@ struct CGDynamicObjectData {
class CGDynamicObject { class CGDynamicObject {
public: public:
// Public static functions // Public static functions
static uint32_t GetBaseOffset();
static uint32_t GetBaseOffsetSaved();
static uint32_t GetDataSize();
static uint32_t GetDataSizeSaved();
static uint32_t TotalFields(); static uint32_t TotalFields();
static uint32_t TotalFieldsSaved(); static uint32_t TotalFieldsSaved();
// Public member variables
CGDynamicObjectData* m_dynamicObj;
uint32_t* m_dynamicObjSaved;
}; };
#endif #endif

View File

@ -0,0 +1,12 @@
#include "object/client/CGDynamicObject_C.hpp"
CGDynamicObject_C::CGDynamicObject_C(uint32_t time, CClientObjCreate& objCreate) : CGObject_C(time, objCreate) {
// TODO
}
void CGDynamicObject_C::SetStorage(uint32_t* storage, uint32_t* saved) {
this->CGObject_C::SetStorage(storage, saved);
this->m_dynamicObj = reinterpret_cast<CGDynamicObjectData*>(&storage[CGDynamicObject::GetBaseOffset()]);
this->m_dynamicObjSaved = &saved[CGDynamicObject::GetBaseOffsetSaved()];
}

View File

@ -1,12 +1,15 @@
#ifndef OBJECT_CLIENT_CG_DYNAMIC_OBJECT_C_HPP #ifndef OBJECT_CLIENT_CG_DYNAMIC_OBJECT_C_HPP
#define OBJECT_CLIENT_CG_DYNAMIC_OBJECT_C_HPP #define OBJECT_CLIENT_CG_DYNAMIC_OBJECT_C_HPP
#include "object/client/CClientObjCreate.hpp"
#include "object/client/CGDynamicObject.hpp" #include "object/client/CGDynamicObject.hpp"
#include "object/client/CGObject_C.hpp" #include "object/client/CGObject_C.hpp"
class CGDynamicObject_C : public CGObject_C, public CGDynamicObject { class CGDynamicObject_C : public CGObject_C, public CGDynamicObject {
public: public:
// TODO // Public member functions
CGDynamicObject_C(uint32_t time, CClientObjCreate& objCreate);
void SetStorage(uint32_t* storage, uint32_t* saved);
}; };
#endif #endif

View File

@ -1,10 +1,26 @@
#include "object/client/CGGameObject.hpp" #include "object/client/CGGameObject.hpp"
#include "object/client/CGObject.hpp" #include "object/client/CGObject.hpp"
uint32_t CGGameObject::GetBaseOffset() {
return CGObject::TotalFields();
}
uint32_t CGGameObject::GetBaseOffsetSaved() {
return CGObject::TotalFieldsSaved();
}
uint32_t CGGameObject::GetDataSize() {
return CGGameObject::TotalFields() * sizeof(uint32_t);
}
uint32_t CGGameObject::GetDataSizeSaved() {
return CGGameObject::TotalFieldsSaved() * sizeof(uint32_t);
}
uint32_t CGGameObject::TotalFields() { uint32_t CGGameObject::TotalFields() {
return CGObject::TotalFields() + 12; return CGGameObject::GetBaseOffset() + 12;
} }
uint32_t CGGameObject::TotalFieldsSaved() { uint32_t CGGameObject::TotalFieldsSaved() {
return CGObject::TotalFieldsSaved() + 4; return CGGameObject::GetBaseOffsetSaved() + 4;
} }

View File

@ -10,8 +10,16 @@ struct CGGameObjectData {
class CGGameObject { class CGGameObject {
public: public:
// Public static functions // Public static functions
static uint32_t GetBaseOffset();
static uint32_t GetBaseOffsetSaved();
static uint32_t GetDataSize();
static uint32_t GetDataSizeSaved();
static uint32_t TotalFields(); static uint32_t TotalFields();
static uint32_t TotalFieldsSaved(); static uint32_t TotalFieldsSaved();
// Public member variables
CGGameObjectData* m_gameObj;
uint32_t* m_gameObjSaved;
}; };
#endif #endif

View File

@ -0,0 +1,12 @@
#include "object/client/CGGameObject_C.hpp"
CGGameObject_C::CGGameObject_C(uint32_t time, CClientObjCreate& objCreate) : CGObject_C(time, objCreate) {
// TODO
}
void CGGameObject_C::SetStorage(uint32_t* storage, uint32_t* saved) {
this->CGObject_C::SetStorage(storage, saved);
this->m_gameObj = reinterpret_cast<CGGameObjectData*>(&storage[CGGameObject::GetBaseOffset()]);
this->m_gameObjSaved = &saved[CGGameObject::GetBaseOffsetSaved()];
}

View File

@ -1,12 +1,15 @@
#ifndef OBJECT_CLIENT_CG_GAME_OBJECT_C_HPP #ifndef OBJECT_CLIENT_CG_GAME_OBJECT_C_HPP
#define OBJECT_CLIENT_CG_GAME_OBJECT_C_HPP #define OBJECT_CLIENT_CG_GAME_OBJECT_C_HPP
#include "object/client/CClientObjCreate.hpp"
#include "object/client/CGGameObject.hpp" #include "object/client/CGGameObject.hpp"
#include "object/client/CGObject_C.hpp" #include "object/client/CGObject_C.hpp"
class CGGameObject_C : public CGObject_C, public CGGameObject { class CGGameObject_C : public CGObject_C, public CGGameObject {
public: public:
// TODO // Public member functions
CGGameObject_C(uint32_t time, CClientObjCreate& objCreate);
void SetStorage(uint32_t* storage, uint32_t* saved);
}; };
#endif #endif

View File

@ -1,10 +1,26 @@
#include "object/client/CGItem.hpp" #include "object/client/CGItem.hpp"
#include "object/client/CGObject.hpp" #include "object/client/CGObject.hpp"
uint32_t CGItem::GetBaseOffset() {
return CGObject::TotalFields();
}
uint32_t CGItem::GetBaseOffsetSaved() {
return CGObject::TotalFieldsSaved();
}
uint32_t CGItem::GetDataSize() {
return CGItem::TotalFields() * sizeof(uint32_t);
}
uint32_t CGItem::GetDataSizeSaved() {
return CGItem::TotalFieldsSaved() * sizeof(uint32_t);
}
uint32_t CGItem::TotalFields() { uint32_t CGItem::TotalFields() {
return CGObject::TotalFields() + 58; return CGItem::GetBaseOffset() + 58;
} }
uint32_t CGItem::TotalFieldsSaved() { uint32_t CGItem::TotalFieldsSaved() {
return CGObject::TotalFieldsSaved() + 47; return CGItem::GetBaseOffsetSaved() + 47;
} }

View File

@ -1,17 +1,46 @@
#ifndef OBJECT_CLIENT_CG_ITEM_HPP #ifndef OBJECT_CLIENT_CG_ITEM_HPP
#define OBJECT_CLIENT_CG_ITEM_HPP #define OBJECT_CLIENT_CG_ITEM_HPP
#include "util/GUID.hpp"
#include <cstdint> #include <cstdint>
struct ItemEnchantment {
int32_t id;
int32_t expiration;
int32_t chargesRemaining;
};
struct CGItemData { struct CGItemData {
// TODO WOWGUID owner;
WOWGUID containedIn;
WOWGUID creator;
WOWGUID giftCreator;
uint32_t stackCount;
int32_t expiration;
int32_t spellCharges[5];
uint32_t flags;
ItemEnchantment enchantments[12];
int32_t propertySeed;
int32_t randomPropertiesID;
int32_t durability;
int32_t maxDurability;
int32_t createPlayedTime;
int32_t pad;
}; };
class CGItem { class CGItem {
public: public:
// Public static functions // Public static functions
static uint32_t GetBaseOffset();
static uint32_t GetBaseOffsetSaved();
static uint32_t GetDataSize();
static uint32_t GetDataSizeSaved();
static uint32_t TotalFields(); static uint32_t TotalFields();
static uint32_t TotalFieldsSaved(); static uint32_t TotalFieldsSaved();
// Public member variables
CGItemData* m_item;
uint32_t* m_itemSaved;
}; };
#endif #endif

View File

@ -0,0 +1,12 @@
#include "object/client/CGItem_C.hpp"
CGItem_C::CGItem_C(uint32_t time, CClientObjCreate& objCreate) : CGObject_C(time, objCreate) {
// TODO
}
void CGItem_C::SetStorage(uint32_t* storage, uint32_t* saved) {
this->CGObject_C::SetStorage(storage, saved);
this->m_item = reinterpret_cast<CGItemData*>(&storage[CGItem::GetBaseOffset()]);
this->m_itemSaved = &saved[CGItem::GetBaseOffsetSaved()];
}

View File

@ -1,12 +1,15 @@
#ifndef OBJECT_CLIENT_CG_ITEM_C_HPP #ifndef OBJECT_CLIENT_CG_ITEM_C_HPP
#define OBJECT_CLIENT_CG_ITEM_C_HPP #define OBJECT_CLIENT_CG_ITEM_C_HPP
#include "object/client/CClientObjCreate.hpp"
#include "object/client/CGObject_C.hpp" #include "object/client/CGObject_C.hpp"
#include "object/client/CGItem.hpp" #include "object/client/CGItem.hpp"
class CGItem_C : public CGObject_C, public CGItem { class CGItem_C : public CGObject_C, public CGItem {
public: public:
// TODO // Public member functions
CGItem_C(uint32_t time, CClientObjCreate& objCreate);
void SetStorage(uint32_t* storage, uint32_t* saved);
}; };
#endif #endif

View File

@ -1,9 +1,25 @@
#include "object/client/CGObject.hpp" #include "object/client/CGObject.hpp"
uint32_t CGObject::GetBaseOffset() {
return 0;
}
uint32_t CGObject::GetBaseOffsetSaved() {
return 0;
}
uint32_t CGObject::GetDataSize() {
return CGObject::TotalFields() * sizeof(uint32_t);
}
uint32_t CGObject::GetDataSizeSaved() {
return CGObject::TotalFieldsSaved() * sizeof(uint32_t);
}
uint32_t CGObject::TotalFields() { uint32_t CGObject::TotalFields() {
return 6; return CGObject::GetBaseOffset() + 6;
} }
uint32_t CGObject::TotalFieldsSaved() { uint32_t CGObject::TotalFieldsSaved() {
return 3; return CGObject::GetBaseOffsetSaved() + 3;
} }

View File

@ -2,10 +2,11 @@
#define OBJECT_CLIENT_CG_OBJECT_HPP #define OBJECT_CLIENT_CG_OBJECT_HPP
#include "object/Types.hpp" #include "object/Types.hpp"
#include "util/GUID.hpp"
#include <cstdint> #include <cstdint>
struct CGObjectData { struct CGObjectData {
uint64_t m_guid; WOWGUID m_guid;
OBJECT_TYPE m_type; OBJECT_TYPE m_type;
int32_t m_entryID; int32_t m_entryID;
float m_scale; float m_scale;
@ -15,6 +16,10 @@ struct CGObjectData {
class CGObject { class CGObject {
public: public:
// Public static functions // Public static functions
static uint32_t GetBaseOffset();
static uint32_t GetBaseOffsetSaved();
static uint32_t GetDataSize();
static uint32_t GetDataSizeSaved();
static uint32_t TotalFields(); static uint32_t TotalFields();
static uint32_t TotalFieldsSaved(); static uint32_t TotalFieldsSaved();

View File

@ -1,4 +1,81 @@
#include "object/client/CGObject_C.hpp" #include "object/client/CGObject_C.hpp"
#include "object/client/ObjMgr.hpp"
#include "world/World.hpp"
CGObject_C::CGObject_C(uint32_t time, CClientObjCreate& objCreate) {
// TODO
this->m_lockCount = 0;
this->m_disabled = false;
this->m_inReenable = false;
this->m_postInited = false;
this->m_flag19 = false;
this->m_disablePending = false;
// TODO
ClntObjMgrLinkInNewObject(this);
// TODO
}
void CGObject_C::AddWorldObject() {
// TODO
}
void CGObject_C::Disable() {
// TODO
this->m_disabled = true;
// TODO other flag manipulation
this->m_disableTimeMs = CWorld::GetCurTimeMs();
}
int32_t CGObject_C::IsInReenable() {
return this->m_inReenable;
}
int32_t CGObject_C::IsObjectLocked() {
return this->m_lockCount != 0;
}
void CGObject_C::Reenable() {
this->m_disabled = false;
this->m_inReenable = true;
// TODO
}
void CGObject_C::SetBlock(uint32_t block, uint32_t value) {
auto storage = reinterpret_cast<uint32_t*>(this->m_obj);
storage[block] = value;
}
void CGObject_C::SetDisablePending(int32_t pending) {
if (pending) {
this->m_disablePending = true;
} else {
this->m_disablePending = false;
}
}
void CGObject_C::SetObjectLocked(int32_t locked) {
if (locked) {
if (this->m_lockCount != 0xFFFF) {
this->m_lockCount++;
}
} else {
if (this->m_lockCount != 0) {
this->m_lockCount--;
}
}
}
void CGObject_C::SetStorage(uint32_t* storage, uint32_t* saved) {
this->m_obj = reinterpret_cast<CGObjectData*>(&storage[CGObject::GetBaseOffset()]);
this->m_objSaved = &saved[CGObject::GetBaseOffsetSaved()];
}
void CGObject_C::SetTypeID(OBJECT_TYPE_ID typeID) { void CGObject_C::SetTypeID(OBJECT_TYPE_ID typeID) {
this->m_typeID = typeID; this->m_typeID = typeID;

View File

@ -1,14 +1,45 @@
#ifndef OBJECT_CLIENT_CG_OBJECT_C_HPP #ifndef OBJECT_CLIENT_CG_OBJECT_C_HPP
#define OBJECT_CLIENT_CG_OBJECT_C_HPP #define OBJECT_CLIENT_CG_OBJECT_C_HPP
#include "object/client/CGObject.hpp"
#include "object/Types.hpp" #include "object/Types.hpp"
#include "util/CHashKeyGUID.hpp" #include "object/client/CClientObjCreate.hpp"
#include "object/client/CGObject.hpp"
#include "util/GUID.hpp"
#include <storm/Hash.hpp> #include <storm/Hash.hpp>
#include <storm/List.hpp>
class CGObject_C : public CGObject, public TSHashObject<CGObject_C, CHashKeyGUID> { class CGObject_C : public CGObject, public TSHashObject<CGObject_C, CHashKeyGUID> {
public: public:
// Public member variables
TSLink<CGObject_C> m_link;
uint32_t m_disableTimeMs;
// TODO
uint32_t m_lockCount : 16;
uint32_t m_disabled : 1;
uint32_t m_inReenable : 1;
uint32_t m_postInited : 1;
uint32_t m_flag19 : 1;
uint32_t m_disablePending : 1;
// TODO
// Virtual public member functions
// TODO
virtual void Disable();
// TODO
virtual void HandleOutOfRange(OUT_OF_RANGE_TYPE type) {};
// TODO
// Public member functions // Public member functions
CGObject_C() = default;
CGObject_C(uint32_t time, CClientObjCreate& objCreate);
void AddWorldObject();
int32_t IsInReenable();
int32_t IsObjectLocked();
void Reenable();
void SetBlock(uint32_t block, uint32_t value);
void SetDisablePending(int32_t pending);
void SetObjectLocked(int32_t locked);
void SetStorage(uint32_t* storage, uint32_t* saved);
void SetTypeID(OBJECT_TYPE_ID typeID); void SetTypeID(OBJECT_TYPE_ID typeID);
}; };

View File

@ -1,18 +1,42 @@
#include "object/client/CGPlayer.hpp" #include "object/client/CGPlayer.hpp"
#include "object/client/CGUnit.hpp" #include "object/client/CGUnit.hpp"
uint32_t CGPlayer::GetBaseOffset() {
return CGUnit::TotalFields();
}
uint32_t CGPlayer::GetBaseOffsetSaved() {
return CGUnit::TotalFieldsSaved();
}
uint32_t CGPlayer::GetDataSize() {
return CGPlayer::TotalFields() * sizeof(uint32_t);
}
uint32_t CGPlayer::GetDataSizeSaved() {
return CGPlayer::TotalFieldsSaved() * sizeof(uint32_t);
}
uint32_t CGPlayer::GetRemoteDataSize() {
return CGPlayer::TotalRemoteFields() * sizeof(uint32_t);
}
uint32_t CGPlayer::GetRemoteDataSizeSaved() {
return CGPlayer::TotalRemoteFieldsSaved() * sizeof(uint32_t);
}
uint32_t CGPlayer::TotalFields() { uint32_t CGPlayer::TotalFields() {
return CGUnit::TotalFields() + 1178; return CGPlayer::GetBaseOffset() + 1178;
} }
uint32_t CGPlayer::TotalRemoteFields() { uint32_t CGPlayer::TotalRemoteFields() {
return CGUnit::TotalFields() + 176; return CGPlayer::GetBaseOffset() + 176;
} }
uint32_t CGPlayer::TotalFieldsSaved() { uint32_t CGPlayer::TotalFieldsSaved() {
return CGUnit::TotalFieldsSaved() + 1043; return CGPlayer::GetBaseOffsetSaved() + 1043;
} }
uint32_t CGPlayer::TotalRemoteFieldsSaved() { uint32_t CGPlayer::TotalRemoteFieldsSaved() {
return CGUnit::TotalFieldsSaved() + 173; return CGPlayer::GetBaseOffsetSaved() + 173;
} }

View File

@ -1,19 +1,156 @@
#ifndef OBJECT_CLIENT_CG_PLAYER_HPP #ifndef OBJECT_CLIENT_CG_PLAYER_HPP
#define OBJECT_CLIENT_CG_PLAYER_HPP #define OBJECT_CLIENT_CG_PLAYER_HPP
#include "object/Types.hpp"
#include "util/GUID.hpp"
#include <cstdint> #include <cstdint>
struct CQuestLogData {
int32_t questID;
uint32_t field2;
uint32_t field3;
uint32_t field4;
uint32_t field5;
};
// TODO is this VisibleItem_C?
struct CVisibleItemData {
int32_t entryID;
uint32_t enchantment;
};
struct CSkillInfo {
uint16_t skillLineID;
uint16_t skillStep;
uint16_t skillRank;
uint16_t skillMaxRank;
int16_t skillTempModifier;
int16_t skillPermModifier;
};
struct CArenaTeamInfo {
uint32_t field1;
uint32_t field2;
uint32_t field3;
uint32_t field4;
uint32_t field5;
uint32_t field6;
uint32_t field7;
};
struct CGPlayerData { struct CGPlayerData {
// TODO WOWGUID duelArbiter;
uint32_t flags;
uint32_t guildID;
uint32_t guildRank;
uint8_t skinID;
uint8_t faceID;
uint8_t hairStyleID;
uint8_t hairColorID;
uint8_t facialHairStyleID;
uint8_t bytes_2_2; // TODO
uint8_t bytes_2_3; // TODO
uint8_t restState;
uint8_t bytes_3_1; // TODO
uint8_t bytes_3_2; // TODO
uint8_t bytes_3_3; // TODO
uint8_t bytes_3_4; // TODO
uint32_t duelTeam;
int32_t guildTimestamp;
CQuestLogData questLog[25];
CVisibleItemData visibleItems[19];
int32_t chosenTitle;
int32_t fakeInebriation;
int32_t pad1;
WOWGUID invSlots[NUM_INVENTORY_SLOTS];
WOWGUID packSlots[16];
WOWGUID bankSlots[28];
WOWGUID bankBagSlots[7];
WOWGUID vendorBuybackSlots[12];
WOWGUID keyringSlots[32];
WOWGUID currencyTokenSlots[32];
WOWGUID farsightObject;
WOWGUID knownTitles;
WOWGUID knownTitles2;
WOWGUID knownTitles3;
WOWGUID knownCurrencies;
uint32_t xp;
uint32_t nextLevelXP;
CSkillInfo skillInfo[128];
int32_t characterPoints[2];
uint32_t trackCreatureMask;
uint32_t trackResourceMask;
float blockPercentage;
float dodgePercentage;
float parryPercentage;
int32_t expertise;
int32_t offhandExpertise;
float critPercentage;
float rangedCritPercentage;
float offhandCritPercentage;
float spellCritPercentage[7];
int32_t shieldBlock;
float shieldBlockCritPercentage;
uint8_t exploredZones[512];
uint32_t restStateXP;
uint32_t coinage;
int32_t modDamageDonePos[7];
int32_t modDamageDoneNeg[7];
float modDamageDonePct[7];
uint32_t modHealingDonePos;
float modHealingPct;
float modHealingDonePct;
int32_t modTargetResistance;
int32_t modTargetPhysicalResistance;
uint8_t field_bytes_1; // TODO
uint8_t field_bytes_2; // TODO
uint8_t field_bytes_3; // TODO
uint8_t field_bytes_4; // TODO
int32_t ammoID;
int32_t selfResSpell;
uint32_t pvpMedals;
uint32_t buybackPrice[12];
uint32_t buybackTimestamp[12];
uint16_t kills[2];
uint32_t todayContribution;
uint32_t yesterdayContribution;
uint32_t lifetimeHonorableKills;
uint8_t field_bytes_2_1; // TODO
uint8_t field_bytes_2_2; // TODO
uint8_t field_bytes_2_3; // TODO
uint8_t field_bytes_2_4; // TODO
int32_t watchedFactionIndex;
uint32_t combatRating[25];
CArenaTeamInfo arenaTeamInfo[3];
uint32_t honorCurrency;
uint32_t arenaCurrency;
uint32_t maxLevel;
uint32_t dailyQuests[25];
float runeRegen[4];
uint32_t noReagentCost[3];
uint32_t glyphSlots[6];
uint32_t glyphs[6];
int32_t glyphsEnabled;
uint32_t petSpellPower;
}; };
class CGPlayer { class CGPlayer {
public: public:
// Public static functions // Public static functions
static uint32_t GetBaseOffset();
static uint32_t GetBaseOffsetSaved();
static uint32_t GetDataSize();
static uint32_t GetDataSizeSaved();
static uint32_t GetRemoteDataSize();
static uint32_t GetRemoteDataSizeSaved();
static uint32_t TotalFields(); static uint32_t TotalFields();
static uint32_t TotalRemoteFields(); static uint32_t TotalRemoteFields();
static uint32_t TotalFieldsSaved(); static uint32_t TotalFieldsSaved();
static uint32_t TotalRemoteFieldsSaved(); static uint32_t TotalRemoteFieldsSaved();
// Public member variables
CGPlayerData* m_player;
uint32_t* m_playerSaved;
}; };
#endif #endif

View File

@ -3,6 +3,17 @@
#include "object/Types.hpp" #include "object/Types.hpp"
#include <storm/Error.hpp> #include <storm/Error.hpp>
CGPlayer_C::CGPlayer_C(uint32_t time, CClientObjCreate& objCreate) : CGUnit_C(time, objCreate) {
// TODO
}
void CGPlayer_C::SetStorage(uint32_t* storage, uint32_t* saved) {
this->CGUnit_C::SetStorage(storage, saved);
this->m_player = reinterpret_cast<CGPlayerData*>(&storage[CGPlayer::GetBaseOffset()]);
this->m_playerSaved = &saved[CGPlayer::GetBaseOffsetSaved()];
}
uint32_t Player_C_GetDisplayId(uint32_t race, uint32_t sex) { uint32_t Player_C_GetDisplayId(uint32_t race, uint32_t sex) {
STORM_ASSERT(sex < UNITSEX_LAST); STORM_ASSERT(sex < UNITSEX_LAST);

View File

@ -1,6 +1,7 @@
#ifndef OBJECT_CLIENT_CG_PLAYER_C_HPP #ifndef OBJECT_CLIENT_CG_PLAYER_C_HPP
#define OBJECT_CLIENT_CG_PLAYER_C_HPP #define OBJECT_CLIENT_CG_PLAYER_C_HPP
#include "object/client/CClientObjCreate.hpp"
#include "object/client/CGPlayer.hpp" #include "object/client/CGPlayer.hpp"
#include "object/client/CGUnit_C.hpp" #include "object/client/CGUnit_C.hpp"
#include <cstdint> #include <cstdint>
@ -9,7 +10,9 @@ class CreatureModelDataRec;
class CGPlayer_C : public CGUnit_C, public CGPlayer { class CGPlayer_C : public CGUnit_C, public CGPlayer {
public: public:
// TODO // Public member functions
CGPlayer_C(uint32_t time, CClientObjCreate& objCreate);
void SetStorage(uint32_t* storage, uint32_t* saved);
}; };
uint32_t Player_C_GetDisplayId(uint32_t race, uint32_t sex); uint32_t Player_C_GetDisplayId(uint32_t race, uint32_t sex);

View File

@ -1,10 +1,26 @@
#include "object/client/CGUnit.hpp" #include "object/client/CGUnit.hpp"
#include "object/client/CGObject.hpp" #include "object/client/CGObject.hpp"
uint32_t CGUnit::GetBaseOffset() {
return CGObject::TotalFields();
}
uint32_t CGUnit::GetBaseOffsetSaved() {
return CGObject::TotalFieldsSaved();
}
uint32_t CGUnit::GetDataSize() {
return CGUnit::TotalFields() * sizeof(uint32_t);
}
uint32_t CGUnit::GetDataSizeSaved() {
return CGUnit::TotalFieldsSaved() * sizeof(uint32_t);
}
uint32_t CGUnit::TotalFields() { uint32_t CGUnit::TotalFields() {
return CGObject::TotalFields() + 142; return CGUnit::GetBaseOffset() + 142;
} }
uint32_t CGUnit::TotalFieldsSaved() { uint32_t CGUnit::TotalFieldsSaved() {
return CGObject::TotalFieldsSaved() + 123; return CGUnit::GetBaseOffsetSaved() + 123;
} }

View File

@ -1,17 +1,90 @@
#ifndef OBJECT_CLIENT_CG_UNIT_HPP #ifndef OBJECT_CLIENT_CG_UNIT_HPP
#define OBJECT_CLIENT_CG_UNIT_HPP #define OBJECT_CLIENT_CG_UNIT_HPP
#include "util/GUID.hpp"
#include <cstdint> #include <cstdint>
struct CGUnitData { struct CGUnitData {
// TODO WOWGUID charm;
WOWGUID summon;
WOWGUID critter;
WOWGUID charmedBy;
WOWGUID summonedBy;
WOWGUID createdBy;
WOWGUID target;
WOWGUID channelObject;
int32_t channelSpell;
int32_t pad1;
int32_t health;
int32_t power[7];
int32_t maxHealth;
int32_t maxPower[7];
float powerRegenFlatModifier[7];
int32_t powerRegenInterruptedFlatModifier[7];
int32_t level;
int32_t factionTemplate;
int32_t virtualItemSlotID[3];
uint32_t flags;
uint32_t flags2;
uint32_t auraState;
uint32_t attackRoundBaseTime[2];
uint32_t rangedAttackTime;
float boundingRadius;
float combatReach;
int32_t displayID;
int32_t nativeDisplayID;
int32_t mountDisplayID;
float minDamage;
float maxDamage;
uint32_t minOffhandDamage;
uint32_t maxOffhandDamage;
int32_t pad2;
uint32_t petNumber;
uint32_t petNameTimestamp;
uint32_t petExperience;
uint32_t petNextLevelExperience;
uint32_t dynamicFlags;
float modCastingSpeed;
int32_t createdBySpell;
uint32_t npcFlags;
uint32_t emoteState;
int32_t stats[5];
int32_t posStats[5];
int32_t negStats[5];
int32_t resistance[7];
int32_t resistanceBuffModsPositive[7];
int32_t resistanceBuffModsNegative[7];
int32_t baseMana;
int32_t baseHealth;
int32_t pad3;
int32_t attackPower;
int32_t attackPowerMods;
int32_t attackPowerMultiplier;
int32_t rangedAttackPower;
int32_t rangedAttackPowerMods;
int32_t rangedAttackPowerMultiplier;
float minRangedDamage;
float maxRangedDamage;
int32_t powerCostModifier[7];
int32_t powerCostMultiplier[7];
int32_t maxHealthModifier;
float hoverHeight;
int32_t pad4;
}; };
class CGUnit { class CGUnit {
public: public:
// Public static functions // Public static functions
static uint32_t GetBaseOffset();
static uint32_t GetBaseOffsetSaved();
static uint32_t GetDataSize();
static uint32_t GetDataSizeSaved();
static uint32_t TotalFields(); static uint32_t TotalFields();
static uint32_t TotalFieldsSaved(); static uint32_t TotalFieldsSaved();
// Public member variables
CGUnitData* m_unit;
uint32_t* m_unitSaved;
}; };
#endif #endif

View File

@ -88,3 +88,14 @@ const char* CGUnit_C::GetDisplayRaceNameFromRecord(const ChrRacesRec* raceRec, U
return raceRec->m_name; return raceRec->m_name;
} }
CGUnit_C::CGUnit_C(uint32_t time, CClientObjCreate& objCreate) : CGObject_C(time, objCreate) {
// TODO
}
void CGUnit_C::SetStorage(uint32_t* storage, uint32_t* saved) {
this->CGObject_C::SetStorage(storage, saved);
this->m_unit = reinterpret_cast<CGUnitData*>(&storage[CGUnit::GetBaseOffset()]);
this->m_unitSaved = &saved[CGUnit::GetBaseOffsetSaved()];
}

View File

@ -1,6 +1,7 @@
#ifndef OBJECT_CLIENT_CG_UNIT_C_HPP #ifndef OBJECT_CLIENT_CG_UNIT_C_HPP
#define OBJECT_CLIENT_CG_UNIT_C_HPP #define OBJECT_CLIENT_CG_UNIT_C_HPP
#include "object/client/CClientObjCreate.hpp"
#include "object/client/CGObject_C.hpp" #include "object/client/CGObject_C.hpp"
#include "object/client/CGUnit.hpp" #include "object/client/CGUnit.hpp"
#include "object/Types.hpp" #include "object/Types.hpp"
@ -13,6 +14,10 @@ class CGUnit_C : public CGObject_C, public CGUnit {
// Public static functions // Public static functions
static const char* GetDisplayClassNameFromRecord(const ChrClassesRec* classRec, UNIT_SEX sex, UNIT_SEX* displaySex); static const char* GetDisplayClassNameFromRecord(const ChrClassesRec* classRec, UNIT_SEX sex, UNIT_SEX* displaySex);
static const char* GetDisplayRaceNameFromRecord(const ChrRacesRec* raceRec, UNIT_SEX sex, UNIT_SEX* displaySex); static const char* GetDisplayRaceNameFromRecord(const ChrRacesRec* raceRec, UNIT_SEX sex, UNIT_SEX* displaySex);
// Public member functions
CGUnit_C(uint32_t time, CClientObjCreate& objCreate);
void SetStorage(uint32_t* storage, uint32_t* saved);
}; };
#endif #endif

View File

@ -1,6 +1,9 @@
#ifndef OBJECT_CLIENT_CLNT_OBJ_MGR_HPP #ifndef OBJECT_CLIENT_CLNT_OBJ_MGR_HPP
#define OBJECT_CLIENT_CLNT_OBJ_MGR_HPP #define OBJECT_CLIENT_CLNT_OBJ_MGR_HPP
#include "object/client/CGObject_C.hpp"
#include <storm/Hash.hpp>
#include <storm/List.hpp>
#include <cstdint> #include <cstdint>
class ClientConnection; class ClientConnection;
@ -8,7 +11,13 @@ class ClientConnection;
class ClntObjMgr { class ClntObjMgr {
public: public:
// Member variables // Member variables
uint64_t m_activePlayer = 0; TSHashTable<CGObject_C, CHashKeyGUID> m_objects;
TSHashTable<CGObject_C, CHashKeyGUID> m_lazyCleanupObjects;
STORM_EXPLICIT_LIST(CGObject_C, m_link) m_lazyCleanupFifo[NUM_CLIENT_OBJECT_TYPES - 1];
STORM_EXPLICIT_LIST(CGObject_C, m_link) m_visibleObjects;
STORM_EXPLICIT_LIST(CGObject_C, m_link) m_reenabledObjects;
// TODO
WOWGUID m_activePlayer = 0;
uint32_t m_mapID = 0; uint32_t m_mapID = 0;
ClientConnection* m_net = nullptr; ClientConnection* m_net = nullptr;
}; };

View File

@ -1,9 +1,330 @@
#include "object/client/MessageHandlers.hpp" #include "object/client/MessageHandlers.hpp"
#include "object/client/CClientObjCreate.hpp"
#include "object/client/CGContainer_C.hpp"
#include "object/client/CGCorpse_C.hpp"
#include "object/client/CGDynamicObject_C.hpp"
#include "object/client/CGGameObject_C.hpp"
#include "object/client/CGItem_C.hpp"
#include "object/client/CGObject_C.hpp"
#include "object/client/CGPlayer_C.hpp"
#include "object/client/CGUnit_C.hpp"
#include "object/client/Mirror.hpp"
#include "object/client/ObjMgr.hpp"
#include "object/client/Util.hpp"
#include "util/GUID.hpp"
#include "util/Unimplemented.hpp" #include "util/Unimplemented.hpp"
#include "util/Zlib.hpp" #include "util/Zlib.hpp"
#include <common/DataStore.hpp> #include <common/DataStore.hpp>
#include <storm/Error.hpp> #include <storm/Error.hpp>
#include <storm/Memory.hpp> #include <storm/Memory.hpp>
#include <new>
enum UPDATE_TYPE {
UPDATE_PARTIAL = 0,
UPDATE_MOVEMENT = 1,
UPDATE_FULL = 2,
UPDATE_3 = 3,
UPDATE_OUT_OF_RANGE = 4,
UPDATE_IN_RANGE = 5,
};
int32_t SkipPartialObjectUpdate(CDataStore* msg) {
// TODO
return 0;
}
void UpdateOutOfRangeObjects(CDataStore* msg) {
uint32_t count;
msg->Get(count);
// TODO CVehiclePassenger_C::StartAddingPendingRescueTransitions();
auto startPos = msg->Tell();
// Pass 1
for (int32_t i = 0; i < count; i++) {
SmartGUID guid;
*msg >> guid;
if (guid == ClntObjMgrGetActivePlayer()) {
continue;
}
auto object = FindActiveObject(guid);
if (object) {
HandleObjectOutOfRangePass1(object, OUT_OF_RANGE_0);
}
}
msg->Seek(startPos);
// Pass 2
for (int32_t i = 0; i < count; i++) {
SmartGUID guid;
*msg >> guid;
if (guid == ClntObjMgrGetActivePlayer()) {
continue;
}
auto object = FindActiveObject(guid);
if (object && !object->IsObjectLocked()) {
HandleObjectOutOfRangePass2(object);
}
}
// TODO CVehiclePassenger_C::ExecutePendingRescueTransitions();
}
int32_t UpdateObject(CDataStore* msg) {
SmartGUID guid;
*msg >> guid;
int32_t reenable;
auto object = GetUpdateObject(guid, &reenable);
if (object) {
if (!FillInPartialObjectData(object, object->m_obj->m_guid, msg, false, false)) {
return 0;
}
if (reenable) {
object->Reenable();
}
return 1;
}
return SkipPartialObjectUpdate(msg);
}
void UpdateObjectMovement(CDataStore* msg) {
WHOA_UNIMPLEMENTED();
}
void SetupObjectStorage(OBJECT_TYPE_ID typeID, CGObject_C* object, WOWGUID guid) {
auto ptr = reinterpret_cast<char*>(object);
switch (typeID) {
case ID_OBJECT: {
auto storage = reinterpret_cast<uint32_t*>(ptr + sizeof(CGObject_C));
auto saved = storage + CGObject::TotalFields();
object->SetStorage(storage, saved);
memset(storage, 0, CGObject::GetDataSize());
break;
}
case ID_ITEM: {
auto storage = reinterpret_cast<uint32_t*>(ptr + sizeof(CGItem_C));
auto saved = storage + CGItem::TotalFields();
static_cast<CGItem_C*>(object)->SetStorage(storage, saved);
memset(storage, 0, CGItem::GetDataSize());
break;
}
case ID_CONTAINER: {
auto storage = reinterpret_cast<uint32_t*>(ptr + sizeof(CGContainer_C));
auto saved = storage + CGContainer::TotalFields();
static_cast<CGContainer_C*>(object)->SetStorage(storage, saved);
memset(storage, 0, CGContainer::GetDataSize());
break;
}
case ID_UNIT: {
auto storage = reinterpret_cast<uint32_t*>(ptr + sizeof(CGUnit_C));
auto saved = storage + CGUnit::TotalFields();
static_cast<CGUnit_C*>(object)->SetStorage(storage, saved);
memset(storage, 0, CGUnit::GetDataSize());
break;
}
case ID_PLAYER: {
// TODO something at ptr + 0x614 (within CGPlayer_C)
if (guid == ClntObjMgrGetActivePlayer()) {
auto storage = reinterpret_cast<uint32_t*>(ptr + sizeof(CGPlayer_C));
auto saved = storage + CGPlayer::TotalFields();
static_cast<CGPlayer_C*>(object)->SetStorage(storage, saved);
memset(storage, 0, CGPlayer::GetDataSize());
} else {
auto storage = reinterpret_cast<uint32_t*>(ptr + sizeof(CGPlayer_C));
auto saved = storage + CGPlayer::TotalRemoteFields();
static_cast<CGPlayer_C*>(object)->SetStorage(storage, saved);
memset(storage, 0, CGPlayer::GetRemoteDataSize());
}
break;
}
case ID_GAMEOBJECT: {
auto storage = reinterpret_cast<uint32_t*>(ptr + sizeof(CGGameObject_C));
auto saved = storage + CGGameObject::TotalFields();
static_cast<CGGameObject_C*>(object)->SetStorage(storage, saved);
memset(storage, 0, CGGameObject::GetDataSize());
break;
}
case ID_DYNAMICOBJECT: {
auto storage = reinterpret_cast<uint32_t*>(ptr + sizeof(CGDynamicObject_C));
auto saved = storage + CGDynamicObject::TotalFields();
static_cast<CGDynamicObject_C*>(object)->SetStorage(storage, saved);
memset(storage, 0, CGDynamicObject::GetDataSize());
break;
}
case ID_CORPSE: {
auto storage = reinterpret_cast<uint32_t*>(ptr + sizeof(CGCorpse_C));
auto saved = storage + CGCorpse::TotalFields();
static_cast<CGCorpse_C*>(object)->SetStorage(storage, saved);
memset(storage, 0, CGCorpse::GetDataSize());
break;
}
}
}
int32_t CreateObject(CDataStore* msg, uint32_t time) {
SmartGUID guid;
*msg >> guid;
uint8_t _typeID;
msg->Get(_typeID);
auto typeID = static_cast<OBJECT_TYPE_ID>(_typeID);
int32_t reenable;
auto existingObject = GetUpdateObject(guid, &reenable);
if (existingObject) {
CClientObjCreate::Skip(msg);
if (!FillInPartialObjectData(existingObject, existingObject->m_obj->m_guid, msg, false, true)) {
return 0;
}
if (reenable) {
existingObject->Reenable();
}
return 1;
}
CClientObjCreate objCreate;
if (!objCreate.Get(msg)) {
return 0;
}
if (objCreate.flags & 0x1) {
ClntObjMgrSetActivePlayer(guid);
}
auto newObject = ClntObjMgrAllocObject(typeID, guid);
SetupObjectStorage(typeID, newObject, guid);
newObject->SetTypeID(typeID);
if (!FillInPartialObjectData(newObject, guid, msg, true, false)) {
return 0;
}
InitObject(newObject, time, objCreate);
ClntObjMgrGetCurrent()->m_visibleObjects.LinkToTail(newObject);
return 1;
}
void UpdateInRangeObjects(CDataStore* msg) {
uint32_t count;
msg->Get(count);
for (int32_t i = 0; i < count; i++) {
SmartGUID guid;
*msg >> guid;
if (guid != ClntObjMgrGetActivePlayer()) {
int32_t reenable;
auto object = GetUpdateObject(guid, &reenable);
if (object && reenable) {
object->Reenable();
}
}
}
}
int32_t ObjectUpdateFirstPass(CDataStore* msg, uint32_t time, uint32_t updateIdx, uint32_t updateCount) {
for (uint32_t i = updateIdx; i < updateCount; i++) {
uint8_t updateType;
msg->Get(updateType);
switch (updateType) {
case UPDATE_PARTIAL: {
if (!UpdateObject(msg)) {
return 0;
}
break;
}
case UPDATE_MOVEMENT: {
// Skipped in first pass
SmartGUID guid;
*msg >> guid;
CClientMoveUpdate::Skip(msg);
break;
}
case UPDATE_FULL:
case UPDATE_3: {
if (!CreateObject(msg, time)) {
return 0;
}
break;
}
case UPDATE_IN_RANGE: {
UpdateInRangeObjects(msg);
break;
}
default: {
STORM_APP_FATAL("Unknown client update packet type (%d)!", updateType);
}
}
}
return 1;
}
int32_t ObjectUpdateSecondPass(CDataStore* msg, uint32_t time, uint32_t updateCount) {
// TODO
return 0;
}
int32_t ObjectCompressedUpdateHandler(void* param, NETMESSAGE msgId, uint32_t time, CDataStore* msg) { int32_t ObjectCompressedUpdateHandler(void* param, NETMESSAGE msgId, uint32_t time, CDataStore* msg) {
uint32_t origSize; uint32_t origSize;
@ -60,9 +381,51 @@ int32_t ObjectCompressedUpdateHandler(void* param, NETMESSAGE msgId, uint32_t ti
} }
int32_t ObjectUpdateHandler(void* param, NETMESSAGE msgId, uint32_t time, CDataStore* msg) { int32_t ObjectUpdateHandler(void* param, NETMESSAGE msgId, uint32_t time, CDataStore* msg) {
WHOA_UNIMPLEMENTED(0); uint32_t updateCount;
msg->Get(updateCount);
auto startPos = msg->Tell();
uint8_t firstUpdateType;
msg->Get(firstUpdateType);
uint32_t updateIdx = 0;
if (firstUpdateType == UPDATE_OUT_OF_RANGE) {
UpdateOutOfRangeObjects(msg);
updateIdx = 1;
} else {
msg->Seek(startPos);
}
int32_t result = 0;
if (ObjectUpdateFirstPass(msg, time, updateIdx, updateCount)) {
msg->Seek(startPos);
result = ObjectUpdateSecondPass(msg, time, updateCount);
}
// TODO
return result;
} }
int32_t OnObjectDestroy(void* param, NETMESSAGE msgId, uint32_t time, CDataStore* msg) { int32_t OnObjectDestroy(void* param, NETMESSAGE msgId, uint32_t time, CDataStore* msg) {
WHOA_UNIMPLEMENTED(0); WOWGUID guid;
msg->Get(guid);
uint8_t dead;
msg->Get(dead);
auto object = FindActiveObject(guid);
if (object) {
// TODO handle unit death
if (HandleObjectOutOfRangePass1(object, OUT_OF_RANGE_1)) {
HandleObjectOutOfRangePass2(object);
}
}
return 1;
} }

View File

@ -0,0 +1,187 @@
#include "object/client/Mirror.hpp"
#include "object/client/CGContainer.hpp"
#include "object/client/CGCorpse.hpp"
#include "object/client/CGDynamicObject.hpp"
#include "object/client/CGGameObject.hpp"
#include "object/client/CGItem.hpp"
#include "object/client/CGObject_C.hpp"
#include "object/client/CGPlayer.hpp"
#include "object/client/CGUnit.hpp"
#include "object/client/ObjMgr.hpp"
#include "object/Types.hpp"
#include <common/DataStore.hpp>
#define MAX_CHANGE_MASKS 42
static uint32_t s_objMirrorBlocks[] = {
CGObject::TotalFields(),
CGItem::TotalFields(),
CGContainer::TotalFields(),
CGUnit::TotalFields(),
CGPlayer::TotalFields(),
CGGameObject::TotalFields(),
CGDynamicObject::TotalFields(),
CGCorpse::TotalFields(),
};
/**
* Given a message data store, extract the dirty change masks contained inside. Any masks not
* present are zeroed out. This function assumes the provided masks pointer has enough space for
* MAX_CHANGE_MASKS.
*/
int32_t ExtractDirtyMasks(CDataStore* msg, uint8_t* maskCount, uint32_t* masks) {
uint8_t count;
msg->Get(count);
*maskCount = count;
if (count > MAX_CHANGE_MASKS) {
return 0;
}
for (int32_t i = 0; i < count; i++) {
msg->Get(masks[i]);
}
// Zero out masks that aren't present
memset(&masks[count], 0, (MAX_CHANGE_MASKS - count) * sizeof(uint32_t));
return 1;
}
/**
* Given an object type hierarchy and GUID, return the number of DWORD blocks backing the object's
* data storage.
*/
uint32_t GetNumDwordBlocks(OBJECT_TYPE type, WOWGUID guid) {
switch (type) {
case HIER_TYPE_OBJECT:
return CGObject::TotalFields();
case HIER_TYPE_ITEM:
return CGItem::TotalFields();
case HIER_TYPE_CONTAINER:
return CGContainer::TotalFields();
case HIER_TYPE_UNIT:
return CGUnit::TotalFields();
case HIER_TYPE_PLAYER:
return guid == ClntObjMgrGetActivePlayer() ? CGPlayer::TotalFields() : CGPlayer::TotalRemoteFields();
case HIER_TYPE_GAMEOBJECT:
return CGGameObject::TotalFields();
case HIER_TYPE_DYNAMICOBJECT:
return CGDynamicObject::TotalFields();
case HIER_TYPE_CORPSE:
return CGCorpse::TotalFields();
default:
return 0;
}
}
/**
* Accounting for the full hierarchy of the given object, return the next inherited type ID after
* the given current type ID. If there is no next inherited type, return NUM_CLIENT_OBJECT_TYPES
* to indicate the end of the hierarchy.
*/
OBJECT_TYPE_ID IncTypeID(CGObject_C* object, OBJECT_TYPE_ID curTypeID) {
switch (object->m_obj->m_type) {
// ID_OBJECT -> ID_ITEM -> ID_CONTAINER
case HIER_TYPE_ITEM:
case HIER_TYPE_CONTAINER:
if (curTypeID == ID_OBJECT) {
return ID_ITEM;
}
if (curTypeID == ID_ITEM) {
return ID_CONTAINER;
}
return NUM_CLIENT_OBJECT_TYPES;
// ID_OBJECT -> ID_UNIT -> ID_PLAYER
case HIER_TYPE_UNIT:
case HIER_TYPE_PLAYER:
if (curTypeID == ID_OBJECT) {
return ID_UNIT;
}
if (curTypeID == ID_UNIT) {
return ID_PLAYER;
}
return NUM_CLIENT_OBJECT_TYPES;
// ID_OBJECT -> ID_GAMEOBJECT
case HIER_TYPE_GAMEOBJECT:
if (curTypeID == ID_OBJECT) {
return ID_GAMEOBJECT;
}
return NUM_CLIENT_OBJECT_TYPES;
// ID_OBJECT -> ID_DYNAMICOBJECT
case HIER_TYPE_DYNAMICOBJECT:
if (curTypeID == ID_OBJECT) {
return ID_DYNAMICOBJECT;
}
return NUM_CLIENT_OBJECT_TYPES;
// ID_OBJECT -> ID_CORPSE
case HIER_TYPE_CORPSE:
if (curTypeID == ID_OBJECT) {
return ID_CORPSE;
}
return NUM_CLIENT_OBJECT_TYPES;
default:
return NUM_CLIENT_OBJECT_TYPES;
}
}
int32_t IsMaskBitSet(uint32_t* masks, uint32_t block) {
return masks[block / 32] & (1 << (block % 32));
}
int32_t FillInPartialObjectData(CGObject_C* object, WOWGUID guid, CDataStore* msg, bool forFullUpdate, bool zeroZeroBits) {
uint8_t changeMaskCount;
uint32_t changeMasks[MAX_CHANGE_MASKS];
if (!ExtractDirtyMasks(msg, &changeMaskCount, changeMasks)) {
return 0;
}
OBJECT_TYPE_ID typeID = ID_OBJECT;
uint32_t blockOffset = 0;
uint32_t numBlocks = GetNumDwordBlocks(object->m_obj->m_type, guid);
for (int32_t block = 0; block < numBlocks; block++) {
if (block >= s_objMirrorBlocks[typeID]) {
blockOffset = s_objMirrorBlocks[typeID];
typeID = IncTypeID(object, typeID);
}
if (!forFullUpdate) {
// TODO
}
if (IsMaskBitSet(changeMasks, block)) {
uint32_t blockValue;
msg->GetArray(reinterpret_cast<uint8_t*>(&blockValue), sizeof(blockValue));
object->SetBlock(block, blockValue);
} else if (zeroZeroBits) {
object->SetBlock(block, 0);
}
}
// TODO
return 1;
}

View File

@ -0,0 +1,12 @@
#ifndef OBJECT_CLIENT_MIRROR_HPP
#define OBJECT_CLIENT_MIRROR_HPP
#include "util/GUID.hpp"
#include <cstdint>
class CDataStore;
class CGObject_C;
int32_t FillInPartialObjectData(CGObject_C* object, WOWGUID guid, CDataStore* msg, bool forFullUpdate, bool zeroZeroBits);
#endif

View File

@ -11,6 +11,7 @@
#include "object/client/CGPlayer_C.hpp" #include "object/client/CGPlayer_C.hpp"
#include "object/client/CGUnit_C.hpp" #include "object/client/CGUnit_C.hpp"
#include "object/client/MessageHandlers.hpp" #include "object/client/MessageHandlers.hpp"
#include "object/client/Util.hpp"
#include "util/Unimplemented.hpp" #include "util/Unimplemented.hpp"
#include <common/ObjectAlloc.hpp> #include <common/ObjectAlloc.hpp>
#include <storm/Memory.hpp> #include <storm/Memory.hpp>
@ -26,14 +27,14 @@ static ClntObjMgr* s_curMgr;
#endif #endif
static uint32_t s_objTotalSize[] = { static uint32_t s_objTotalSize[] = {
static_cast<uint32_t>(sizeof(CGObject_C) + sizeof(CGObjectData) + (sizeof(uint32_t) * CGObject::TotalFieldsSaved())), static_cast<uint32_t>(sizeof(CGObject_C) + CGObject::GetDataSize() + CGObject::GetDataSizeSaved()),
static_cast<uint32_t>(sizeof(CGItem_C) + sizeof(CGItemData) + (sizeof(uint32_t) * CGItem::TotalFieldsSaved())), static_cast<uint32_t>(sizeof(CGItem_C) + CGItem::GetDataSize() + CGItem::GetDataSizeSaved()),
static_cast<uint32_t>(sizeof(CGContainer_C) + sizeof(CGContainerData) + (sizeof(uint32_t) * CGContainer::TotalFieldsSaved())), static_cast<uint32_t>(sizeof(CGContainer_C) + CGContainer::GetDataSize() + CGContainer::GetDataSizeSaved()),
static_cast<uint32_t>(sizeof(CGUnit_C) + sizeof(CGUnitData) + (sizeof(uint32_t) * CGUnit::TotalFieldsSaved())), static_cast<uint32_t>(sizeof(CGUnit_C) + CGUnit::GetDataSize() + CGUnit::GetDataSizeSaved()),
static_cast<uint32_t>(sizeof(CGPlayer_C) + sizeof(CGPlayerData) + (sizeof(uint32_t) * CGPlayer::TotalRemoteFieldsSaved())), static_cast<uint32_t>(sizeof(CGPlayer_C) + CGPlayer::GetRemoteDataSize() + CGPlayer::GetRemoteDataSizeSaved()),
static_cast<uint32_t>(sizeof(CGGameObject_C) + sizeof(CGGameObjectData) + (sizeof(uint32_t) * CGGameObject::TotalFieldsSaved())), static_cast<uint32_t>(sizeof(CGGameObject_C) + CGGameObject::GetDataSize() + CGGameObject::GetDataSizeSaved()),
static_cast<uint32_t>(sizeof(CGDynamicObject_C) + sizeof(CGDynamicObjectData) + (sizeof(uint32_t) * CGDynamicObject::TotalFieldsSaved())), static_cast<uint32_t>(sizeof(CGDynamicObject_C) + CGDynamicObject::GetDataSize() + CGDynamicObject::GetDataSizeSaved()),
static_cast<uint32_t>(sizeof(CGCorpse_C) + sizeof(CGCorpseData) + (sizeof(uint32_t) * CGCorpse::TotalFieldsSaved())), static_cast<uint32_t>(sizeof(CGCorpse_C) + CGCorpse::GetDataSize() + CGCorpse::GetDataSizeSaved()),
}; };
static const char* s_objNames[] = { static const char* s_objNames[] = {
@ -66,12 +67,12 @@ void MirrorInitialize() {
// TODO // TODO
} }
void* ClntObjMgrAllocObject(OBJECT_TYPE_ID typeID, uint64_t guid) { CGObject_C* ClntObjMgrAllocObject(OBJECT_TYPE_ID typeID, WOWGUID guid) {
auto playerGUID = ClntObjMgrGetActivePlayer(); auto playerGUID = ClntObjMgrGetActivePlayer();
// Heap allocate player object for current player // Heap allocate player object for current player
if (guid == playerGUID) { if (guid == playerGUID) {
return STORM_ALLOC(sizeof(CGPlayer_C) + sizeof(CGPlayerData) + (sizeof(uint32_t) * CGPlayer::TotalFieldsSaved())); return static_cast<CGObject_C*>(STORM_ALLOC(sizeof(CGPlayer_C) + CGPlayer::GetDataSize() + CGPlayer::GetDataSizeSaved()));
} }
// TODO GarbageCollect(typeID, 10000); // TODO GarbageCollect(typeID, 10000);
@ -84,12 +85,13 @@ void* ClntObjMgrAllocObject(OBJECT_TYPE_ID typeID, uint64_t guid) {
} }
// TODO pointer should be fetched via ObjectPtr // TODO pointer should be fetched via ObjectPtr
static_cast<CGObject_C*>(mem)->m_memHandle = memHandle; auto object = static_cast<CGObject_C*>(mem);
object->m_memHandle = memHandle;
return mem; return object;
} }
uint64_t ClntObjMgrGetActivePlayer() { WOWGUID ClntObjMgrGetActivePlayer() {
if (!s_curMgr) { if (!s_curMgr) {
return 0; return 0;
} }
@ -138,6 +140,29 @@ void ClntObjMgrInitializeStd(uint32_t mapID) {
mgr->m_mapID = mapID; mgr->m_mapID = mapID;
} }
void ClntObjMgrLinkInNewObject(CGObject_C* object) {
CHashKeyGUID key(object->m_obj->m_guid);
s_curMgr->m_objects.Insert(object, object->m_obj->m_guid, key);
}
CGObject_C* ClntObjMgrObjectPtr(WOWGUID guid, OBJECT_TYPE type, const char* fileName, int32_t lineNumber) {
if (!s_curMgr || !guid) {
return nullptr;
}
auto object = FindActiveObject(guid);
if (!object) {
return nullptr;
}
if (!(object->m_obj->m_type & type)) {
return nullptr;
}
return object;
}
void ClntObjMgrPop() { void ClntObjMgrPop() {
if (!s_savMgr) { if (!s_savMgr) {
return; return;
@ -156,7 +181,7 @@ void ClntObjMgrPush(ClntObjMgr* mgr) {
s_curMgr = mgr; s_curMgr = mgr;
} }
void ClntObjMgrSetActivePlayer(uint64_t guid) { void ClntObjMgrSetActivePlayer(WOWGUID guid) {
s_curMgr->m_activePlayer = guid; s_curMgr->m_activePlayer = guid;
} }

View File

@ -6,9 +6,9 @@
#include "object/Types.hpp" #include "object/Types.hpp"
#include <cstdint> #include <cstdint>
void* ClntObjMgrAllocObject(OBJECT_TYPE_ID typeID, uint64_t guid); CGObject_C* ClntObjMgrAllocObject(OBJECT_TYPE_ID typeID, WOWGUID guid);
uint64_t ClntObjMgrGetActivePlayer(); WOWGUID ClntObjMgrGetActivePlayer();
ClntObjMgr* ClntObjMgrGetCurrent(); ClntObjMgr* ClntObjMgrGetCurrent();
@ -18,11 +18,15 @@ void ClntObjMgrInitializeShared();
void ClntObjMgrInitializeStd(uint32_t mapID); void ClntObjMgrInitializeStd(uint32_t mapID);
void ClntObjMgrLinkInNewObject(CGObject_C* object);
CGObject_C* ClntObjMgrObjectPtr(WOWGUID guid, OBJECT_TYPE type, const char* fileName, int32_t lineNumber);
void ClntObjMgrPop(); void ClntObjMgrPop();
void ClntObjMgrPush(ClntObjMgr* mgr); void ClntObjMgrPush(ClntObjMgr* mgr);
void ClntObjMgrSetActivePlayer(uint64_t guid); void ClntObjMgrSetActivePlayer(WOWGUID guid);
void ClntObjMgrSetHandlers(); void ClntObjMgrSetHandlers();

142
src/object/client/Util.cpp Normal file
View File

@ -0,0 +1,142 @@
#include "object/client/Util.hpp"
#include "object/client/CClientObjCreate.hpp"
#include "object/client/CGContainer_C.hpp"
#include "object/client/CGCorpse_C.hpp"
#include "object/client/CGDynamicObject_C.hpp"
#include "object/client/CGGameObject_C.hpp"
#include "object/client/CGItem_C.hpp"
#include "object/client/CGObject_C.hpp"
#include "object/client/CGPlayer_C.hpp"
#include "object/client/CGUnit_C.hpp"
#include "object/client/ObjMgr.hpp"
CGObject_C* FindActiveObject(WOWGUID guid) {
return ClntObjMgrGetCurrent()->m_objects.Ptr(guid, CHashKeyGUID(guid));
}
CGObject_C* GetUpdateObject(WOWGUID guid, int32_t* reenable) {
*reenable = false;
// Active object
auto activeObject = FindActiveObject(guid);
if (activeObject) {
activeObject->SetDisablePending(false);
return activeObject;
}
// Disabled object
auto disabledObject = ClntObjMgrGetCurrent()->m_lazyCleanupObjects.Ptr(guid, CHashKeyGUID(guid));
if (disabledObject) {
ClntObjMgrGetCurrent()->m_lazyCleanupObjects.Unlink(disabledObject);
disabledObject->m_link.Unlink();
ClntObjMgrGetCurrent()->m_objects.Insert(disabledObject, guid, CHashKeyGUID(guid));
// These link checks are guaranteed to pass because of the unlink above (both lists share
// the same link). This check is either from an inlined function or is cruft left behind
// after a refactor.
if (
!ClntObjMgrGetCurrent()->m_visibleObjects.IsLinked(disabledObject)
&& !ClntObjMgrGetCurrent()->m_reenabledObjects.IsLinked(disabledObject)
) {
*reenable = true;
ClntObjMgrGetCurrent()->m_reenabledObjects.LinkToTail(disabledObject);
}
return disabledObject;
}
// Object not found
return nullptr;
}
int32_t HandleObjectOutOfRangePass1(CGObject_C* object, OUT_OF_RANGE_TYPE type) {
// TODO arena unit out of range handling
object->HandleOutOfRange(type);
if (object->IsObjectLocked()) {
object->SetDisablePending(true);
return false;
}
object->SetDisablePending(false);
object->Disable();
return true;
}
void HandleObjectOutOfRangePass2(CGObject_C* object) {
// TODO ClearObjectMirrorHandlers(object);
ClntObjMgrGetCurrent()->m_objects.Unlink(object);
if (ClntObjMgrGetCurrent()->m_visibleObjects.IsLinked(object)) {
ClntObjMgrGetCurrent()->m_visibleObjects.UnlinkNode(object);
}
ClntObjMgrGetCurrent()->m_lazyCleanupObjects.Insert(object, object->m_hashval, CHashKeyGUID(object->m_key));
ClntObjMgrGetCurrent()->m_lazyCleanupFifo[object->m_typeID - 1].LinkToTail(object);
}
void InitObject(CGObject_C* object, uint32_t time, CClientObjCreate& objCreate) {
switch (object->m_typeID) {
case ID_ITEM: {
new (object) CGItem_C(time, objCreate);
break;
}
case ID_CONTAINER: {
new (object) CGContainer_C(time, objCreate);
break;
}
case ID_UNIT: {
new (object) CGUnit_C(time, objCreate);
object->AddWorldObject();
break;
}
case ID_PLAYER: {
new (object) CGPlayer_C(time, objCreate);
object->AddWorldObject();
break;
}
case ID_GAMEOBJECT: {
new (object) CGGameObject_C(time, objCreate);
object->AddWorldObject();
break;
}
case ID_DYNAMICOBJECT: {
new (object) CGDynamicObject_C(time, objCreate);
object->AddWorldObject();
break;
}
case ID_CORPSE: {
new (object) CGCorpse_C(time, objCreate);
object->AddWorldObject();
break;
}
default: {
break;
}
}
}

View File

@ -0,0 +1,21 @@
#ifndef OBJECT_CLIENT_UTIL_HPP
#define OBJECT_CLIENT_UTIL_HPP
#include "object/Types.hpp"
#include "util/GUID.hpp"
#include <cstdint>
class CClientObjCreate;
class CGObject_C;
CGObject_C* FindActiveObject(WOWGUID guid);
CGObject_C* GetUpdateObject(WOWGUID guid, int32_t* reenable);
int32_t HandleObjectOutOfRangePass1(CGObject_C* object, OUT_OF_RANGE_TYPE type);
void HandleObjectOutOfRangePass2(CGObject_C* object);
void InitObject(CGObject_C* object, uint32_t time, CClientObjCreate& objCreate);
#endif

View File

@ -0,0 +1,55 @@
#include "object/movement/CMoveSpline.hpp"
#include "util/DataStore.hpp"
#include <common/Time.hpp>
void CMoveSpline::Skip(CDataStore* msg) {
uint32_t flags;
msg->Get(flags);
uint32_t faceBytes = 0;
if (flags & 0x20000) {
faceBytes = 4;
} else if (flags & 0x10000) {
faceBytes = 8;
} else if (flags & 0x8000) {
faceBytes = 12;
}
void* data;
msg->GetDataInSitu(data, faceBytes + 28);
uint32_t splinePoints = 0;
msg->Get(splinePoints);
msg->GetDataInSitu(data, (splinePoints * sizeof(C3Vector)) + 13);
}
CDataStore& operator>>(CDataStore& msg, CMoveSpline& spline) {
msg.Get(spline.flags);
if (spline.flags & 0x20000) {
msg.Get(spline.face.facing);
} else if (spline.flags & 0x10000) {
msg.Get(spline.face.guid);
} else if (spline.flags & 0x8000) {
msg >> spline.face.spot;
}
uint32_t val;
msg.Get(val);
spline.start = OsGetAsyncTimeMsPrecise() - val;
msg.Get(spline.uint2C);
msg.Get(spline.uint30);
msg.Get(spline.float204);
msg.Get(spline.float208);
msg.Get(spline.float20C);
msg.Get(spline.uint210);
msg >> spline.spline;
msg >> spline.vector1F8;
return msg;
}

View File

@ -0,0 +1,34 @@
#ifndef OBJECT_MOVEMENT_C_MOVE_SPLINE_HPP
#define OBJECT_MOVEMENT_C_MOVE_SPLINE_HPP
#include "util/C3Spline.hpp"
#include "util/GUID.hpp"
#include <common/DataStore.hpp>
#include <tempest/Vector.hpp>
struct CMoveSpline {
// TODO
union {
C3Vector spot = {};
WOWGUID guid;
float facing;
} face;
uint32_t flags;
uint32_t start;
// TODO
uint32_t uint2C;
uint32_t uint30;
C3Spline_CatmullRom spline;
C3Vector vector1F8;
float float204;
float float208;
float float20C;
uint32_t uint210;
// TODO
static void Skip(CDataStore* msg);
};
CDataStore& operator>>(CDataStore& msg, CMoveSpline& spline);
#endif

View File

@ -0,0 +1,81 @@
#include "object/movement/CMovementStatus.hpp"
#include "util/DataStore.hpp"
uint32_t CMovementStatus::Skip(CDataStore* msg) {
uint32_t moveFlags = 0;
msg->Get(moveFlags);
uint16_t uint14;
msg->Get(uint14);
void* data;
msg->GetDataInSitu(data, 20);
uint32_t skipBytes = 0;
if (moveFlags & 0x200) {
SmartGUID guid;
*msg >> guid;
skipBytes += 21;
if (uint14 & 0x400) {
skipBytes += 4;
}
}
if ((moveFlags & (0x200000 | 0x2000000)) || (uint14 & 0x20)) {
skipBytes += 4;
}
skipBytes += 4;
if (moveFlags & 0x1000) {
skipBytes += 16;
}
if (moveFlags & 0x4000000) {
skipBytes += 4;
}
msg->GetDataInSitu(data, skipBytes);
return moveFlags;
}
CDataStore& operator>>(CDataStore& msg, CMovementStatus& move) {
msg.Get(move.moveFlags);
msg.Get(move.uint14);
msg.Get(move.uint0);
msg >> move.position18;
msg.Get(move.facing34);
if (move.moveFlags & 0x200) {
// TODO
} else {
move.transport = 0;
// TODO
}
if ((move.moveFlags & (0x200000 | 0x2000000)) || (move.uint14 & 0x20)) {
msg.Get(move.float38);
} else {
move.float38 = 0.0f;
}
msg.Get(move.uint3C);
if (move.moveFlags & 0x1000) {
msg.Get(move.float40);
msg.Get(move.float44);
msg.Get(move.float48);
msg.Get(move.float4C);
}
if (move.moveFlags & 0x4000000) {
msg.Get(move.float50);
}
return msg;
}

View File

@ -0,0 +1,34 @@
#ifndef OBJECT_MOVEMENT_C_MOVEMENT_STATUS_HPP
#define OBJECT_MOVEMENT_C_MOVEMENT_STATUS_HPP
#include "util/GUID.hpp"
#include <common/DataStore.hpp>
#include <tempest/Vector.hpp>
#include <cstdint>
struct CMovementStatus {
uint32_t uint0 = 0;
// TODO
WOWGUID transport = 0;
uint32_t moveFlags = 0x0;
uint16_t uint14 = 0;
// TODO
C3Vector position18;
float facing24 = 0.0f;
C3Vector position28;
float facing34 = 0.0f;
float float38 = 0.0f;
uint32_t uint3C = 0;
float float40 = 0.0f;
float float44 = 0.0f;
float float48 = 0.0f;
float float4C = 0.0f;
float float50 = 0.0f;
// TODO
static uint32_t Skip(CDataStore* msg);
};
CDataStore& operator>>(CDataStore& msg, CMovementStatus& move);
#endif

20
src/util/C3Spline.cpp Normal file
View File

@ -0,0 +1,20 @@
#include "util/C3Spline.hpp"
#include <tempest/vector/C3Vector.hpp>
CDataStore& operator>>(CDataStore& msg, C3Spline_CatmullRom& spline) {
uint32_t pointCount = 0;
msg.Get(pointCount);
void* points;
msg.GetDataInSitu(points, sizeof(C3Vector) * pointCount);
uint8_t splineMode;
msg.Get(splineMode);
// TODO spline.splineMode = splineMode;
if (pointCount && msg.IsValid()) {
// TODO spline.SetPoints()
}
return msg;
}

20
src/util/C3Spline.hpp Normal file
View File

@ -0,0 +1,20 @@
#ifndef UTIL_C3_SPLINE_HPP
#define UTIL_C3_SPLINE_HPP
#include <common/DataStore.hpp>
// TODO move these classes to typhoon
class C3Spline {
public:
// TODO
};
class C3Spline_CatmullRom : public C3Spline {
public:
// TODO
};
// TODO move this operator>> to util/DataStore.hpp
CDataStore& operator>>(CDataStore& msg, C3Spline_CatmullRom& spline);
#endif

View File

@ -1,9 +0,0 @@
#include "util/CHashKeyGUID.hpp"
CHashKeyGUID::CHashKeyGUID() {
this->m_guid = 0;
}
CHashKeyGUID::CHashKeyGUID(uint64_t guid) {
this->m_guid = guid;
}

View File

@ -1,17 +0,0 @@
#ifndef UTIL_C_HASH_KEY_GUID_HPP
#define UTIL_C_HASH_KEY_GUID_HPP
#include <cstdint>
class CHashKeyGUID {
public:
// Public member functions
CHashKeyGUID();
CHashKeyGUID(uint64_t guid);
private:
// Private member variables
uint64_t m_guid;
};
#endif

View File

@ -1,5 +1,6 @@
file(GLOB PRIVATE_SOURCES file(GLOB PRIVATE_SOURCES
"*.cpp" "*.cpp"
"guid/*.cpp"
) )
if(WHOA_SYSTEM_MAC) if(WHOA_SYSTEM_MAC)

8
src/util/GUID.hpp Normal file
View File

@ -0,0 +1,8 @@
#ifndef UTIL_GUID_HPP
#define UTIL_GUID_HPP
#include "util/guid/CHashKeyGUID.hpp"
#include "util/guid/SmartGUID.hpp"
#include "util/guid/Types.hpp"
#endif

View File

@ -0,0 +1,17 @@
#include "util/guid/CHashKeyGUID.hpp"
CHashKeyGUID::CHashKeyGUID() {
this->m_guid = 0;
}
CHashKeyGUID::CHashKeyGUID(WOWGUID guid) {
this->m_guid = guid;
}
bool CHashKeyGUID::operator==(WOWGUID guid) const {
return this->m_guid == guid;
}
bool CHashKeyGUID::operator==(const CHashKeyGUID& key) const {
return this->m_guid == key.m_guid;
}

View File

@ -0,0 +1,20 @@
#ifndef UTIL_GUID_C_HASH_KEY_GUID_HPP
#define UTIL_GUID_C_HASH_KEY_GUID_HPP
#include "util/guid/Types.hpp"
#include <cstdint>
class CHashKeyGUID {
public:
// Public member functions
CHashKeyGUID();
CHashKeyGUID(WOWGUID guid);
bool operator==(WOWGUID guid) const;
bool operator==(const CHashKeyGUID& key) const;
private:
// Private member variables
WOWGUID m_guid;
};
#endif

View File

@ -0,0 +1,29 @@
#include "util/guid/SmartGUID.hpp"
#include <common/DataStore.hpp>
SmartGUID::operator WOWGUID() const {
return this->guid;
}
SmartGUID& SmartGUID::operator=(WOWGUID guid) {
this->guid = guid;
return *this;
}
CDataStore& operator>>(CDataStore& msg, SmartGUID& guid) {
guid = 0;
uint8_t mask;
msg.Get(mask);
for (int32_t i = 0; i < 8; i++) {
if (mask & (1 << i)) {
uint8_t byte;
msg.Get(byte);
guid.guid |= static_cast<uint64_t>(byte) << (i * 8);
}
}
return msg;
}

View File

@ -0,0 +1,18 @@
#ifndef UTIL_GUID_SMART_GUID_HPP
#define UTIL_GUID_SMART_GUID_HPP
#include "util/guid/Types.hpp"
#include <cstdint>
class CDataStore;
struct SmartGUID {
WOWGUID guid;
operator WOWGUID() const;
SmartGUID& operator=(WOWGUID value);
};
CDataStore& operator>>(CDataStore& msg, SmartGUID& guid);
#endif

8
src/util/guid/Types.hpp Normal file
View File

@ -0,0 +1,8 @@
#ifndef UTIL_GUID_TYPES_HPP
#define UTIL_GUID_TYPES_HPP
#include <cstdint>
typedef uint64_t WOWGUID;
#endif

View File

@ -6,10 +6,49 @@
#include "world/Weather.hpp" #include "world/Weather.hpp"
#include <storm/Memory.hpp> #include <storm/Memory.hpp>
uint32_t CWorld::s_curTimeMs;
float CWorld::s_curTimeSec;
uint32_t CWorld::s_enables; uint32_t CWorld::s_enables;
uint32_t CWorld::s_enables2; uint32_t CWorld::s_enables2;
uint32_t CWorld::s_gameTimeFixed;
float CWorld::s_gameTimeSec;
uint32_t CWorld::s_tickTimeFixed;
uint32_t CWorld::s_tickTimeMs;
float CWorld::s_tickTimeSec;
Weather* CWorld::s_weather; Weather* CWorld::s_weather;
uint32_t CWorld::GetCurTimeMs() {
return CWorld::s_curTimeMs;
}
float CWorld::GetCurTimeSec() {
return CWorld::s_curTimeSec;
}
uint32_t CWorld::GetFixedPrecisionTime(float timeSec) {
return static_cast<uint32_t>(timeSec * 1024.0f);
}
uint32_t CWorld::GetGameTimeFixed() {
return CWorld::s_gameTimeFixed;
}
float CWorld::GetGameTimeSec() {
return CWorld::s_gameTimeSec;
}
uint32_t CWorld::GetTickTimeFixed() {
return CWorld::s_tickTimeFixed;
}
uint32_t CWorld::GetTickTimeMs() {
return CWorld::s_tickTimeMs;
}
float CWorld::GetTickTimeSec() {
return CWorld::s_tickTimeSec;
}
void CWorld::Initialize() { void CWorld::Initialize() {
CWorld::s_enables |= CWorld::s_enables |=
Enables::Enable_1 Enables::Enable_1
@ -26,6 +65,9 @@ void CWorld::Initialize() {
| Enables::Enable_Particulates | Enables::Enable_Particulates
| Enables::Enable_LowDetail; | Enables::Enable_LowDetail;
CWorld::s_gameTimeFixed = 0;
CWorld::s_gameTimeSec = 0.0f;
// TODO // TODO
if (GxCaps().m_shaderTargets[GxSh_Pixel] > GxShPS_none) { if (GxCaps().m_shaderTargets[GxSh_Pixel] > GxShPS_none) {
@ -58,3 +100,23 @@ void CWorld::LoadMap(const char* mapName, const C3Vector& position, int32_t zone
// TODO // TODO
} }
int32_t CWorld::OnTick(const EVENT_DATA_TICK* data, void* param) {
CWorld::SetUpdateTime(data->tickTimeSec, data->curTimeMs);
return 1;
}
void CWorld::SetUpdateTime(float tickTimeSec, uint32_t curTimeMs) {
auto tickTimeFixed = CWorld::GetFixedPrecisionTime(tickTimeSec);
CWorld::s_curTimeMs = curTimeMs;
CWorld::s_curTimeSec = static_cast<float>(curTimeMs) * 0.001f;
CWorld::s_gameTimeFixed += tickTimeFixed;
CWorld::s_gameTimeSec += tickTimeSec;
CWorld::s_tickTimeFixed = tickTimeFixed;
CWorld::s_tickTimeMs = static_cast<uint32_t>(tickTimeSec * 1000.0f);
CWorld::s_tickTimeSec = tickTimeSec;
}

View File

@ -1,6 +1,7 @@
#ifndef WORLD_C_WORLD_HPP #ifndef WORLD_C_WORLD_HPP
#define WORLD_C_WORLD_HPP #define WORLD_C_WORLD_HPP
#include "event/Event.hpp"
#include <tempest/Vector.hpp> #include <tempest/Vector.hpp>
#include <cstdint> #include <cstdint>
@ -44,14 +45,36 @@ class CWorld {
Enable_HwPcf = 0x2 Enable_HwPcf = 0x2
}; };
// Static variables // Public static variables
static uint32_t s_enables; static uint32_t s_enables;
static uint32_t s_enables2; static uint32_t s_enables2;
static Weather* s_weather; static Weather* s_weather;
// Static functions // Public static functions
static void Initialize(void); static uint32_t GetCurTimeMs();
static float GetCurTimeSec();
static uint32_t GetGameTimeFixed();
static float GetGameTimeSec();
static uint32_t GetTickTimeFixed();
static uint32_t GetTickTimeMs();
static float GetTickTimeSec();
static void Initialize();
static void LoadMap(const char* mapName, const C3Vector& position, int32_t zoneID); static void LoadMap(const char* mapName, const C3Vector& position, int32_t zoneID);
static int32_t OnTick(const EVENT_DATA_TICK* data, void* param);
static void SetUpdateTime(float tickTimeSec, uint32_t curTimeMs);
private:
// Private static variables
static uint32_t s_curTimeMs;
static float s_curTimeSec;
static uint32_t s_gameTimeFixed;
static float s_gameTimeSec;
static uint32_t s_tickTimeFixed;
static uint32_t s_tickTimeMs;
static float s_tickTimeSec;
// Private static functions
static uint32_t GetFixedPrecisionTime(float timeSec);
}; };
#endif #endif

View File

@ -22,6 +22,8 @@ if(WHOA_SYSTEM_MAC)
"-framework AppKit" "-framework AppKit"
"-framework Carbon" "-framework Carbon"
"-framework IOKit" "-framework IOKit"
"-framework Metal"
"-framework QuartzCore"
) )
endif() endif()