Reconstruct readable C++ and organize cohesive source subsystems

Administrative source import: native x86 compilation passed for 423 authored units. Source placement and submission states are migrated separately; this commit does not imply peer acceptance.

Previous head: 35d2a8cb36
Payload SHA256: 592f016d2730c5593bb653aa054c1e5f76a6df72c8f5a09e66f74876e2e33dee
This commit is contained in:
ragnarok-clanker 2026-10-25 07:42:41 +00:00
commit a47d20f8be
890 changed files with 11796 additions and 16664 deletions

View file

@ -4,7 +4,7 @@ NamespaceIndentation: All
FixNamespaceComments: false
TabWidth: 2
UseTab: Never
ColumnLimit: 120
ColumnLimit: 160
AlignAfterOpenBracket: BlockIndent
ContinuationIndentWidth: 2
AlwaysBreakAfterReturnType: None
@ -12,7 +12,7 @@ BreakBeforeBraces: Custom
BraceWrapping:
AfterFunction: false
AllowShortIfStatementsOnASingleLine: Never
InsertBraces: true
InsertBraces: false
AllowShortLoopsOnASingleLine: false
AllowShortFunctionsOnASingleLine: None
AllowShortBlocksOnASingleLine: Never
@ -21,25 +21,13 @@ SpaceBeforeParens: Custom
SpaceBeforeParensOptions:
AfterControlStatements: true
AfterFunctionDefinitionName: false
BinPackParameters: false
AllowAllParametersOfDeclarationOnNextLine: false
PenaltyBreakBeforeFirstCallParameter: 0
BinPackArguments: true
BinPackParameters: BinPack
AllowAllParametersOfDeclarationOnNextLine: true
PenaltyBreakBeforeFirstCallParameter: 19
PointerAlignment: Left
# Include sorting:
# 1. pch (must stay first) 2. other WoW.exe project headers
# 3. generated gen/ headers 4. system <...> headers
# Each group is alphabetised; Regroup re-buckets across blank lines.
# IncludeIsMainRegex is set to never match so no header is auto-pinned above pch
# (clang-format otherwise forces the "main" header to the very top).
SortIncludes: CaseSensitive
IncludeBlocks: Regroup
IncludeIsMainRegex: "(WILL_NEVER_MATCH_zzz)$"
IncludeCategories:
- Regex: '^"pch(-impl)?\.h"'
Priority: 1
- Regex: '^"gen/'
Priority: 3
- Regex: '^<'
Priority: 4
- Regex: '^"'
Priority: 2
BreakStringLiterals: false
ReflowComments: Never
MaxEmptyLinesToKeep: 1
SortIncludes: Never
IncludeBlocks: Preserve

View file

@ -10,12 +10,12 @@ add_subdirectory(ThirdParty)
add_library(RagnarokUtility STATIC
Source/Utility/XorBytes.cpp
Source/Utility/Base64.cpp
Source/Utility/GroupedInteger.cpp
Source/Utility/LanguageCharset.cpp
Source/Utility/ClientAngles.cpp
Source/Utility/AffineMatrix.cpp
Source/Utility/AffineLookAt.cpp
Source/Utility/RayTriangle.cpp
Source/Utility/Text/GroupedInteger.cpp
Source/Utility/Text/LanguageCharset.cpp
Source/Utility/Math/ClientAngles.cpp
Source/Utility/Math/AffineMatrix.cpp
Source/Utility/Math/AffineLookAt.cpp
Source/Utility/Math/RayTriangle.cpp
Source/Utility/Rijndael.cpp
)
@ -28,21 +28,21 @@ set_target_properties(RagnarokUtility PROPERTIES CXX_EXTENSIONS OFF)
if(WIN32)
target_sources(RagnarokUtility PRIVATE
Source/Utility/GuidParse.cpp
Source/Utility/NSyncObject.cpp
Source/Utility/CSyncObject.cpp
Source/Utility/NThread.cpp
Source/Utility/NMessageQueue.cpp
Source/Utility/NMessageMgr.cpp
Source/Utility/NObject.cpp
Source/Utility/NRecycleObject.cpp
Source/Utility/NRecycleObjectPoolMgr.cpp
Source/Utility/NAsyncWork.cpp
Source/Utility/NAsyncWorkQueue.cpp
Source/Utility/NAsyncWorkThread.cpp
Source/Utility/NAsyncWorkMgr.cpp
Source/Utility/AsyncDiagnostic.cpp
Source/Utility/Threading/NSyncObject.cpp
Source/Utility/Threading/CSyncObject.cpp
Source/Utility/Threading/NThread.cpp
Source/Utility/Async/NMessageQueue.cpp
Source/Utility/Async/NMessageMgr.cpp
Source/Utility/Async/NObject.cpp
Source/Utility/Async/NRecycleObject.cpp
Source/Utility/Async/NRecycleObjectPoolMgr.cpp
Source/Utility/Async/NAsyncWork.cpp
Source/Utility/Async/NAsyncWorkQueue.cpp
Source/Utility/Async/NAsyncWorkThread.cpp
Source/Utility/Async/NAsyncWorkMgr.cpp
Source/Utility/Async/AsyncDiagnostic.cpp
Source/Contents/InstantVar.cpp
Source/Utility/FormatString.cpp
Source/Utility/Text/FormatString.cpp
)
target_compile_definitions(RagnarokUtility PUBLIC
WIN32_LEAN_AND_MEAN NOMINMAX _ITERATOR_DEBUG_LEVEL=0
@ -69,31 +69,32 @@ if(WIN32)
set_target_properties(RagnarokArchive PROPERTIES CXX_EXTENSIONS OFF)
add_library(RagnarokClientStartup STATIC
Source/Client/Launcher.cpp
Source/Client/ApplicationWindow.cpp
Source/Client/ErrorDialog.cpp
Source/Client/UnhandledExceptionHandler.cpp
Source/Client/ModeCursor.cpp
Source/Client/Mouse.cpp
Source/Client/Application/Launcher.cpp
Source/Client/Application/ApplicationWindow.cpp
Source/Client/Application/ErrorDialog.cpp
Source/Client/Application/UnhandledExceptionHandler.cpp
Source/Client/Mode/ModeCursor.cpp
Source/Client/Mode/ActiveGameMode.cpp
Source/Client/Input/Mouse.cpp
Source/Client/ClientOptions.cpp
Source/Client/TextInputBuffer.cpp
Source/Client/ImeInput.cpp
Source/Client/TraditionalKeyInput.cpp
Source/Client/InputCharset.cpp
Source/Client/BrowserWindowSizing.cpp
Source/Client/BrowserInterface.cpp
Source/Client/BrowserCursor.cpp
Source/Client/BrowserAddressEdit.cpp
Source/Client/BrowserHostWindow.cpp
Source/Client/BrowserCommandTarget.cpp
Source/Client/BrowserInPlace.cpp
Source/Client/BrowserDocumentUI.cpp
Source/Client/BrowserClientSite.cpp
Source/Client/BrowserAddressBar.cpp
Source/Client/BrowserFrame.cpp
Source/Client/BrowserSiteAttachment.cpp
Source/Client/BrowserClose.cpp
Source/Client/BrowserCreation.cpp
Source/Client/Input/TextInputBuffer.cpp
Source/Client/Input/ImeInput.cpp
Source/Client/Input/TraditionalKeyInput.cpp
Source/Client/Input/InputCharset.cpp
Source/Client/Browser/BrowserWindowSizing.cpp
Source/Client/Browser/BrowserInterface.cpp
Source/Client/Browser/BrowserCursor.cpp
Source/Client/Browser/BrowserAddressEdit.cpp
Source/Client/Browser/BrowserHostWindow.cpp
Source/Client/Browser/BrowserCommandTarget.cpp
Source/Client/Browser/BrowserInPlace.cpp
Source/Client/Browser/BrowserDocumentUI.cpp
Source/Client/Browser/BrowserClientSite.cpp
Source/Client/Browser/BrowserAddressBar.cpp
Source/Client/Browser/BrowserFrame.cpp
Source/Client/Browser/BrowserSiteAttachment.cpp
Source/Client/Browser/BrowserClose.cpp
Source/Client/Browser/BrowserCreation.cpp
)
target_include_directories(RagnarokClientStartup PUBLIC
"${CMAKE_CURRENT_SOURCE_DIR}/Source"
@ -104,74 +105,74 @@ if(WIN32)
set_target_properties(RagnarokClientStartup PROPERTIES CXX_EXTENSIONS OFF)
add_library(RagnarokRender STATIC
Source/Render/RenderPrimitive.cpp
Source/Render/RenderPrimitivePool.cpp
Source/Render/RenderCommandPool.cpp
Source/Render/LightmappedPrimitive.cpp
Source/Render/DepthAlpha.cpp
Source/Render/RenderVertexPool.cpp
Source/Render/RenderProjection.cpp
Source/Render/RendererViewport.cpp
Source/Render/RenderRay.cpp
Source/Render/BitmapPixels.cpp
Source/Render/Surface.cpp
Source/Render/RenderQueues.cpp
Source/Render/Texture.cpp
Source/Render/UIRPData.cpp
Source/Render/SurfaceDX9.cpp
Source/Render/SurfaceDX7.cpp
Source/Render/D3DX9Runtime.cpp
Source/Render/TextureDX9.cpp
Source/Render/TextureDX7.cpp
Source/Render/TextureBindingDX7.cpp
Source/Render/TextureAllocationDX7.cpp
Source/Render/BitmapTextureCache.cpp
Source/Render/SpriteAtlas.cpp
Source/Render/DeviceContext.cpp
Source/Render/DCBitmap.cpp
Source/Render/DCSurface.cpp
Source/Render/DeviceStateDX9.cpp
Source/Render/DeviceOwnerDX9.cpp
Source/Render/DeviceOwnerDX7.cpp
Source/Render/DeviceCapabilitiesDX7.cpp
Source/Render/TextureCalibrationDX7.cpp
Source/Render/Primitives/RenderPrimitive.cpp
Source/Render/Primitives/RenderPrimitivePool.cpp
Source/Render/Primitives/RenderCommandPool.cpp
Source/Render/Primitives/LightmappedPrimitive.cpp
Source/Render/Primitives/DepthAlpha.cpp
Source/Render/Primitives/RenderVertexPool.cpp
Source/Render/Projection/RenderProjection.cpp
Source/Render/Projection/RendererViewport.cpp
Source/Render/Projection/RenderRay.cpp
Source/Render/Textures/BitmapPixels.cpp
Source/Render/Textures/Surface.cpp
Source/Render/Primitives/RenderQueues.cpp
Source/Render/Textures/Texture.cpp
Source/Render/Primitives/UIRPData.cpp
Source/Render/DX9/SurfaceDX9.cpp
Source/Render/DX7/SurfaceDX7.cpp
Source/Render/DX9/D3DX9Runtime.cpp
Source/Render/DX9/TextureDX9.cpp
Source/Render/DX7/TextureDX7.cpp
Source/Render/DX7/TextureBindingDX7.cpp
Source/Render/DX7/TextureAllocationDX7.cpp
Source/Render/Textures/BitmapTextureCache.cpp
Source/Render/Textures/SpriteAtlas.cpp
Source/Render/DeviceContext/DeviceContext.cpp
Source/Render/DeviceContext/DCBitmap.cpp
Source/Render/DeviceContext/DCSurface.cpp
Source/Render/DX9/DeviceStateDX9.cpp
Source/Render/DX9/DeviceOwnerDX9.cpp
Source/Render/DX7/DeviceOwnerDX7.cpp
Source/Render/DX7/DeviceCapabilitiesDX7.cpp
Source/Render/DX7/TextureCalibrationDX7.cpp
Source/Render/RenderAdapter.cpp
Source/Render/RenderAdapterDX7.cpp
Source/Render/DX7/RenderAdapterDX7.cpp
Source/Render/RenderBackends.cpp
Source/Render/DisplayMode.cpp
Source/Render/DisplayModeDX7.cpp
Source/Render/DirectDrawEnumeration.cpp
Source/Render/DeviceRecoveryDX9.cpp
Source/Render/BackBufferDX9.cpp
Source/Render/BackBufferDX7.cpp
Source/Render/DX7/DisplayModeDX7.cpp
Source/Render/DX7/DirectDrawEnumeration.cpp
Source/Render/DX9/DeviceRecoveryDX9.cpp
Source/Render/DX9/BackBufferDX9.cpp
Source/Render/DX7/BackBufferDX7.cpp
Source/Render/Direct3DErrors.cpp
Source/Render/RendererBackBuffer.cpp
Source/Render/DX9/RendererBackBuffer.cpp
Source/Render/Renderer.cpp
Source/Render/RendererDX9.cpp
Source/Render/RenderSystemDX7.cpp
Source/Render/RenderSystemDX9.cpp
Source/Render/RendererDX9Operations.cpp
Source/Render/RendererDX7Operations.cpp
Source/Render/RenderToTextureDX7.cpp
Source/Render/TextureModesDX9.cpp
Source/Render/TextureModesDX7.cpp
Source/Render/DX9/RendererDX9.cpp
Source/Render/DX7/RenderSystemDX7.cpp
Source/Render/DX9/RenderSystemDX9.cpp
Source/Render/DX9/RendererDX9Operations.cpp
Source/Render/DX7/RendererDX7Operations.cpp
Source/Render/DX7/RenderToTextureDX7.cpp
Source/Render/DX9/TextureModesDX9.cpp
Source/Render/DX7/TextureModesDX7.cpp
Source/Render/TextureStageModes.cpp
Source/Render/RendererFogDX9.cpp
Source/Render/RendererFogDX7.cpp
Source/Render/OpaqueQueuesDX9.cpp
Source/Render/GroundQueuesDX9.cpp
Source/Render/AlphaQueuesDX9.cpp
Source/Render/QueuedDrawingDX9.cpp
Source/Render/RendererFrameDX9.cpp
Source/Render/ScreenshotDX9.cpp
Source/Render/ScreenshotDX7.cpp
Source/Contents/Effect.cpp
Source/Contents/EffectLists.cpp
Source/Render/DX9/RendererFogDX9.cpp
Source/Render/DX7/RendererFogDX7.cpp
Source/Render/DX9/OpaqueQueuesDX9.cpp
Source/Render/DX9/GroundQueuesDX9.cpp
Source/Render/DX9/AlphaQueuesDX9.cpp
Source/Render/DX9/QueuedDrawingDX9.cpp
Source/Render/DX9/RendererFrameDX9.cpp
Source/Render/DX9/ScreenshotDX9.cpp
Source/Render/DX7/ScreenshotDX7.cpp
Source/Contents/Effects/Effect.cpp
Source/Contents/Effects/EffectLists.cpp
Source/Render/BlendColor.cpp
Source/Render/RendererPresentation.cpp
Source/Render/RendererPresentationDX7.cpp
Source/Render/FontCache.cpp
Source/Render/TextContext.cpp
Source/Render/DX9/RendererPresentation.cpp
Source/Render/DX7/RendererPresentationDX7.cpp
Source/Render/Text/FontCache.cpp
Source/Render/Text/TextContext.cpp
)
target_include_directories(RagnarokRender PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/Source")
target_compile_features(RagnarokRender PUBLIC cxx_std_20)
@ -180,116 +181,116 @@ if(WIN32)
target_link_libraries(RagnarokRender PUBLIC gdi32 winmm gdiplus d3d9 ddraw dxguid)
add_library(RagnarokUI STATIC
Source/UI/WindowGeometry.cpp
Source/UI/WindowCoordinates.cpp
Source/UI/WindowAncestry.cpp
Source/UI/WindowRegistration.cpp
Source/UI/WindowRetirement.cpp
Source/UI/WindowOrdering.cpp
Source/UI/WindowMouseHit.cpp
Source/UI/UIWindow.cpp
Source/UI/UIControl.cpp
Source/UI/UIDropDownBox.cpp
Source/UI/ChatSuggestions.cpp
Source/UI/ItemTagRetirement.cpp
Source/UI/SnapRectangle.cpp
Source/UI/SnapObject.cpp
Source/UI/SnapMgr.cpp
Source/UI/WindowSnapping.cpp
Source/UI/FrameTextCache.cpp
Source/UI/FrameFocus.cpp
Source/UI/InputFocus.cpp
Source/UI/UIFrameWnd.cpp
Source/UI/ShortcutGrid.cpp
Source/UI/WindowPolicy.cpp
Source/UI/UIButton.cpp
Source/UI/UIBasicButton.cpp
Source/UI/UITextButton.cpp
Source/UI/UINaviLinkButton.cpp
Source/UI/UIEditCtrl.cpp
Source/UI/UIEditVariants.cpp
Source/UI/UIEditLinks.cpp
Source/UI/UIBitmapButton.cpp
Source/UI/UIBmpTextButton.cpp
Source/UI/UIJobSlotButton.cpp
Source/UI/UIPartyInfoWnd.cpp
Source/UI/UIAdvenPartyBoardWnd.cpp
Source/UI/UIApplyForPartyWnd.cpp
Source/UI/UIRegisterPartyWnd.cpp
Source/UI/UIRequestJoinPartyMgr.cpp
Source/UI/UIRequestJoinPartyWnd.cpp
Source/UI/UIChooseSellBuyWnd.cpp
Source/UI/UIExchangeAcceptWnd.cpp
Source/UI/UIJoinPartyAcceptWnd.cpp
Source/Network/PartyJoinRequest.cpp
Source/UI/UICheckBox.cpp
Source/UI/UIScrollBar.cpp
Source/UI/UIScrollBarNavi.cpp
Source/UI/UIListBox.cpp
Source/UI/UIListBoxEx.cpp
Source/UI/UIComboBoxEx.cpp
Source/UI/UIComboBoxDefWnd.cpp
Source/UI/TextMarkup.cpp
Source/UI/PixelTextWrapping.cpp
Source/UI/ItemLinkDisplay.cpp
Source/UI/UITextViewer.cpp
Source/UI/UITextViewerLinks.cpp
Source/UI/UITextViewerMessages.cpp
Source/UI/Layout/WindowGeometry.cpp
Source/UI/Layout/WindowCoordinates.cpp
Source/UI/Window/WindowAncestry.cpp
Source/UI/Window/WindowRegistration.cpp
Source/UI/Window/WindowRetirement.cpp
Source/UI/Window/WindowOrdering.cpp
Source/UI/Window/WindowMouseHit.cpp
Source/UI/Window/UIWindow.cpp
Source/UI/Window/UIControl.cpp
Source/UI/Lists/UIDropDownBox.cpp
Source/UI/Chat/ChatSuggestions.cpp
Source/UI/Edit/ItemTagRetirement.cpp
Source/UI/Layout/SnapRectangle.cpp
Source/UI/Layout/SnapObject.cpp
Source/UI/Layout/SnapMgr.cpp
Source/UI/Layout/WindowSnapping.cpp
Source/UI/Window/FrameTextCache.cpp
Source/UI/Window/FrameFocus.cpp
Source/UI/Window/InputFocus.cpp
Source/UI/Window/UIFrameWnd.cpp
Source/UI/Shortcuts/ShortcutGrid.cpp
Source/UI/Window/WindowPolicy.cpp
Source/UI/Buttons/UIButton.cpp
Source/UI/Buttons/UIBasicButton.cpp
Source/UI/Buttons/UITextButton.cpp
Source/UI/Buttons/UINaviLinkButton.cpp
Source/UI/Edit/UIEditCtrl.cpp
Source/UI/Edit/UIEditVariants.cpp
Source/UI/Edit/UIEditLinks.cpp
Source/UI/Buttons/UIBitmapButton.cpp
Source/UI/Buttons/UIBmpTextButton.cpp
Source/UI/Buttons/UIJobSlotButton.cpp
Source/UI/Party/UIPartyInfoWnd.cpp
Source/UI/Party/UIAdvenPartyBoardWnd.cpp
Source/UI/Party/UIApplyForPartyWnd.cpp
Source/UI/Party/UIRegisterPartyWnd.cpp
Source/UI/Party/UIRequestJoinPartyMgr.cpp
Source/UI/Party/UIRequestJoinPartyWnd.cpp
Source/UI/Acceptance/UIChooseSellBuyWnd.cpp
Source/UI/Acceptance/UIExchangeAcceptWnd.cpp
Source/UI/Acceptance/UIJoinPartyAcceptWnd.cpp
Source/Network/Packets/PartyJoinRequest.cpp
Source/UI/Buttons/UICheckBox.cpp
Source/UI/Lists/UIScrollBar.cpp
Source/UI/Lists/UIScrollBarNavi.cpp
Source/UI/Lists/UIListBox.cpp
Source/UI/Lists/UIListBoxEx.cpp
Source/UI/Lists/UIComboBoxEx.cpp
Source/UI/Lists/UIComboBoxDefWnd.cpp
Source/UI/Text/TextMarkup.cpp
Source/UI/Text/PixelTextWrapping.cpp
Source/UI/Text/ItemLinkDisplay.cpp
Source/UI/Text/UITextViewer.cpp
Source/UI/Text/UITextViewerLinks.cpp
Source/UI/Text/UITextViewerMessages.cpp
Source/UI/UIStaticBitmap.cpp
Source/UI/UIStaticText.cpp
Source/UI/UIMessageBox.cpp
Source/UI/WindowDialogs.cpp
Source/UI/Text/UIStaticText.cpp
Source/UI/Window/UIMessageBox.cpp
Source/UI/Window/WindowDialogs.cpp
Source/Client/ReplayPacketRecorder.cpp
Source/UI/CooldownState.cpp
Source/UI/CooldownDrawing.cpp
Source/UI/CooldownOwner.cpp
Source/UI/ShortcutCooldowns.cpp
Source/UI/ItemDrawing.cpp
Source/UI/ShortcutPainting.cpp
Source/UI/ShortcutBindings.cpp
Source/UI/ShortcutLayout.cpp
Source/UI/ShortcutActivation.cpp
Source/UI/ShortcutControls.cpp
Source/UI/ShortcutControlEvents.cpp
Source/UI/ShortcutTooltip.cpp
Source/UI/ShortcutPress.cpp
Source/UI/ShortcutDrop.cpp
Source/UI/ShortcutUse.cpp
Source/UI/ShortcutVisibility.cpp
Source/UI/ShortcutDetails.cpp
Source/UI/SkillDetailClose.cpp
Source/UI/NormalItemSlotLoad.cpp
Source/UI/UIShortCutWnd.cpp
Source/UI/TextWrapping.cpp
Source/UI/ChatNotifications.cpp
Source/UI/BrowserFactory.cpp
Source/UI/BrowserPopupDispatch.cpp
Source/UI/WindowFrameUpdate.cpp
Source/UI/UIBalloonText.cpp
Source/UI/UITransBalloonText.cpp
Source/UI/ColoredText.cpp
Source/UI/WindowBorder.cpp
Source/UI/EditTextState.cpp
Source/UI/EditViewport.cpp
Source/UI/EditPainting.cpp
Source/UI/PriceColor.cpp
Source/UI/MerchantShopRefresh.cpp
Source/UI/NavigationLink.cpp
Source/UI/TextFitting.cpp
Source/Client/ModeDragState.cpp
Source/Client/ModeTooltip.cpp
Source/Contents/CharacterConfigLoad.cpp
Source/Contents/CharacterLinkedUserDataLoadAsyncWork.cpp
Source/Contents/EmblemCache.cpp
Source/Contents/EmblemUpload.cpp
Source/Contents/ChangePartyMasterCompletion.cpp
Source/Contents/PartyListCompletion.cpp
Source/Contents/StopRecruitingCompletion.cpp
Source/Contents/MyPartyCompletion.cpp
Source/Contents/PartyRegistrationCompletion.cpp
Source/Contents/PartyInfoCompletion.cpp
Source/Contents/PartyJoinResult.cpp
Source/Contents/PartyInvitation.cpp
Source/UI/Cooldowns/CooldownState.cpp
Source/UI/Cooldowns/CooldownDrawing.cpp
Source/UI/Cooldowns/CooldownOwner.cpp
Source/UI/Shortcuts/ShortcutCooldowns.cpp
Source/UI/Shop/ItemDrawing.cpp
Source/UI/Shortcuts/ShortcutPainting.cpp
Source/UI/Shortcuts/ShortcutBindings.cpp
Source/UI/Shortcuts/ShortcutLayout.cpp
Source/UI/Shortcuts/ShortcutActivation.cpp
Source/UI/Shortcuts/ShortcutControls.cpp
Source/UI/Shortcuts/ShortcutControlEvents.cpp
Source/UI/Shortcuts/ShortcutTooltip.cpp
Source/UI/Shortcuts/ShortcutPress.cpp
Source/UI/Shortcuts/ShortcutDrop.cpp
Source/UI/Shortcuts/ShortcutUse.cpp
Source/UI/Shortcuts/ShortcutVisibility.cpp
Source/UI/Shortcuts/ShortcutDetails.cpp
Source/UI/Shortcuts/SkillDetailClose.cpp
Source/UI/Shortcuts/NormalItemSlotLoad.cpp
Source/UI/Shortcuts/UIShortCutWnd.cpp
Source/UI/Text/TextWrapping.cpp
Source/UI/Chat/ChatNotifications.cpp
Source/Client/Browser/BrowserFactory.cpp
Source/Client/Browser/BrowserPopupDispatch.cpp
Source/UI/Window/WindowFrameUpdate.cpp
Source/UI/Text/UIBalloonText.cpp
Source/UI/Text/UITransBalloonText.cpp
Source/UI/Text/ColoredText.cpp
Source/UI/Window/WindowBorder.cpp
Source/UI/Edit/EditTextState.cpp
Source/UI/Edit/EditViewport.cpp
Source/UI/Edit/EditPainting.cpp
Source/UI/Shop/PriceColor.cpp
Source/UI/Shop/MerchantShopRefresh.cpp
Source/UI/Text/NavigationLink.cpp
Source/UI/Text/TextFitting.cpp
Source/Client/Mode/ModeDragState.cpp
Source/Client/Mode/ModeTooltip.cpp
Source/Contents/UserData/CharacterConfigLoad.cpp
Source/Contents/UserData/CharacterLinkedUserDataLoadAsyncWork.cpp
Source/Contents/Emblems/EmblemCache.cpp
Source/Contents/Emblems/EmblemUpload.cpp
Source/Contents/Party/ChangePartyMasterCompletion.cpp
Source/Contents/Party/PartyListCompletion.cpp
Source/Contents/Party/StopRecruitingCompletion.cpp
Source/Contents/Party/MyPartyCompletion.cpp
Source/Contents/Party/PartyRegistrationCompletion.cpp
Source/Contents/Party/PartyInfoCompletion.cpp
Source/Contents/Party/PartyJoinResult.cpp
Source/Contents/Party/PartyInvitation.cpp
)
target_include_directories(RagnarokUI PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/Source")
target_compile_features(RagnarokUI PUBLIC cxx_std_20)
@ -310,68 +311,68 @@ if(WIN32)
add_library(RagnarokResource STATIC
Source/Resource/ResourceAliases.cpp
Source/Resource/BitmapImage.cpp
Source/Resource/BitmapImagePng.cpp
Source/Resource/BitmapImageJpeg.cpp
Source/Resource/IJL15Runtime.cpp
Source/Resource/MilesRuntime.cpp
Source/Resource/WaveResource.cpp
Source/Resource/Bitmap/BitmapImage.cpp
Source/Resource/Bitmap/BitmapImagePng.cpp
Source/Resource/Bitmap/BitmapImageJpeg.cpp
Source/Resource/Bitmap/IJL15Runtime.cpp
Source/Resource/Audio/MilesRuntime.cpp
Source/Resource/Audio/WaveResource.cpp
Source/Resource/Resource.cpp
Source/Resource/BitmapResource.cpp
Source/Resource/SpriteResource.cpp
Source/Resource/SpriteEncoding.cpp
Source/Resource/ActionResource.cpp
Source/Resource/TerrainResource.cpp
Source/Resource/GroundResource.cpp
Source/Resource/WorldResource.cpp
Source/Resource/WorldEnvironment.cpp
Source/Resource/WorldObjects.cpp
Source/Resource/ModelMesh.cpp
Source/Resource/ModelResource.cpp
Source/Resource/ModelNodeLoading.cpp
Source/Resource/ModelResourceV2.cpp
Source/Resource/ModelNodeLoadingV2.cpp
Source/Resource/AnimatedModelResource.cpp
Source/Contents/ModelAnimation.cpp
Source/Contents/ModelQuaternion.cpp
Source/Contents/ModelNode.cpp
Source/Contents/ModelTextureAnimation.cpp
Source/Contents/ModelRendering.cpp
Source/Contents/ModelTextureUV.cpp
Source/Contents/ModelLighting.cpp
Source/Contents/ModelNodeBounds.cpp
Source/Contents/ModelActor.cpp
Source/Contents/ModelActorBounds.cpp
Source/Contents/ModelPlayback.cpp
Source/Contents/ModelOcclusion.cpp
Source/Contents/ModelMovies.cpp
Source/Contents/WorldModelPlacement.cpp
Source/Contents/WorldModelLoading.cpp
Source/Contents/WorldGroundImport.cpp
Source/Contents/WorldEnvironment.cpp
Source/Contents/WorldSpatialTree.cpp
Source/Contents/WorldSpatialInitialization.cpp
Source/Contents/WorldRayQuery.cpp
Source/Contents/WorldOcclusion.cpp
Source/Contents/WorldModelView.cpp
Source/Contents/WorldViewSpatial.cpp
Source/Contents/CameraSmoothing.cpp
Source/Contents/CameraShake.cpp
Source/Contents/CameraFrame.cpp
Source/Contents/CameraQueries.cpp
Source/Contents/ModelSpatial.cpp
Source/Contents/GroundSpatial.cpp
Source/Contents/GroundGeometry.cpp
Source/Contents/GroundLightmaps.cpp
Source/Contents/GroundRendering.cpp
Source/Contents/GroundPicking.cpp
Source/Contents/GroundDecals.cpp
Source/Contents/GroundWaterState.cpp
Source/Contents/GroundWaterRendering.cpp
Source/Contents/GroundLighting.cpp
Source/Contents/GroundSamples.cpp
Source/Contents/GroundLightingInitialization.cpp
Source/Render/TextureCache.cpp
Source/Resource/Bitmap/BitmapResource.cpp
Source/Resource/Sprites/SpriteResource.cpp
Source/Resource/Sprites/SpriteEncoding.cpp
Source/Resource/Sprites/ActionResource.cpp
Source/Resource/World/TerrainResource.cpp
Source/Resource/World/GroundResource.cpp
Source/Resource/World/WorldResource.cpp
Source/Resource/World/WorldEnvironment.cpp
Source/Resource/World/WorldObjects.cpp
Source/Resource/Models/ModelMesh.cpp
Source/Resource/Models/ModelResource.cpp
Source/Resource/Models/ModelNodeLoading.cpp
Source/Resource/Models/ModelResourceV2.cpp
Source/Resource/Models/ModelNodeLoadingV2.cpp
Source/Resource/Models/AnimatedModelResource.cpp
Source/Contents/Models/ModelAnimation.cpp
Source/Contents/Models/ModelQuaternion.cpp
Source/Contents/Models/ModelNode.cpp
Source/Contents/Models/ModelTextureAnimation.cpp
Source/Contents/Models/ModelRendering.cpp
Source/Contents/Models/ModelTextureUV.cpp
Source/Contents/Models/ModelLighting.cpp
Source/Contents/Models/ModelNodeBounds.cpp
Source/Contents/Models/ModelActor.cpp
Source/Contents/Models/ModelActorBounds.cpp
Source/Contents/Models/ModelPlayback.cpp
Source/Contents/Models/ModelOcclusion.cpp
Source/Contents/Models/ModelMovies.cpp
Source/Contents/World/WorldModelPlacement.cpp
Source/Contents/World/WorldModelLoading.cpp
Source/Contents/World/WorldGroundImport.cpp
Source/Contents/World/WorldEnvironment.cpp
Source/Contents/World/WorldSpatialTree.cpp
Source/Contents/World/WorldSpatialInitialization.cpp
Source/Contents/World/WorldRayQuery.cpp
Source/Contents/World/WorldOcclusion.cpp
Source/Contents/World/WorldModelView.cpp
Source/Contents/World/WorldViewSpatial.cpp
Source/Contents/Camera/CameraSmoothing.cpp
Source/Contents/Camera/CameraShake.cpp
Source/Contents/Camera/CameraFrame.cpp
Source/Contents/Camera/CameraQueries.cpp
Source/Contents/Models/ModelSpatial.cpp
Source/Contents/Ground/GroundSpatial.cpp
Source/Contents/Ground/GroundGeometry.cpp
Source/Contents/Ground/GroundLightmaps.cpp
Source/Contents/Ground/GroundRendering.cpp
Source/Contents/Ground/GroundPicking.cpp
Source/Contents/Ground/GroundDecals.cpp
Source/Contents/Ground/GroundWaterState.cpp
Source/Contents/Ground/GroundWaterRendering.cpp
Source/Contents/Ground/GroundLighting.cpp
Source/Contents/Ground/GroundSamples.cpp
Source/Contents/Ground/GroundLightingInitialization.cpp
Source/Render/Textures/TextureCache.cpp
Source/Resource/EZeffectResource.cpp
Source/Resource/ResourceMgr.cpp
Source/Resource/ResourceFailures.cpp
@ -379,9 +380,9 @@ if(WIN32)
Source/Resource/TextureNames.cpp
Source/Contents/SkinInfo.cpp
Source/Resource/BinkRuntime.cpp
Source/Contents/BinkMovie.cpp
Source/Contents/BinkMovies.cpp
Source/Render/ClientTextureSources.cpp
Source/Contents/Movies/BinkMovie.cpp
Source/Contents/Movies/BinkMovies.cpp
Source/Render/Textures/ClientTextureSources.cpp
)
target_include_directories(RagnarokResource PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/Source")
target_compile_features(RagnarokResource PUBLIC cxx_std_20)
@ -390,15 +391,15 @@ if(WIN32)
set_target_properties(RagnarokResource PROPERTIES CXX_EXTENSIONS OFF)
add_library(RagnarokNetwork STATIC
Source/Network/CURLMgr.cpp
Source/Network/CURLPostHander.cpp
Source/Network/Http/CURLMgr.cpp
Source/Network/Http/CURLPostHander.cpp
Source/Network/TextEncoding.cpp
Source/Network/ConnectionBuffer.cpp
Source/Network/Connection.cpp
Source/Network/PacketLengths.cpp
Source/Network/ConnectionRuntime.cpp
Source/Network/ShortcutPacket.cpp
Source/Network/PartyJoinPacket.cpp
Source/Network/Connection/ConnectionBuffer.cpp
Source/Network/Connection/Connection.cpp
Source/Network/Packets/PacketLengths.cpp
Source/Network/Connection/ConnectionRuntime.cpp
Source/Network/Packets/ShortcutPacket.cpp
Source/Network/Packets/PartyJoinPacket.cpp
)
target_include_directories(RagnarokNetwork PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/Source")
target_compile_features(RagnarokNetwork PUBLIC cxx_std_20)
@ -406,104 +407,104 @@ if(WIN32)
set_target_properties(RagnarokNetwork PROPERTIES CXX_EXTENSIONS OFF)
add_library(RagnarokContents STATIC
Source/Contents/WhisperBlockMgr.cpp
Source/Contents/Messenger/WhisperBlockMgr.cpp
Source/Contents/CashEmotionMgr.cpp
Source/Contents/AccountUserData.cpp
Source/Contents/EmotionHotkeys.cpp
Source/Contents/UserHotkeyScript.cpp
Source/Contents/UserHotkeyMgr.cpp
Source/Contents/AccountLinkedUserDataMgr.cpp
Source/Contents/AccountService.cpp
Source/Contents/ScriptOptions.cpp
Source/Contents/GraphicsConfiguration.cpp
Source/Contents/SoundConfiguration.cpp
Source/Contents/SoundMgr.cpp
Source/Contents/OptionWriter.cpp
Source/Contents/UserData/AccountUserData.cpp
Source/Contents/Hotkeys/EmotionHotkeys.cpp
Source/Contents/Hotkeys/UserHotkeyScript.cpp
Source/Contents/Hotkeys/UserHotkeyMgr.cpp
Source/Contents/UserData/AccountLinkedUserDataMgr.cpp
Source/Contents/UserData/AccountService.cpp
Source/Contents/Configuration/ScriptOptions.cpp
Source/Contents/Configuration/GraphicsConfiguration.cpp
Source/Contents/Sound/SoundConfiguration.cpp
Source/Contents/Sound/SoundMgr.cpp
Source/Contents/Configuration/OptionWriter.cpp
Source/Contents/MessageTable.cpp
Source/Contents/AccountLinkedUserDataSaveAsyncWork.cpp
Source/Contents/AccountLinkedUserDataLoadAsyncWork.cpp
Source/Contents/CharacterLinkedUserDataMgr.cpp
Source/Contents/CharacterLinkedUserDataSaveAsyncWork.cpp
Source/Contents/CharacterConfigSave.cpp
Source/Contents/SkillLevelConfig.cpp
Source/Contents/SkillLevelRegistry.cpp
Source/Contents/ServiceOptions.cpp
Source/Contents/NormalItemSlots.cpp
Source/Contents/SkillInfo.cpp
Source/Contents/PlayerSkillBundle.cpp
Source/Contents/SkillTreeScript.cpp
Source/Contents/ClientSkills.cpp
Source/Network/SkillUpdatePacket.cpp
Source/Contents/ItemInfo.cpp
Source/Contents/ItemDescription.cpp
Source/Contents/ItemLink.cpp
Source/Contents/UserData/AccountLinkedUserDataSaveAsyncWork.cpp
Source/Contents/UserData/AccountLinkedUserDataLoadAsyncWork.cpp
Source/Contents/UserData/CharacterLinkedUserDataMgr.cpp
Source/Contents/UserData/CharacterLinkedUserDataSaveAsyncWork.cpp
Source/Contents/UserData/CharacterConfigSave.cpp
Source/Contents/Skills/SkillLevelConfig.cpp
Source/Contents/Skills/SkillLevelRegistry.cpp
Source/Contents/Configuration/ServiceOptions.cpp
Source/Contents/UserData/NormalItemSlots.cpp
Source/Contents/Skills/SkillInfo.cpp
Source/Contents/Skills/PlayerSkillBundle.cpp
Source/Contents/Skills/SkillTreeScript.cpp
Source/Contents/Skills/ClientSkills.cpp
Source/Network/Packets/SkillUpdatePacket.cpp
Source/Contents/Items/ItemInfo.cpp
Source/Contents/Items/ItemDescription.cpp
Source/Contents/Items/ItemLink.cpp
Source/Contents/TipBoxTitles.cpp
Source/Contents/AutomaticSkills.cpp
Source/Contents/AttackMotion.cpp
Source/Client/ApplicationActivation.cpp
Source/Client/ApplicationMessages.cpp
Source/Client/BrowserInputHandoff.cpp
Source/Client/WebBrowser.cpp
Source/Client/BrowserRegistry.cpp
Source/Client/WebEventReceiver.cpp
Source/Client/BrowserMessages.cpp
Source/Contents/HotkeyInfo.cpp
Source/Contents/Skills/AutomaticSkills.cpp
Source/Contents/Actors/AttackMotion.cpp
Source/Client/Application/ApplicationActivation.cpp
Source/Client/Application/ApplicationMessages.cpp
Source/Client/Browser/BrowserInputHandoff.cpp
Source/Client/Browser/WebBrowser.cpp
Source/Client/Browser/BrowserRegistry.cpp
Source/Client/Browser/WebEventReceiver.cpp
Source/Client/Browser/BrowserMessages.cpp
Source/Contents/Hotkeys/HotkeyInfo.cpp
Source/Contents/PlayerNameDictionary.cpp
Source/Contents/ItemNaming.cpp
Source/Contents/ItemResources.cpp
Source/Contents/StoreBackupData.cpp
Source/Contents/MCStoreInfoBackup.cpp
Source/Contents/MCStoreInfoBackupAsyncWork.cpp
Source/Contents/EmblemDownload.cpp
Source/Contents/EmblemDataDownloadAsyncWork.cpp
Source/Contents/EmblemDataMgr.cpp
Source/Contents/GuildEmblemReqBundle.cpp
Source/Contents/EmblemDataUploadAsyncWork.cpp
Source/Contents/AdvenPartyInfo.cpp
Source/Contents/AdventurerAgencyMgr.cpp
Source/Contents/ChangePartyMasterAsyncWork.cpp
Source/Contents/LoadPartyListAsyncWork.cpp
Source/Contents/StopRecruitingAsyncWork.cpp
Source/Contents/LoadMyPartyAsyncWork.cpp
Source/Contents/RegisterPartyAsyncWork.cpp
Source/Contents/LoadPartyInfoAsyncWork.cpp
Source/Contents/AsyncWorkRecycleObjectPoolMgr.cpp
Source/Contents/AsyncWorkMgr.cpp
Source/Contents/AgencyRequests.cpp
Source/Contents/Items/ItemNaming.cpp
Source/Contents/Items/ItemResources.cpp
Source/Contents/Store/StoreBackupData.cpp
Source/Contents/Store/MCStoreInfoBackup.cpp
Source/Contents/Store/MCStoreInfoBackupAsyncWork.cpp
Source/Contents/Emblems/EmblemDownload.cpp
Source/Contents/Emblems/EmblemDataDownloadAsyncWork.cpp
Source/Contents/Emblems/EmblemDataMgr.cpp
Source/Contents/Emblems/GuildEmblemReqBundle.cpp
Source/Contents/Emblems/EmblemDataUploadAsyncWork.cpp
Source/Contents/Party/AdvenPartyInfo.cpp
Source/Contents/Party/AdventurerAgencyMgr.cpp
Source/Contents/Party/ChangePartyMasterAsyncWork.cpp
Source/Contents/Party/LoadPartyListAsyncWork.cpp
Source/Contents/Party/StopRecruitingAsyncWork.cpp
Source/Contents/Party/LoadMyPartyAsyncWork.cpp
Source/Contents/Party/RegisterPartyAsyncWork.cpp
Source/Contents/Party/LoadPartyInfoAsyncWork.cpp
Source/Contents/Async/AsyncWorkRecycleObjectPoolMgr.cpp
Source/Contents/Async/AsyncWorkMgr.cpp
Source/Contents/Party/AgencyRequests.cpp
Source/Contents/ForbiddenWords.cpp
Source/Contents/JobNames.cpp
Source/Contents/SpriteDrawingPolicy.cpp
Source/Contents/JobInheritance.cpp
Source/Contents/MessengerMember.cpp
Source/Contents/ClientMessenger.cpp
Source/Contents/RenderObjectState.cpp
Source/Contents/GameObject.cpp
Source/Contents/RenderObject.cpp
Source/Contents/WorldObjects.cpp
Source/Contents/WorldActors.cpp
Source/Contents/EffectAttachments.cpp
Source/Contents/EffectTypes.cpp
Source/Contents/RagEffectState.cpp
Source/Contents/RagEffectInitialization.cpp
Source/Contents/RagEffectResourceSelection.cpp
Source/Contents/EffectPrimitiveState.cpp
Source/Contents/EffectPrimitiveColor.cpp
Source/Contents/EffectPrimitiveMotion.cpp
Source/Contents/EffectPrimitiveRendering.cpp
Source/Contents/EffectPrimitiveRecords.cpp
Source/Contents/EffectParticle.cpp
Source/Contents/PartyEffect.cpp
Source/Contents/EffectActor.cpp
Source/Contents/AttachedEffect.cpp
Source/Contents/PartyMemberEffects.cpp
Source/Contents/EffectVisibility.cpp
Source/Contents/TerrainHeight.cpp
Source/Contents/TerrainCoordinates.cpp
Source/Contents/TerrainPicking.cpp
Source/Contents/TerrainPlane.cpp
Source/Contents/WorldTerrainPicking.cpp
Source/Contents/WorldProximity.cpp
Source/Contents/JobNameInitialization.cpp
Source/Contents/Jobs/JobNames.cpp
Source/Contents/Actors/SpriteDrawingPolicy.cpp
Source/Contents/Jobs/JobInheritance.cpp
Source/Contents/Messenger/MessengerMember.cpp
Source/Contents/Messenger/ClientMessenger.cpp
Source/Contents/Actors/RenderObjectState.cpp
Source/Contents/Actors/GameObject.cpp
Source/Contents/Actors/RenderObject.cpp
Source/Contents/World/WorldObjects.cpp
Source/Contents/World/WorldActors.cpp
Source/Contents/Effects/EffectAttachments.cpp
Source/Contents/Effects/EffectTypes.cpp
Source/Contents/Effects/RagEffectState.cpp
Source/Contents/Effects/RagEffectInitialization.cpp
Source/Contents/Effects/RagEffectResourceSelection.cpp
Source/Contents/Effects/EffectPrimitiveState.cpp
Source/Contents/Effects/EffectPrimitiveColor.cpp
Source/Contents/Effects/EffectPrimitiveMotion.cpp
Source/Contents/Effects/EffectPrimitiveRendering.cpp
Source/Contents/Effects/EffectPrimitiveRecords.cpp
Source/Contents/Effects/EffectParticle.cpp
Source/Contents/Effects/PartyEffect.cpp
Source/Contents/Effects/EffectActor.cpp
Source/Contents/Effects/AttachedEffect.cpp
Source/Contents/Effects/PartyMemberEffects.cpp
Source/Contents/Effects/EffectVisibility.cpp
Source/Contents/Ground/TerrainHeight.cpp
Source/Contents/Ground/TerrainCoordinates.cpp
Source/Contents/Ground/TerrainPicking.cpp
Source/Contents/Ground/TerrainPlane.cpp
Source/Contents/World/WorldTerrainPicking.cpp
Source/Contents/World/WorldProximity.cpp
Source/Contents/Jobs/JobNameInitialization.cpp
Source/Contents/ShowRankingScheduler.cpp
)
target_include_directories(RagnarokContents PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/Source")

View file

@ -80,7 +80,7 @@ static void BuildFullKeyName(const char* keyname, char* buffer) {
changes. Include the real prerequisite interfaces, implementations and affected callers, or land them first.
- Preserve functions that already match. Fix compile errors and structural differences; byte identity is a
bonus, not permission to distort source or spend unbounded time tuning it.
- Do not add WoW `// VERIFY:` hashes or use `re/tools/verify.py`; neither is this project's verification workflow.
- Do not add game `// VERIFY:` hashes or use `re/tools/verify.py`; neither is this project's verification workflow.
- Claims, submission scope and peer-review procedure follow `AGENTS.md` and current server guidance.
## 2b. Cast chains mean the types are wrong
@ -152,7 +152,7 @@ class CResourceCache {
- Reuse the appropriate header under `Source/` for shared enums and data types.
- Use an existing `Types.h` if the subsystem has one; do not create a repository-wide `Types.h` migration.
- Keep dependencies small and avoid cycles. Do not introduce WoW-specific DB or event headers.
- Keep dependencies small and avoid cycles. Do not introduce game-specific DB or event headers.
## 6. Diagnostic file and line arguments preserve original behavior
@ -166,6 +166,25 @@ the original instructions.
- This target is Windows x86. Keep code in its assigned existing translation unit and subsystem headers.
- Use the original Win32, DirectDraw, Direct3D, Lua and codec ABIs where evidenced. Preserve calling
conventions, ownership, field widths and failure behavior.
- Do not introduce WoW architecture macros, parallel `Win32/` / `Win64/` trees or a new portability layer.
- Compile individual units with the configured Clank toolchain and `compile.json`, not a new build system.
- Missing original instructions are a blocker, not permission to invent a fallback or partial implementation.
## 8. Reconstruct source, not instructions
- Prefer the original programmer's types and algorithms over instruction-shaped C++. Byte identity is a bonus,
never a reason for cryptic code. Use compiler intrinsics only with clear evidence that the original source
used them; an optimized SIMD instruction alone is not evidence. Scalar data is not `__m128i`.
- Recover records and members instead of dereferencing integer pointers cast onto byte buffers. At a real
binary-format boundary, use a typed record or `memcpy` for unaligned fields; preserve layout and aliasing.
- Apply namespace and API conventions consistently throughout a subsystem, including declarations and callers.
- Group cohesive implementations and their headers in subsystem folders, e.g. `Client/Browser/`. Group by
actual ownership and dependencies, not a loose keyword; update includes and build metadata with every move.
- Use SDK/library constants and identifiers directly: `WS_CHILD | WS_VISIBLE`, `CGID_DocHostCommandHandler`.
Do not duplicate documented definitions. Name game-specific choices with an enum, or `constexpr` when an enum
is unsuitable; do not turn serialized data, hashes or lookup tables into invented symbolic constants.
- Do not include `<mmsystem.h>`; include the specific Windows API headers actually required. Formatter-control
comments are forbidden too. Preserve include dependencies without `clang-format` suppression comments.
- Separate different logical phases with a blank line; keep related assignments together. Use a 160-column
limit, rather than wrapping short calls into instruction-like fragments. Formatting must not change behavior.
- Leave exactly one blank line after an include block before declarations, including in headers. Never keep
more than one consecutive blank line; whitespace-only lines count as blank.

View file

@ -3,5 +3,5 @@
This tree is coordinated with Clank Together. Functions and data carry stable symbol IDs
instead of addresses (`// FUNCTION: fn_01234`, `// GLOBAL: gl_00042`); the coordinator's symbol database holds
their addresses in every client build, so a new client version needs new addresses, not a retagged tree.
`decomp.json` and `config/compile.json` pin the VS compiler and the exact command line of every source.
`decomp.json` and `compile.json` pin the VS compiler and the exact command line of every source.
See `AGENTS.md` for how to contribute.

View file

@ -4,11 +4,9 @@
#include <algorithm>
#include <cstdlib>
#include <cstring>
#include <emmintrin.h>
#include <zlib.h>
namespace {
std::uint32_t Read32(const std::uint8_t* bytes) {
std::uint32_t value;
std::memcpy(&value, bytes, sizeof(value));
@ -29,22 +27,18 @@ namespace {
// FUNCTION: fn_05116
std::uint64_t ReadAuxiliaryIdentifier(const void* data, std::size_t size) {
if (size != 0) {
const __m128i header = _mm_loadu_si128(static_cast<const __m128i*>(data));
if (static_cast<std::uint8_t>(_mm_cvtsi128_si32(header)) <= 1) {
std::uint64_t identifier;
_mm_storel_epi64(reinterpret_cast<__m128i*>(&identifier), _mm_srli_si128(header, 4));
return identifier;
const auto* header = static_cast<const std::uint8_t*>(data);
if (header[0] <= 1) {
return Read64(header + 4);
}
}
return UINT64_MAX;
}
void SortEntries(std::vector<myGPack::PakEntry>& entries) {
std::sort(entries.begin(), entries.end(), [](const auto& first, const auto& second) {
return first.name < second.name;
});
std::sort(entries.begin(), entries.end(), [](const auto& first, const auto& second) { return first.name < second.name; });
}
}
// OFFSET: 0x00E555A0
@ -80,6 +74,7 @@ bool CGPak::Open(CPakFile* file) {
if (!file) {
return false;
}
this->m_file = file;
const std::uint8_t* header = file->Read(0, 46);
if (std::memcmp(header, "Event Horizon", 14) == 0) {
@ -95,6 +90,7 @@ bool CGPak::Open(CPakFile* file) {
}
bool loaded;
switch (this->m_version & 0xFF00) {
case 0x100:
loaded = this->ReadTableV1();
@ -109,9 +105,11 @@ bool CGPak::Open(CPakFile* file) {
loaded = false;
break;
}
if (loaded) {
return true;
}
this->Reset();
return false;
}
@ -119,20 +117,22 @@ bool CGPak::Open(CPakFile* file) {
// OFFSET: 0x00AEC050
// FUNCTION: fn_18133
bool CGPak::ReadTableV1() {
this->m_tableSize =
static_cast<std::uint32_t>(this->m_file->GetSize()) - static_cast<std::uint32_t>(this->m_tableOffset);
this->m_tableSize = static_cast<std::uint32_t>(this->m_file->GetSize()) - static_cast<std::uint32_t>(this->m_tableOffset);
const std::uint8_t* cursor = this->m_file->Read(this->m_tableOffset, this->m_tableSize);
this->m_entries.resize(this->m_entryCount);
std::uint32_t maximum = 0;
std::uint32_t sequence = 1;
std::int32_t legacyKey = 95001;
for (std::uint32_t i = 0; i < this->m_entryCount; ++i) {
std::uint32_t nameSize = Read32(cursor);
cursor += 4;
char name[256];
if (this->m_version < 0x101) {
std::int32_t length = static_cast<std::int32_t>(std::strlen(reinterpret_cast<const char*>(cursor)) + 1);
for (std::int32_t j = 0; j < length; ++j) {
name[j] = static_cast<char>(SwapNibbles(cursor[j]));
}
@ -140,18 +140,23 @@ bool CGPak::ReadTableV1() {
if (this->m_version > 0x103) {
return false;
}
cursor += 2;
std::int32_t length = static_cast<std::int32_t>(nameSize - 6);
for (std::int32_t j = 0; j < length; ++j) {
name[j] = static_cast<char>(SwapNibbles(cursor[j]));
}
std::int32_t number = legacyKey;
if (this->m_version != 0x101) {
number = static_cast<std::int32_t>(3 * (31669u - (sequence >> 1)));
}
if (number < 10000) {
number += 85000;
}
char digits[20];
_itoa(number, digits, 10);
std::uint8_t key[8];
@ -178,13 +183,14 @@ bool CGPak::ReadTableV1() {
entry.name.Assign(name);
const char* extension = std::strrchr(name, '.');
bool special = extension && (_stricmp(extension, ".gnd") == 0 || _stricmp(extension, ".gat") == 0 ||
_stricmp(extension, ".act") == 0 || _stricmp(extension, ".str") == 0);
bool special = extension && (_stricmp(extension, ".gnd") == 0 || _stricmp(extension, ".gat") == 0 || _stricmp(extension, ".act") == 0 ||
_stricmp(extension, ".str") == 0);
entry.flags |= special ? 4 : 2;
maximum = std::max(maximum, entry.alignedSize);
sequence += 5;
legacyKey -= 2;
}
SortEntries(this->m_entries);
this->m_scratch.resize(maximum);
return true;
@ -200,6 +206,7 @@ bool CGPak::ReadTableV2() {
const std::uint8_t* source = this->m_file->Read(this->m_tableOffset + 8, compressed);
uLongf length = original + 8;
std::vector<std::uint8_t> decoded(length);
if (uncompress(decoded.data(), &length, source, compressed) != Z_OK) {
return false;
}
@ -207,6 +214,7 @@ bool CGPak::ReadTableV2() {
this->m_entries.resize(this->m_entryCount);
const std::uint8_t* cursor = decoded.data();
std::uint32_t maximum = 0;
for (std::uint32_t i = 0; i < this->m_entryCount; ++i) {
const char* name = reinterpret_cast<const char*>(cursor);
const std::uint8_t* metadata = cursor + std::strlen(name) + 1;
@ -220,6 +228,7 @@ bool CGPak::ReadTableV2() {
entry.name.Assign(name);
maximum = std::max(maximum, entry.alignedSize);
}
SortEntries(this->m_entries);
this->m_scratch.resize(maximum);
return true;
@ -236,6 +245,7 @@ bool CGPak::ReadTableV3() {
const std::uint8_t* source = this->m_file->Read(this->m_tableOffset + 12, compressed);
uLongf length = original + 8;
std::vector<std::uint8_t> decoded(length);
if (uncompress(decoded.data(), &length, source, compressed) != Z_OK) {
return false;
}
@ -243,6 +253,7 @@ bool CGPak::ReadTableV3() {
this->m_entries.resize(this->m_entryCount);
const std::uint8_t* cursor = decoded.data();
std::uint32_t maximum = 0;
for (std::uint32_t i = 0; i < this->m_entryCount; ++i) {
const char* name = reinterpret_cast<const char*>(cursor);
const std::uint8_t* metadata = cursor + std::strlen(name) + 1;
@ -252,12 +263,11 @@ bool CGPak::ReadTableV3() {
entry.alignedSize = Read32(metadata + 4);
entry.originalSize = Read32(metadata + 8);
entry.flags = metadata[12];
const std::uint32_t offsetLow = Read32(metadata + 13);
reinterpret_cast<std::uint32_t*>(&entry.dataOffset)[1] = Read32(metadata + 17);
reinterpret_cast<std::uint32_t*>(&entry.dataOffset)[0] = offsetLow;
entry.dataOffset = Read64(metadata + 13);
entry.name.Assign(name);
maximum = std::max(maximum, entry.alignedSize);
}
SortEntries(this->m_entries);
this->m_scratch.resize(maximum);
return true;
@ -266,16 +276,17 @@ bool CGPak::ReadTableV3() {
// OFFSET: 0x00AEBA30
// FUNCTION: fn_18128
bool CGPak::Find(const myGPack::PakName& name, myGPack::PakEntry* entry) const {
auto found = std::lower_bound(
this->m_entries.begin(), this->m_entries.end(), name,
[](const myGPack::PakEntry& candidate, const myGPack::PakName& key) { return candidate.name < key; }
);
auto found = std::lower_bound(this->m_entries.begin(), this->m_entries.end(), name, [](const myGPack::PakEntry& candidate, const myGPack::PakName& key) {
return candidate.name < key;
});
if (found == this->m_entries.end() || found->name != name) {
return false;
}
if (entry) {
std::memcpy(entry, &*found, sizeof(*entry));
}
return true;
}
@ -290,6 +301,7 @@ void CGPak::ReadAuxiliary(std::vector<std::uint8_t>& output, std::uint64_t* iden
std::uint32_t size;
std::uint64_t offset;
switch (this->m_version & 0xFF00) {
case 0x200:
if (this->m_version < 0x201) {

View file

@ -1,14 +1,10 @@
#include "Archive/MemMapPakFile.h"
#include <bit>
// OFFSET: 0x00AE99D0
// FUNCTION: fn_18111
// OFFSET: 0x00AECAA0
// FUNCTION: fn_18140
CMemMapPakFile::CMemMapPakFile()
: m_handle(nullptr), m_mapping(nullptr), m_viewSize(0), m_windowSize(0x20000000), m_size(0), m_viewOffset(0),
m_view(nullptr) {
CMemMapPakFile::CMemMapPakFile() : m_handle(nullptr), m_mapping(nullptr), m_viewSize(0), m_windowSize(0x20000000), m_size(0), m_viewOffset(0), m_view(nullptr) {
SYSTEM_INFO information;
GetSystemInfo(&information);
this->m_offsetMask = 0xFFFFFFFF00000000ULL | static_cast<std::uint32_t>(~(information.dwAllocationGranularity - 1));
@ -30,8 +26,7 @@ std::uint64_t CMemMapPakFile::GetSize() const {
// OFFSET: 0x00AECB10
// FUNCTION: fn_18141
bool CMemMapPakFile::Open(const char* filename) {
this->m_handle =
CreateFileA(filename, GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
this->m_handle = CreateFileA(filename, GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
if (this->m_handle == INVALID_HANDLE_VALUE) {
this->m_handle = nullptr;
return false;
@ -39,13 +34,15 @@ bool CMemMapPakFile::Open(const char* filename) {
LARGE_INTEGER size;
GetFileSizeEx(this->m_handle, &size);
this->m_size = std::bit_cast<std::uint64_t>(size.QuadPart);
this->m_size = static_cast<std::uint64_t>(size.QuadPart);
this->m_viewOffset = 0;
this->m_viewSize = 0;
this->m_mapping = CreateFileMappingA(this->m_handle, nullptr, PAGE_READONLY, 0, 0, nullptr);
if (this->m_mapping) {
return true;
}
this->m_windowSize = 0;
return false;
}
@ -57,10 +54,12 @@ void CMemMapPakFile::Close() {
UnmapViewOfFile(this->m_view);
this->m_view = nullptr;
}
if (this->m_mapping) {
CloseHandle(this->m_mapping);
this->m_mapping = nullptr;
}
if (this->m_handle) {
CloseHandle(this->m_handle);
this->m_handle = nullptr;
@ -74,27 +73,29 @@ std::uint8_t* CMemMapPakFile::Read(std::uint64_t offset, std::uint32_t length) {
if (offset >= this->m_viewOffset && offset + length <= this->m_viewOffset + this->m_viewSize) {
return this->m_view + static_cast<std::uint32_t>(offset - this->m_viewOffset);
}
if (this->m_view) {
UnmapViewOfFile(this->m_view);
this->m_view = nullptr;
}
while (this->m_windowSize >=
length + (static_cast<std::uint32_t>(offset) & ~static_cast<std::uint32_t>(this->m_offsetMask))) {
while (this->m_windowSize >= length + (static_cast<std::uint32_t>(offset) & ~static_cast<std::uint32_t>(this->m_offsetMask))) {
this->m_viewOffset = offset & this->m_offsetMask;
this->m_viewSize = this->m_windowSize;
SIZE_T bytes = this->m_windowSize;
if (this->m_viewOffset + this->m_windowSize > this->m_size) {
bytes = 0;
this->m_viewSize = static_cast<std::uint32_t>(this->m_size - this->m_viewOffset);
}
this->m_view = static_cast<std::uint8_t*>(MapViewOfFile(
this->m_mapping, FILE_MAP_READ, static_cast<DWORD>(this->m_viewOffset >> 32),
static_cast<DWORD>(this->m_viewOffset), bytes
));
this->m_view = static_cast<std::uint8_t*>(
MapViewOfFile(this->m_mapping, FILE_MAP_READ, static_cast<DWORD>(this->m_viewOffset >> 32), static_cast<DWORD>(this->m_viewOffset), bytes)
);
if (this->m_view) {
return this->m_view + static_cast<std::uint32_t>(offset - this->m_viewOffset);
}
this->m_windowSize >>= 1;
if (!this->m_windowSize) {
break;
@ -113,14 +114,16 @@ std::uint8_t* CMemMapPakFile::Read(std::uint64_t offset, std::uint32_t length) {
this->m_buffer.resize(length);
this->m_view = this->m_buffer.data();
}
LARGE_INTEGER position;
position.QuadPart = std::bit_cast<std::int64_t>(offset);
position.QuadPart = static_cast<std::int64_t>(offset);
SetFilePointerEx(this->m_handle, position, nullptr, FILE_BEGIN);
DWORD read = 0;
if (ReadFile(this->m_handle, this->m_buffer.data(), length, &read, nullptr)) {
// The original accepts a successful short read; it does not compare read.
this->m_view = this->m_buffer.empty() ? nullptr : this->m_buffer.data();
return this->m_view;
}
return nullptr;
}

View file

@ -3,7 +3,6 @@
#include "Archive/PakFile.h"
// Class name established by original RTTI; field/method names reconstructed.
class CMemMapPakFile : public CPakFile {
public:
CMemMapPakFile();

View file

@ -5,21 +5,18 @@
namespace myGPack {
namespace {
// STATIC: 0x01159EC8
// GLOBAL: gl_13428
constexpr std::uint8_t s_initialPermutation[64] = {
58, 50, 42, 34, 26, 18, 10, 2, 60, 52, 44, 36, 28, 20, 12, 4, 62, 54, 46, 38, 30, 22,
14, 6, 64, 56, 48, 40, 32, 24, 16, 8, 57, 49, 41, 33, 25, 17, 9, 1, 59, 51, 43, 35,
27, 19, 11, 3, 61, 53, 45, 37, 29, 21, 13, 5, 63, 55, 47, 39, 31, 23, 15, 7,
58, 50, 42, 34, 26, 18, 10, 2, 60, 52, 44, 36, 28, 20, 12, 4, 62, 54, 46, 38, 30, 22, 14, 6, 64, 56, 48, 40, 32, 24, 16, 8,
57, 49, 41, 33, 25, 17, 9, 1, 59, 51, 43, 35, 27, 19, 11, 3, 61, 53, 45, 37, 29, 21, 13, 5, 63, 55, 47, 39, 31, 23, 15, 7,
};
// STATIC: 0x01159F08
// GLOBAL: gl_13429
constexpr std::uint8_t s_finalPermutation[64] = {
40, 8, 48, 16, 56, 24, 64, 32, 39, 7, 47, 15, 55, 23, 63, 31, 38, 6, 46, 14, 54, 22,
62, 30, 37, 5, 45, 13, 53, 21, 61, 29, 36, 4, 44, 12, 52, 20, 60, 28, 35, 3, 43, 11,
51, 19, 59, 27, 34, 2, 42, 10, 50, 18, 58, 26, 33, 1, 41, 9, 49, 17, 57, 25,
40, 8, 48, 16, 56, 24, 64, 32, 39, 7, 47, 15, 55, 23, 63, 31, 38, 6, 46, 14, 54, 22, 62, 30, 37, 5, 45, 13, 53, 21, 61, 29,
36, 4, 44, 12, 52, 20, 60, 28, 35, 3, 43, 11, 51, 19, 59, 27, 34, 2, 42, 10, 50, 18, 58, 26, 33, 1, 41, 9, 49, 17, 57, 25,
};
// STATIC: 0x01159FC0
@ -32,42 +29,38 @@ namespace myGPack {
// STATIC: 0x01159FF0
// GLOBAL: gl_13431
constexpr std::uint8_t s_roundPermutation[32] = {
16, 7, 20, 21, 29, 12, 28, 17, 1, 15, 23, 26, 5, 18, 31, 10,
2, 8, 24, 14, 32, 27, 3, 9, 19, 13, 30, 6, 22, 11, 4, 25,
16, 7, 20, 21, 29, 12, 28, 17, 1, 15, 23, 26, 5, 18, 31, 10, 2, 8, 24, 14, 32, 27, 3, 9, 19, 13, 30, 6, 22, 11, 4, 25,
};
// STATIC: 0x0115A010
// GLOBAL: gl_13432
constexpr std::uint8_t s_substitution[512] = {
14, 0, 4, 15, 13, 7, 1, 4, 2, 14, 15, 2, 11, 13, 8, 1, 3, 10, 10, 6, 6, 12, 12, 11, 5, 9, 9,
5, 0, 3, 7, 8, 4, 15, 1, 12, 14, 8, 8, 2, 13, 4, 6, 9, 2, 1, 11, 7, 15, 5, 12, 11, 9, 3,
7, 14, 3, 10, 10, 0, 5, 6, 0, 13, 15, 3, 1, 13, 8, 4, 14, 7, 6, 15, 11, 2, 3, 8, 4, 14, 9,
12, 7, 0, 2, 1, 13, 10, 12, 6, 0, 9, 5, 11, 10, 5, 0, 13, 14, 8, 7, 10, 11, 1, 10, 3, 4, 15,
13, 4, 1, 2, 5, 11, 8, 6, 12, 7, 6, 12, 9, 0, 3, 5, 2, 14, 15, 9, 10, 13, 0, 7, 9, 0, 14,
9, 6, 3, 3, 4, 15, 6, 5, 10, 1, 2, 13, 8, 12, 5, 7, 14, 11, 12, 4, 11, 2, 15, 8, 1, 13, 1,
6, 10, 4, 13, 9, 0, 8, 6, 15, 9, 3, 8, 0, 7, 11, 4, 1, 15, 2, 14, 12, 3, 5, 11, 10, 5, 14,
2, 7, 12, 7, 13, 13, 8, 14, 11, 3, 5, 0, 6, 6, 15, 9, 0, 10, 3, 1, 4, 2, 7, 8, 2, 5, 12,
11, 1, 12, 10, 4, 14, 15, 9, 10, 3, 6, 15, 9, 0, 0, 6, 12, 10, 11, 1, 7, 13, 13, 8, 15, 9, 1,
4, 3, 5, 14, 11, 5, 12, 2, 7, 8, 2, 4, 14, 2, 14, 12, 11, 4, 2, 1, 12, 7, 4, 10, 7, 11, 13,
6, 1, 8, 5, 5, 0, 3, 15, 15, 10, 13, 3, 0, 9, 14, 8, 9, 6, 4, 11, 2, 8, 1, 12, 11, 7, 10,
1, 13, 14, 7, 2, 8, 13, 15, 6, 9, 15, 12, 0, 5, 9, 6, 10, 3, 4, 0, 5, 14, 3, 12, 10, 1, 15,
10, 4, 15, 2, 9, 7, 2, 12, 6, 9, 8, 5, 0, 6, 13, 1, 3, 13, 4, 14, 14, 0, 7, 11, 5, 3, 11,
8, 9, 4, 14, 3, 15, 2, 5, 12, 2, 9, 8, 5, 12, 15, 3, 10, 7, 11, 0, 14, 4, 1, 10, 7, 1, 6,
13, 0, 11, 8, 6, 13, 4, 13, 11, 0, 2, 11, 14, 7, 15, 4, 0, 9, 8, 1, 13, 10, 3, 14, 12, 3, 9,
5, 7, 12, 5, 2, 10, 15, 6, 8, 1, 6, 1, 6, 4, 11, 11, 13, 13, 8, 12, 1, 3, 4, 7, 10, 14, 7,
10, 9, 15, 5, 6, 0, 8, 15, 0, 14, 5, 2, 9, 3, 2, 12, 13, 1, 2, 15, 8, 13, 4, 8, 6, 10, 15,
3, 11, 7, 1, 4, 10, 12, 9, 5, 3, 6, 14, 11, 5, 0, 0, 14, 12, 9, 7, 2, 7, 2, 11, 1, 4, 14,
1, 7, 9, 4, 12, 10, 14, 8, 2, 13, 0, 15, 6, 12, 10, 9, 13, 0, 15, 3, 3, 5, 5, 6, 8, 11,
14, 0, 4, 15, 13, 7, 1, 4, 2, 14, 15, 2, 11, 13, 8, 1, 3, 10, 10, 6, 6, 12, 12, 11, 5, 9, 9, 5, 0, 3, 7, 8, 4, 15, 1, 12, 14,
8, 8, 2, 13, 4, 6, 9, 2, 1, 11, 7, 15, 5, 12, 11, 9, 3, 7, 14, 3, 10, 10, 0, 5, 6, 0, 13, 15, 3, 1, 13, 8, 4, 14, 7, 6, 15,
11, 2, 3, 8, 4, 14, 9, 12, 7, 0, 2, 1, 13, 10, 12, 6, 0, 9, 5, 11, 10, 5, 0, 13, 14, 8, 7, 10, 11, 1, 10, 3, 4, 15, 13, 4, 1,
2, 5, 11, 8, 6, 12, 7, 6, 12, 9, 0, 3, 5, 2, 14, 15, 9, 10, 13, 0, 7, 9, 0, 14, 9, 6, 3, 3, 4, 15, 6, 5, 10, 1, 2, 13, 8,
12, 5, 7, 14, 11, 12, 4, 11, 2, 15, 8, 1, 13, 1, 6, 10, 4, 13, 9, 0, 8, 6, 15, 9, 3, 8, 0, 7, 11, 4, 1, 15, 2, 14, 12, 3, 5,
11, 10, 5, 14, 2, 7, 12, 7, 13, 13, 8, 14, 11, 3, 5, 0, 6, 6, 15, 9, 0, 10, 3, 1, 4, 2, 7, 8, 2, 5, 12, 11, 1, 12, 10, 4, 14,
15, 9, 10, 3, 6, 15, 9, 0, 0, 6, 12, 10, 11, 1, 7, 13, 13, 8, 15, 9, 1, 4, 3, 5, 14, 11, 5, 12, 2, 7, 8, 2, 4, 14, 2, 14, 12,
11, 4, 2, 1, 12, 7, 4, 10, 7, 11, 13, 6, 1, 8, 5, 5, 0, 3, 15, 15, 10, 13, 3, 0, 9, 14, 8, 9, 6, 4, 11, 2, 8, 1, 12, 11, 7,
10, 1, 13, 14, 7, 2, 8, 13, 15, 6, 9, 15, 12, 0, 5, 9, 6, 10, 3, 4, 0, 5, 14, 3, 12, 10, 1, 15, 10, 4, 15, 2, 9, 7, 2, 12, 6,
9, 8, 5, 0, 6, 13, 1, 3, 13, 4, 14, 14, 0, 7, 11, 5, 3, 11, 8, 9, 4, 14, 3, 15, 2, 5, 12, 2, 9, 8, 5, 12, 15, 3, 10, 7, 11,
0, 14, 4, 1, 10, 7, 1, 6, 13, 0, 11, 8, 6, 13, 4, 13, 11, 0, 2, 11, 14, 7, 15, 4, 0, 9, 8, 1, 13, 10, 3, 14, 12, 3, 9, 5, 7,
12, 5, 2, 10, 15, 6, 8, 1, 6, 1, 6, 4, 11, 11, 13, 13, 8, 12, 1, 3, 4, 7, 10, 14, 7, 10, 9, 15, 5, 6, 0, 8, 15, 0, 14, 5, 2,
9, 3, 2, 12, 13, 1, 2, 15, 8, 13, 4, 8, 6, 10, 15, 3, 11, 7, 1, 4, 10, 12, 9, 5, 3, 6, 14, 11, 5, 0, 0, 14, 12, 9, 7, 2, 7,
2, 11, 1, 4, 14, 1, 7, 9, 4, 12, 10, 14, 8, 2, 13, 0, 15, 6, 12, 10, 9, 13, 0, 15, 3, 3, 5, 5, 6, 8, 11,
};
void Permute(std::uint8_t* block, const std::uint8_t* table, unsigned count) {
std::uint8_t result[8] = {};
for (unsigned i = 0; i < count; ++i) {
unsigned bit = table[i] - 1;
if (block[bit >> 3] & (0x80u >> (bit & 7))) {
result[i >> 3] |= static_cast<std::uint8_t>(0x80u >> (i & 7));
}
}
std::memcpy(block, result, sizeof(result));
}
@ -105,7 +98,6 @@ namespace myGPack {
return value;
}
}
}
// OFFSET: 0x00AE8480
@ -118,9 +110,6 @@ namespace myGPack {
// OFFSET: 0x00AE92F0
// FUNCTION: fn_18105
PakCipher::PakCipher(const std::uint8_t* key) {
// The original key permutation ANDs into zeroed state. Every resulting
// round key is zero, independent of the eight key bytes it reads.
// This is intentional original behavior, not standard DES key expansion.
(void)key;
std::memset(this->m_roundKeys, 0, sizeof(this->m_roundKeys));
}
@ -133,22 +122,30 @@ namespace myGPack {
// OFFSET: 0x00AE8E70
// FUNCTION: fn_18101
int PakCipher::DecodeBlock(int rounds, const std::uint8_t* input, std::uint8_t* output) const {
std::memcpy(output, input, 8);
std::uint32_t inputLow;
std::uint32_t inputHigh;
std::memcpy(&inputLow, input, sizeof(inputLow));
std::memcpy(&inputHigh, input + 4, sizeof(inputHigh));
std::memcpy(output, &inputLow, sizeof(inputLow));
std::memcpy(output + 4, &inputHigh, sizeof(inputHigh));
Permute(output, s_initialPermutation, 64);
for (int round = 0; round < rounds; ++round) {
std::uint8_t expanded[8] = {};
for (unsigned i = 0; i < 48; ++i) {
unsigned bit = s_expansion[i] + 31;
if (output[bit >> 3] & (0x80u >> (bit & 7))) {
expanded[i / 6] |= static_cast<std::uint8_t>(0x80u >> (i % 6));
}
}
for (unsigned i = 0; i < 8; ++i) {
expanded[i] ^= this->m_roundKeys[15 - round][i];
}
std::uint8_t substituted[4] = {};
for (unsigned i = 0; i < 8; ++i) {
std::uint8_t value = s_substitution[64 * i + (expanded[i] >> 2)];
if (i & 1) {
@ -159,15 +156,18 @@ namespace myGPack {
}
std::uint8_t transformed[4] = {};
for (unsigned i = 0; i < 32; ++i) {
unsigned bit = s_roundPermutation[i] - 1;
if (substituted[bit >> 3] & (0x80u >> (bit & 7))) {
transformed[i >> 3] |= static_cast<std::uint8_t>(0x80u >> (i & 7));
}
}
std::uint8_t previous[4];
std::memcpy(previous, output, 4);
std::memcpy(output, output + 4, 4);
for (unsigned i = 0; i < 4; ++i) {
output[i + 4] = transformed[i] ^ previous[i];
}
@ -176,22 +176,18 @@ namespace myGPack {
for (unsigned i = 0; i < 4; ++i) {
std::swap(output[i], output[i + 4]);
}
Permute(output, s_finalPermutation, 64);
return 1;
}
// OFFSET: 0x00AE84A0
// FUNCTION: fn_18099
int PakCipher::Decode(
const std::uint8_t* input,
int length,
std::uint8_t* output,
int* outputLength,
int cycle
) const {
int PakCipher::Decode(const std::uint8_t* input, int length, std::uint8_t* output, int* outputLength, int cycle) const {
if (!input || !output || !outputLength) {
return 0;
}
*outputLength = length;
if (cycle < 3) {
cycle = 1;
@ -206,10 +202,10 @@ namespace myGPack {
int shuffled = 0;
int block = 0;
int offset = 0;
do {
if (block >= 20 && block % cycle != 0) {
if (shuffled == 7) {
// Preserve the original store/load order, including in-place use.
std::uint16_t pair;
std::memcpy(&pair, input + offset + 3, 2);
std::memcpy(output + offset, &pair, 2);
@ -221,11 +217,12 @@ namespace myGPack {
output[offset + 7] = SubstituteLastByte(input[offset + 7]);
shuffled = 1;
} else {
std::uint32_t word;
std::memcpy(&word, input + offset, 4);
std::memcpy(output + offset, &word, 4);
std::memcpy(&word, input + offset + 4, 4);
std::memcpy(output + offset + 4, &word, 4);
std::uint32_t low;
std::uint32_t high;
std::memcpy(&low, input + offset, sizeof(low));
std::memcpy(&high, input + offset + 4, sizeof(high));
std::memcpy(output + offset, &low, sizeof(low));
std::memcpy(output + offset + 4, &high, sizeof(high));
++shuffled;
}
} else {
@ -235,9 +232,11 @@ namespace myGPack {
this->DecodeBlock(1, blockInput, blockOutput);
std::memcpy(output + offset, blockOutput, 8);
}
offset += 8;
++block;
} while (offset < length);
return 1;
}
@ -248,6 +247,7 @@ namespace myGPack {
std::memcpy(output, input, static_cast<std::uint32_t>(length));
int offset = 0;
int block = 0;
do {
std::uint8_t blockInput[8];
std::uint8_t decoded[8];
@ -257,6 +257,7 @@ namespace myGPack {
offset += 8;
++block;
} while (offset < length && block < 20);
return 1;
}
@ -264,49 +265,56 @@ namespace myGPack {
// FUNCTION: fn_18104
int __stdcall InitialPermutation(std::uint8_t* block) {
std::uint8_t result[8] = {};
for (unsigned i = 0; i < 64; ++i) {
unsigned bit = s_initialPermutation[i] - 1;
if (block[bit >> 3] & (0x80u >> (bit & 7))) {
result[i >> 3] |= static_cast<std::uint8_t>(0x80u >> (i & 7));
}
}
std::memcpy(block, result, 8);
return *reinterpret_cast<const int*>(result + 4);
int high;
std::memcpy(&high, result + 4, sizeof(high));
return high;
}
// OFFSET: 0x00AE91D0
// FUNCTION: fn_18103
int __stdcall FinalPermutation(std::uint8_t* block) {
std::uint8_t result[8] = {};
for (unsigned i = 0; i < 64; ++i) {
unsigned bit = s_finalPermutation[i] - 1;
if (block[bit >> 3] & (0x80u >> (bit & 7))) {
result[i >> 3] |= static_cast<std::uint8_t>(0x80u >> (i & 7));
}
}
std::memcpy(block, result, 8);
return *reinterpret_cast<const int*>(result + 4);
int high;
std::memcpy(&high, result + 4, sizeof(high));
return high;
}
// OFFSET: 0x00AE9020
// FUNCTION: fn_18102
int __stdcall EncodeBlock(
int rounds,
const std::uint8_t (*roundKeys)[8],
std::uint32_t inputLow,
std::uint32_t inputHigh,
std::uint8_t* output
) {
int __stdcall EncodeBlock(int rounds, const std::uint8_t (*roundKeys)[8], std::uint32_t inputLow, std::uint32_t inputHigh, std::uint8_t* output) {
std::memcpy(output, &inputLow, 4);
std::memcpy(output + 4, &inputHigh, 4);
InitialPermutation(output);
if (rounds > 0) {
std::uint32_t left = *reinterpret_cast<const std::uint32_t*>(output);
std::uint32_t right = *reinterpret_cast<const std::uint32_t*>(output + 4);
std::uint32_t left;
std::uint32_t right;
std::memcpy(&left, output, sizeof(left));
std::memcpy(&right, output + 4, sizeof(right));
for (int round = 0; round < rounds; ++round) {
std::uint8_t expanded[8] = {};
for (unsigned i = 0; i < 48; ++i) {
unsigned bit = s_expansion[i] + 31;
if (output[bit >> 3] & (0x80u >> (bit & 7))) {
@ -319,6 +327,7 @@ namespace myGPack {
}
std::uint8_t substituted[4] = {};
for (unsigned i = 0; i < 8; ++i) {
std::uint8_t value = s_substitution[64 * i + (expanded[i] >> 2)];
if (i & 1) {
@ -329,6 +338,7 @@ namespace myGPack {
}
std::uint8_t transformed[4] = {};
for (unsigned i = 0; i < 32; ++i) {
unsigned bit = s_roundPermutation[i] - 1;
if (substituted[bit >> 3] & (0x80u >> (bit & 7))) {
@ -336,19 +346,24 @@ namespace myGPack {
}
}
std::uint32_t newRight = left ^ *reinterpret_cast<const std::uint32_t*>(transformed);
std::uint32_t transformedWord;
std::memcpy(&transformedWord, transformed, sizeof(transformedWord));
std::uint32_t newRight = left ^ transformedWord;
left = right;
right = newRight;
*reinterpret_cast<std::uint32_t*>(output) = left;
*reinterpret_cast<std::uint32_t*>(output + 4) = right;
std::memcpy(output, &left, sizeof(left));
std::memcpy(output + 4, &right, sizeof(right));
}
*reinterpret_cast<std::uint32_t*>(output) = right;
*reinterpret_cast<std::uint32_t*>(output + 4) = left;
std::memcpy(output, &right, sizeof(right));
std::memcpy(output + 4, &left, sizeof(left));
} else {
std::uint32_t temp = *reinterpret_cast<const std::uint32_t*>(output);
*reinterpret_cast<std::uint32_t*>(output) = *reinterpret_cast<const std::uint32_t*>(output + 4);
*reinterpret_cast<std::uint32_t*>(output + 4) = temp;
std::uint32_t left;
std::uint32_t right;
std::memcpy(&left, output, sizeof(left));
std::memcpy(&right, output + 4, sizeof(right));
std::memcpy(output, &right, sizeof(right));
std::memcpy(output + 4, &left, sizeof(left));
}
FinalPermutation(output);
@ -382,5 +397,4 @@ namespace myGPack {
return key;
}
}

View file

@ -5,9 +5,6 @@
namespace myGPack {
// Reconstructed semantic class name; original symbol unavailable.
// The original stream routine processes complete eight-byte blocks, including
// one block for length <= 0. Callers must provide corresponding buffer space.
class PakCipher {
public:
PakCipher();
@ -25,13 +22,7 @@ namespace myGPack {
std::uint8_t* __stdcall DerivePakKey(const char* name, std::uint8_t* key);
int __stdcall InitialPermutation(std::uint8_t* block);
int __stdcall FinalPermutation(std::uint8_t* block);
int __stdcall EncodeBlock(
int rounds,
const std::uint8_t (*roundKeys)[8],
std::uint32_t inputLow,
std::uint32_t inputHigh,
std::uint8_t* output
);
int __stdcall EncodeBlock(int rounds, const std::uint8_t (*roundKeys)[8], std::uint32_t inputLow, std::uint32_t inputHigh, std::uint8_t* output);
}

View file

@ -1,13 +1,10 @@
#include "Archive/PakFile.h"
#include <bit>
// OFFSET: 0x005EF660
// FUNCTION: fn_04009
CPakFile::~CPakFile() = default;
namespace myGPack {
// OFFSET: 0x005F7790
// FUNCTION: fn_04046
CReadPakFile::CReadPakFile() : m_handle(INVALID_HANDLE_VALUE), m_size(0) {
@ -31,7 +28,6 @@ namespace myGPack {
// OFFSET: 0x005F7810
// FUNCTION: fn_04047
void CReadPakFile::Close() {
// The original tests for null, not INVALID_HANDLE_VALUE.
if (this->m_handle) {
CloseHandle(this->m_handle);
this->m_handle = nullptr;
@ -41,18 +37,15 @@ namespace myGPack {
// OFFSET: 0x005F7890
// FUNCTION: fn_04048
bool CWritePakFile::Open(const char* filename) {
this->m_handle = CreateFileA(
filename, GENERIC_READ | GENERIC_WRITE, 0, nullptr, OPEN_ALWAYS, FILE_FLAG_WRITE_THROUGH | FILE_ATTRIBUTE_NORMAL,
nullptr
);
this->m_handle = CreateFileA(filename, GENERIC_READ | GENERIC_WRITE, 0, nullptr, OPEN_ALWAYS, FILE_FLAG_WRITE_THROUGH | FILE_ATTRIBUTE_NORMAL, nullptr);
if (this->m_handle == INVALID_HANDLE_VALUE) {
return false;
}
LARGE_INTEGER size;
// The original does not check GetFileSizeEx's return value.
GetFileSizeEx(this->m_handle, &size);
this->m_size = std::bit_cast<std::uint64_t>(size.QuadPart);
this->m_size = static_cast<std::uint64_t>(size.QuadPart);
return true;
}
@ -66,14 +59,15 @@ namespace myGPack {
this->m_buffer.resize(length);
LARGE_INTEGER position;
position.QuadPart = std::bit_cast<std::int64_t>(offset);
// Seeking errors are not checked before the original ReadFile call.
position.QuadPart = static_cast<std::int64_t>(offset);
SetFilePointerEx(this->m_handle, position, nullptr, FILE_BEGIN);
DWORD read;
if (ReadFile(this->m_handle, this->m_buffer.data(), length, &read, nullptr) && read == length) {
return this->m_buffer.data();
}
return nullptr;
}
@ -81,7 +75,7 @@ namespace myGPack {
// FUNCTION: fn_04050
bool CWritePakFile::Write(std::uint64_t offset, const void* bytes, std::uint32_t length) {
LARGE_INTEGER position;
position.QuadPart = std::bit_cast<std::int64_t>(offset);
position.QuadPart = static_cast<std::int64_t>(offset);
SetFilePointerEx(this->m_handle, position, nullptr, FILE_BEGIN);
DWORD written;
@ -93,7 +87,7 @@ namespace myGPack {
if (this->m_size < end) {
this->m_size = end;
}
return true;
}
}

View file

@ -5,8 +5,6 @@
#include <vector>
#include <windows.h>
// Class names and inheritance are established by original RTTI.
// Method and member names are reconstructed from their behavior.
class CPakFile {
public:
virtual ~CPakFile();

View file

@ -4,7 +4,6 @@
#include <cstring>
namespace myGPack {
// OFFSET: 0x00AECE00
// FUNCTION: fn_18145
PakName::PakName() {
@ -19,14 +18,15 @@ namespace myGPack {
}
void AssignNameKey(std::uint32_t& result, char* destination, const char* source) {
// Source helper: copies through NUL without bounds checking.
std::strcpy(destination, source);
_strlwr(destination);
const std::size_t length = std::strlen(destination);
std::uint32_t hash = 5381;
for (std::size_t i = 0; i < length; ++i) {
hash = 33 * hash + static_cast<std::int8_t>(destination[i]);
}
result = hash;
}
@ -48,7 +48,7 @@ namespace myGPack {
if (this->m_hash == other.m_hash) {
return std::strcmp(this->m_name, other.m_name) < 0;
}
return this->m_hash < other.m_hash;
}
}

View file

@ -6,10 +6,8 @@
namespace myGPack {
// Shared machine algorithm used with different owner-reserved buffer extents.
void AssignNameKey(std::uint32_t& hash, char* destination, const char* source);
// Reconstructed name for the key embedded at archive entry offset 0x1C.
class PakName {
public:
PakName();

View file

@ -12,6 +12,7 @@ PakRegistry::~PakRegistry() {
delete archive.first;
delete archive.second;
}
this->m_archives.clear();
}
@ -23,6 +24,7 @@ bool PakRegistry::Add(const char* filename) {
if (file) {
file->Open(filename);
}
this->m_archives.emplace_front(file, archive);
return this->m_archives.front().second->Open(this->m_archives.front().first);
}
@ -79,6 +81,7 @@ bool PakRegistry::Exists(const char* filename, bool looseOnly) const {
if (search == INVALID_HANDLE_VALUE) {
return false;
}
FindClose(search);
return true;
}

View file

@ -0,0 +1,19 @@
#include "Client/Application/ApplicationActivation.h"
#include "Client/Application/ApplicationWindow.h"
#include "Contents/Configuration/ServiceOptions.h"
// OFFSET: 0x00E5A190
// FUNCTION: fn_24369
void ApplicationActivation::Set(int value) {
this->active = value;
if (value != 0) {
SetPriorityClass(GetCurrentProcess(), this->priority);
if (this->service.Get(ServiceOption::ConfineCursor) != 0) {
ClipApplicationCursor(this->window);
}
} else {
SetPriorityClass(GetCurrentProcess(), IDLE_PRIORITY_CLASS);
ClipCursor(nullptr);
this->automaticSkills.DisableAll();
}
}

View file

@ -0,0 +1,17 @@
#ifndef RAGNAROK_SOURCE_CLIENT_APPLICATION_APPLICATIONACTIVATION_H
#define RAGNAROK_SOURCE_CLIENT_APPLICATION_APPLICATIONACTIVATION_H
#include "Contents/Skills/AutomaticSkills.h"
#include "Contents/Configuration/ServiceOptions.h"
struct ApplicationActivation {
HWND& window;
const DWORD& priority;
int& active;
ServiceOptions& service;
AutomaticSkills& automaticSkills;
void Set(int value);
};
#endif

View file

@ -0,0 +1,46 @@
#include "Client/Application/ApplicationMessages.h"
#include "Client/Application/ApplicationWindow.h"
#include "Client/Input/TraditionalKeyInput.h"
#include "Contents/Configuration/ServiceOptions.h"
#include <cstdint>
#include <imm.h>
// OFFSET: 0x00E57380
// FUNCTION: fn_24357
void ApplicationMessages::Pump() {
MSG message;
while (PeekMessageA(&message, nullptr, 0, 0, PM_REMOVE)) {
if (message.message == WM_KEYDOWN && message.wParam == VK_PROCESSKEY) {
const UINT key = ImmGetVirtualKey(message.hwnd);
if (this->traditional) {
this->traditional->Key(static_cast<int>(key));
}
}
TranslateMessage(&message);
DispatchMessageA(&message);
}
if (this->dragging == 1) {
POINT point;
GetCursorPos(&point);
const int deltaX = point.x - this->dragStart.x;
const int deltaY = point.y - this->dragStart.y;
if (deltaX != 0 || deltaY != 0) {
MoveWindow(
this->window, this->dragRectangle.left + deltaX, this->dragRectangle.top + deltaY, this->dragRectangle.right - this->dragRectangle.left,
this->dragRectangle.bottom - this->dragRectangle.top, TRUE
);
}
if ((GetAsyncKeyState(VK_LBUTTON) & 0x8000) == 0) {
this->dragging = 0;
if (this->service.Get(ServiceOption::ConfineCursor) != 0) {
ClipApplicationCursor(this->window);
}
}
}
}

View file

@ -0,0 +1,20 @@
#ifndef RAGNAROK_SOURCE_CLIENT_APPLICATION_APPLICATIONMESSAGES_H
#define RAGNAROK_SOURCE_CLIENT_APPLICATION_APPLICATIONMESSAGES_H
#include <windows.h>
struct TraditionalKeyInput;
struct ServiceOptions;
struct ApplicationMessages {
HWND& window;
unsigned char& dragging;
POINT& dragStart;
RECT& dragRectangle;
TraditionalKeyInput* const& traditional;
ServiceOptions& service;
void Pump();
};
#endif

View file

@ -0,0 +1,24 @@
#include "Client/Application/ApplicationWindow.h"
// OFFSET: 0x03DE9F37
// FUNCTION: fn_45411
HWND CreateApplicationWindow(
DWORD extendedStyle, const char* className, const char*, DWORD style, int x, int y, int width, int height, HWND parent, HMENU menu, HINSTANCE instance,
void* parameter
) {
return CreateWindowExA(extendedStyle, className, "Ragnarok 2026", style | WS_SYSMENU, x, y, width, height, parent, menu, instance, parameter);
}
// OFFSET: 0x00E57DD0
// FUNCTION: fn_24360
BOOL ClipApplicationCursor(HWND window) {
RECT rectangle;
GetClientRect(window, &rectangle);
POINT first{rectangle.left, rectangle.top};
POINT last{rectangle.right, rectangle.bottom};
ClientToScreen(window, &first);
ClientToScreen(window, &last);
RECT clip{first.x, first.y, last.x, last.y};
return ClipCursor(&clip);
}

View file

@ -0,0 +1,13 @@
#ifndef RAGNAROK_SOURCE_CLIENT_APPLICATION_APPLICATIONWINDOW_H
#define RAGNAROK_SOURCE_CLIENT_APPLICATION_APPLICATIONWINDOW_H
#include <windows.h>
HWND CreateApplicationWindow(
DWORD extendedStyle, const char* className, const char* ignoredTitle, DWORD style, int x, int y, int width, int height, HWND parent, HMENU menu,
HINSTANCE instance, void* parameter
);
BOOL ClipApplicationCursor(HWND window);
#endif

View file

@ -1,4 +1,4 @@
#include "Client/ErrorDialog.h"
#include "Client/Application/ErrorDialog.h"
#include "Render/RenderSystemBase.h"
// OFFSET: 0x00AD6360
@ -7,5 +7,6 @@ int ShowErrorDialog(CRenderSystemBase* renderSystem, const char* text, UINT type
if (renderSystem) {
renderSystem->PrepareErrorDialog();
}
return MessageBoxA(nullptr, text, "Error", type);
}

View file

@ -0,0 +1,10 @@
#ifndef RAGNAROK_SOURCE_CLIENT_APPLICATION_ERRORDIALOG_H
#define RAGNAROK_SOURCE_CLIENT_APPLICATION_ERRORDIALOG_H
#include <windows.h>
class CRenderSystemBase;
int ShowErrorDialog(CRenderSystemBase* renderSystem, const char* text, UINT type);
#endif

View file

@ -0,0 +1,40 @@
#include "Client/Application/Launcher.h"
#include <cstring>
#include <windows.h>
// OFFSET: 0x00E58820
// FUNCTION: fn_24363
bool RestartFromCommandLine(char* commandLine) {
char* marker = std::strstr(commandLine, "/launcherRESTART:");
if (!marker) {
return false;
}
STARTUPINFOA startup = {};
startup.cb = sizeof(startup);
startup.dwFlags = STARTF_USESHOWWINDOW;
startup.wShowWindow = SW_SHOWNORMAL;
PROCESS_INFORMATION process;
CreateProcessA(nullptr, marker + std::strlen("/launcherRESTART:"), nullptr, nullptr, FALSE, 0, nullptr, nullptr, &startup, &process);
CloseHandle(process.hProcess);
CloseHandle(process.hThread);
return true;
}
// OFFSET: 0x00E5D390
// FUNCTION: fn_24380
void ExitForProtectionCheck(const char* commandLine) {
if (std::strstr(commandLine, "/check_themida")) {
ExitProcess(0);
}
}
// OFFSET: 0x00E5D390
// FUNCTION: fn_24380
bool AcquireInstanceMutex(HANDLE* mutex) {
*mutex = CreateMutexA(nullptr, TRUE, "MutexInit");
return GetLastError() != ERROR_ALREADY_EXISTS;
}

View file

@ -0,0 +1,11 @@
#ifndef RAGNAROK_SOURCE_CLIENT_APPLICATION_LAUNCHER_H
#define RAGNAROK_SOURCE_CLIENT_APPLICATION_LAUNCHER_H
#include <windows.h>
bool RestartFromCommandLine(char* commandLine);
void ExitForProtectionCheck(const char* commandLine);
bool AcquireInstanceMutex(HANDLE* mutex);
#endif

View file

@ -1,4 +1,5 @@
#include "Client/UnhandledExceptionHandler.h"
#include "Client/Mode/ActiveGameMode.h"
#include "Client/Application/UnhandledExceptionHandler.h"
#include <windows.h>
#include <dbghelp.h>
@ -56,35 +57,36 @@ extern int64_t g_loginTimeTicks;
// GLOBAL: gl_24474
extern const uint8_t g_session[];
// STATIC: 0x013495b8
// GLOBAL: gl_24475
extern const uint8_t g_world[];
namespace {
int ReadPlayerJob() {
return *reinterpret_cast<const int*>(reinterpret_cast<uintptr_t>(g_session) + 0x1628);
int job;
std::memcpy(&job, g_session + 0x1628, sizeof(job));
return job;
}
const char* ReadPlayerJobName(int jobId) {
const auto* const* namesBegin = *reinterpret_cast<const char* const* const*>(reinterpret_cast<uintptr_t>(g_session) + 0xFA8);
const auto* const* namesEnd = *reinterpret_cast<const char* const* const*>(reinterpret_cast<uintptr_t>(g_session) + 0xFAC);
const char* const* namesBegin;
const char* const* namesEnd;
std::memcpy(&namesBegin, g_session + 0xFA8, sizeof(namesBegin));
std::memcpy(&namesEnd, g_session + 0xFAC, sizeof(namesEnd));
if (!namesBegin || !namesEnd || namesBegin >= namesEnd) {
return "";
}
size_t count = namesEnd - namesBegin;
if (static_cast<size_t>(jobId) >= count || !namesBegin[jobId]) {
return "";
}
return namesBegin[jobId];
}
const char* ReadCurrentMapName() {
if (*reinterpret_cast<const int*>(reinterpret_cast<uintptr_t>(g_world) + 0x58) == 1) {
void* zone = *reinterpret_cast<void* const*>(reinterpret_cast<uintptr_t>(g_world) + 0x04);
if (zone != nullptr) {
return reinterpret_cast<const char*>(reinterpret_cast<uintptr_t>(zone) + 0x68);
}
if (g_world.state == 1 && g_world.gameMode != nullptr) {
return reinterpret_cast<const char*>(g_world.gameMode) + 0x68;
}
return nullptr;
}
}
@ -149,6 +151,7 @@ int CleanupUnhandledExceptionHandler() {
delete g_unhandledExceptionHandler;
g_unhandledExceptionHandler = nullptr;
}
return 0;
}
@ -216,13 +219,7 @@ BOOL CALLBACK EnumerateLoadedModulesCallback(PCSTR moduleName, ULONG moduleBase,
// OFFSET: 0x00635E00
// FUNCTION: fn_04707
void __cdecl InvalidParameterHandler(
const wchar_t* expression,
const wchar_t* function,
const wchar_t* file,
unsigned int line,
uintptr_t pReserved
) {
void __cdecl InvalidParameterHandler(const wchar_t* expression, const wchar_t* function, const wchar_t* file, unsigned int line, uintptr_t pReserved) {
EXCEPTION_RECORD record = {};
CONTEXT context = {};
EXCEPTION_POINTERS exceptionInfo = {&record, &context};
@ -262,17 +259,14 @@ LONG WINAPI TopLevelExceptionFilter(EXCEPTION_POINTERS* exceptionInfo) {
if (dbgHelp != nullptr) {
auto pStackWalk = reinterpret_cast<BOOL(WINAPI*)(
DWORD, HANDLE, HANDLE, LPSTACKFRAME, PVOID, PREAD_PROCESS_MEMORY_ROUTINE,
PFUNCTION_TABLE_ACCESS_ROUTINE, PGET_MODULE_BASE_ROUTINE, PTRANSLATE_ADDRESS_ROUTINE
DWORD, HANDLE, HANDLE, LPSTACKFRAME, PVOID, PREAD_PROCESS_MEMORY_ROUTINE, PFUNCTION_TABLE_ACCESS_ROUTINE, PGET_MODULE_BASE_ROUTINE,
PTRANSLATE_ADDRESS_ROUTINE
)>(GetProcAddress(dbgHelp, "StackWalk"));
auto pGetTimestamp = reinterpret_cast<DWORD(WINAPI*)(HMODULE)>(
GetProcAddress(dbgHelp, "GetTimestampForLoadedLibrary")
);
auto pGetTimestamp = reinterpret_cast<DWORD(WINAPI*)(HMODULE)>(GetProcAddress(dbgHelp, "GetTimestampForLoadedLibrary"));
auto pEnumerateLoadedModules = reinterpret_cast<BOOL(WINAPI*)(
HANDLE, PENUMLOADED_MODULES_CALLBACK, PVOID
)>(GetProcAddress(dbgHelp, "EnumerateLoadedModules"));
auto pEnumerateLoadedModules =
reinterpret_cast<BOOL(WINAPI*)(HANDLE, PENUMLOADED_MODULES_CALLBACK, PVOID)>(GetProcAddress(dbgHelp, "EnumerateLoadedModules"));
HMODULE module = GetModuleHandleA(nullptr);
CHAR filename[256] = {};
@ -281,7 +275,9 @@ LONG WINAPI TopLevelExceptionFilter(EXCEPTION_POINTERS* exceptionInfo) {
DWORD timestamp = pGetTimestamp ? pGetTimestamp(module) : 0;
sprintf(&g_crashString[strlen(g_crashString)], "Module Name: %s\r\n", filename);
const char* timeString = _ctime32(reinterpret_cast<const __time32_t*>(&timestamp));
__time32_t timestampTime;
std::memcpy(&timestampTime, &timestamp, sizeof(timestampTime));
const char* timeString = _ctime32(&timestampTime);
sprintf(&g_crashString[strlen(g_crashString)], "Time Stamp: 0x%08x - %s\r\n", timestamp, timeString);
sprintf(&g_crashString[strlen(g_crashString)], "Version: 0x%08x\r\n", g_clientVersion);
sprintf(&g_crashString[strlen(g_crashString)], "\r\n");
@ -310,6 +306,7 @@ LONG WINAPI TopLevelExceptionFilter(EXCEPTION_POINTERS* exceptionInfo) {
if (frame.AddrPC.Offset == 0) {
break;
}
if (!pStackWalk(IMAGE_FILE_MACHINE_I386, process, thread, &frame, context, nullptr, nullptr, nullptr, nullptr)) {
break;
}
@ -322,26 +319,28 @@ LONG WINAPI TopLevelExceptionFilter(EXCEPTION_POINTERS* exceptionInfo) {
const auto* stack = reinterpret_cast<const unsigned char*>(context->Esp);
sprintf(&g_crashString[strlen(g_crashString)], "\r\n");
sprintf(
&g_crashString[strlen(g_crashString)],
"stack %08x - %08x\r\n",
static_cast<unsigned int>(reinterpret_cast<uintptr_t>(stack)),
&g_crashString[strlen(g_crashString)], "stack %08x - %08x\r\n", static_cast<unsigned int>(reinterpret_cast<uintptr_t>(stack)),
static_cast<unsigned int>(reinterpret_cast<uintptr_t>(stack + 1024))
);
for (int i = 0; i < 16; ++i) {
sprintf(&g_crashString[strlen(g_crashString)], "%08X : ", static_cast<unsigned int>(reinterpret_cast<uintptr_t>(stack)));
for (int j = 0; j < 16; ++j) {
sprintf(&g_crashString[strlen(g_crashString)], "%02X ", *stack++);
}
sprintf(&g_crashString[strlen(g_crashString)], "\r\n");
}
sprintf(&g_crashString[strlen(g_crashString)], "\r\nLaunch Info \r\n");
int launchIndex = 0;
for (int k = 0; k < 4; ++k) {
for (int m = 0; m < 8; ++m) {
sprintf(&g_crashString[strlen(g_crashString)], "%04X ", g_launchInfo[launchIndex++]);
}
sprintf(&g_crashString[strlen(g_crashString)], "\r\n");
}
@ -354,12 +353,7 @@ LONG WINAPI TopLevelExceptionFilter(EXCEPTION_POINTERS* exceptionInfo) {
sprintf(&g_crashString[strlen(g_crashString)], "%s %d %d\r\n", mapName, g_playerX, g_playerY);
}
sprintf(
&g_crashString[strlen(g_crashString)],
"\r\n%I64d - %I64d",
g_startTimeTicks / 10000000LL,
g_loginTimeTicks / 10000000LL
);
sprintf(&g_crashString[strlen(g_crashString)], "\r\n%I64d - %I64d", g_startTimeTicks / 10000000LL, g_loginTimeTicks / 10000000LL);
int64_t reportTime = _Xtime_get_ticks() / 10000000LL;
PROCESS_MEMORY_COUNTERS memCounters = {};

View file

@ -1,5 +1,5 @@
#ifndef RAGNAROK_SOURCE_CLIENT_UNHANDLEDEXCEPTIONHANDLER_H
#define RAGNAROK_SOURCE_CLIENT_UNHANDLEDEXCEPTIONHANDLER_H
#ifndef RAGNAROK_SOURCE_CLIENT_APPLICATION_UNHANDLEDEXCEPTIONHANDLER_H
#define RAGNAROK_SOURCE_CLIENT_APPLICATION_UNHANDLEDEXCEPTIONHANDLER_H
#include <windows.h>
#include <cstdint>
@ -39,13 +39,7 @@ BOOL CALLBACK EnumerateLoadedModulesCallback(PCSTR moduleName, ULONG moduleBase,
// OFFSET: 0x00635E00
// FUNCTION: fn_04707
void __cdecl InvalidParameterHandler(
const wchar_t* expression,
const wchar_t* function,
const wchar_t* file,
unsigned int line,
uintptr_t pReserved
);
void __cdecl InvalidParameterHandler(const wchar_t* expression, const wchar_t* function, const wchar_t* file, unsigned int line, uintptr_t pReserved);
// OFFSET: 0x00635E90
// FUNCTION: fn_04708
@ -55,4 +49,4 @@ void __cdecl PurecallHandler();
// FUNCTION: fn_04709
LONG WINAPI TopLevelExceptionFilter(EXCEPTION_POINTERS* exceptionInfo);
#endif // RAGNAROK_SOURCE_CLIENT_UNHANDLEDEXCEPTIONHANDLER_H
#endif

View file

@ -1,20 +0,0 @@
#include "Client/ApplicationActivation.h"
#include "Client/ApplicationWindow.h"
namespace client {
// OFFSET: 0x00E5A190
// FUNCTION: fn_24369
void ApplicationActivation::Set(int value) {
this->active = value;
if (value != 0) {
SetPriorityClass(GetCurrentProcess(), this->priority);
if (this->service.Get(271) != 0) {
ClipApplicationCursor(this->window);
}
} else {
SetPriorityClass(GetCurrentProcess(), IDLE_PRIORITY_CLASS);
ClipCursor(nullptr);
this->automaticSkills.DisableAll();
}
}
}

View file

@ -1,23 +0,0 @@
#ifndef RAGNAROK_SOURCE_CLIENT_APPLICATIONACTIVATION_H
#define RAGNAROK_SOURCE_CLIENT_APPLICATIONACTIVATION_H
#include "Contents/AutomaticSkills.h"
#include "Contents/ServiceOptions.h"
namespace client {
// Borrowed original main-window/priority/active globals and concrete owners.
struct ApplicationActivation {
HWND& window;
const DWORD& priority;
int& active;
ServiceOptions& service;
AutomaticSkills& automaticSkills;
// Publishes value verbatim. Nonzero restores configured process priority
// and clips only when option 271 is enabled. Zero selects idle priority,
// releases clipping, then cancels automatic skills through their connection.
void Set(int value);
};
}
#endif

View file

@ -1,47 +0,0 @@
#include "Client/ApplicationMessages.h"
#include "Client/ApplicationWindow.h"
#include "Client/TraditionalKeyInput.h"
#include "Contents/ServiceOptions.h"
#include <cstdint>
#include <imm.h>
namespace client {
// OFFSET: 0x00E57380
// FUNCTION: fn_24357
void ApplicationMessages::Pump() {
MSG message;
while (PeekMessageA(&message, nullptr, 0, 0, PM_REMOVE)) {
if (message.message == WM_KEYDOWN && message.wParam == VK_PROCESSKEY) {
const UINT key = ImmGetVirtualKey(message.hwnd);
if (this->traditional) {
this->traditional->Key(static_cast<int>(key));
}
}
TranslateMessage(&message);
DispatchMessageA(&message);
}
if (this->dragging == 1) {
POINT point;
GetCursorPos(&point);
const int deltaX = point.x - this->dragStart.x;
const int deltaY = point.y - this->dragStart.y;
if (deltaX != 0 || deltaY != 0) {
MoveWindow(
this->window, this->dragRectangle.left + deltaX, this->dragRectangle.top + deltaY,
this->dragRectangle.right - this->dragRectangle.left, this->dragRectangle.bottom - this->dragRectangle.top,
TRUE
);
}
if ((GetAsyncKeyState(VK_LBUTTON) & 0x8000) == 0) {
this->dragging = 0;
if (this->service.Get(271) != 0) {
ClipApplicationCursor(this->window);
}
}
}
}
}

View file

@ -1,26 +0,0 @@
#ifndef RAGNAROK_SOURCE_CLIENT_APPLICATIONMESSAGES_H
#define RAGNAROK_SOURCE_CLIENT_APPLICATIONMESSAGES_H
#include <windows.h>
struct TraditionalKeyInput;
struct ServiceOptions;
namespace client {
// Borrowed application globals. A non-null traditional input view denotes
// CLanguageTC; base/TH/ARB virtual-key delivery is an established empty entry.
struct ApplicationMessages {
HWND& window;
unsigned char& dragging;
POINT& dragStart;
RECT& dragRectangle;
TraditionalKeyInput* const& traditional;
ServiceOptions& service;
// Drains all messages (including WM_QUIT) through Translate/Dispatch, then
// updates native window dragging. Does not invent the main window procedure.
void Pump();
};
}
#endif

View file

@ -1,39 +0,0 @@
#include "Client/ApplicationWindow.h"
namespace client {
// OFFSET: 0x03DE9F37
// FUNCTION: fn_45411
HWND CreateApplicationWindow(
DWORD extendedStyle,
const char* className,
const char*,
DWORD style,
int x,
int y,
int width,
int height,
HWND parent,
HMENU menu,
HINSTANCE instance,
void* parameter
) {
return CreateWindowExA(
extendedStyle, className, "Ragnarok 2026", style | WS_SYSMENU, x, y, width, height, parent, menu, instance,
parameter
);
}
// OFFSET: 0x00E57DD0
// FUNCTION: fn_24360
BOOL ClipApplicationCursor(HWND window) {
RECT rectangle;
GetClientRect(window, &rectangle);
POINT first{rectangle.left, rectangle.top};
POINT last{rectangle.right, rectangle.bottom};
ClientToScreen(window, &first);
ClientToScreen(window, &last);
RECT clip{first.x, first.y, last.x, last.y};
return ClipCursor(&clip);
}
}

View file

@ -1,29 +0,0 @@
#ifndef RAGNAROK_SOURCE_CLIENT_APPLICATIONWINDOW_H
#define RAGNAROK_SOURCE_CLIENT_APPLICATIONWINDOW_H
#include <windows.h>
namespace client {
// Recovered CreateWindowExA wrapper, not the full application initializer.
// Forces the title "Ragnarok 2026" and adds WS_SYSMENU to the caller's style.
HWND CreateApplicationWindow(
DWORD extendedStyle,
const char* className,
const char* ignoredTitle,
DWORD style,
int x,
int y,
int width,
int height,
HWND parent,
HMENU menu,
HINSTANCE instance,
void* parameter
);
// Original global main-window handle is borrowed; clips its client rectangle
// after converting both corners to screen coordinates. Returns ClipCursor.
BOOL ClipApplicationCursor(HWND window);
}
#endif

View file

@ -1,4 +1,4 @@
#include "Client/BrowserAddressBar.h"
#include "Client/Browser/BrowserAddressBar.h"
#include <commctrl.h>
@ -6,7 +6,10 @@
// FUNCTION: fn_17416
bool BrowserAddressBar::Create(int width, int requestedHeight) {
this->rebar = CreateWindowExA(
0x80, "ReBarWindow32", "rebar", 0x56809648, 0, 0, width, 0, this->host, nullptr, GetModuleHandleA(nullptr), nullptr
WS_EX_TOOLWINDOW, REBARCLASSNAMEA, "rebar",
WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_BORDER | RBS_VARHEIGHT | RBS_BANDBORDERS | RBS_REGISTERDROP | RBS_DBLCLKTOGGLE |
CCS_NOPARENTALIGN | CCS_NODIVIDER,
0, 0, width, 0, this->host, nullptr, GetModuleHandleA(nullptr), nullptr
);
if (!this->rebar) {
return false;
@ -19,33 +22,31 @@ bool BrowserAddressBar::Create(int width, int requestedHeight) {
}
HWND combo = CreateWindowExA(
0x200, "COMBOBOX", "addressbar", 0x50000002, 10, 10, 160, 22, this->rebar, nullptr, GetModuleHandleA(nullptr),
WS_EX_CLIENTEDGE, WC_COMBOBOXA, "addressbar", WS_CHILD | WS_VISIBLE | CBS_DROPDOWN, 10, 10, 160, 22, this->rebar, nullptr, GetModuleHandleA(nullptr),
nullptr
);
REBARBANDINFOA band{};
band.cbSize = sizeof(band);
band.fMask = 0xF1;
band.fStyle = 0x24;
band.fMask = RBBIM_STYLE | RBBIM_CHILD | RBBIM_CHILDSIZE | RBBIM_SIZE | RBBIM_BACKGROUND;
band.fStyle = RBBS_CHILDEDGE | RBBS_FIXEDBMP;
band.hwndChild = combo;
band.cxMinChild = 0;
band.cyMinChild = requestedHeight;
band.cx = 160;
band.hbmBack = LoadBitmapA(GetModuleHandleA(nullptr), nullptr);
if (!SendMessageA(this->rebar, RB_INSERTBANDA, static_cast<WPARAM>(-1), reinterpret_cast<LPARAM>(&band))) {
return false;
}
this->combo = combo;
HWND edit = GetWindow(combo, GW_CHILD);
this->previous =
reinterpret_cast<WNDPROC>(SetWindowLongPtrA(edit, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(this->procedure)));
this->previous = reinterpret_cast<WNDPROC>(SetWindowLongPtrA(edit, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(this->procedure)));
RECT rectangle;
GetClientRect(this->host, &rectangle);
SetWindowPos(
this->rebar, nullptr, 0, 0, rectangle.right - rectangle.left, rectangle.bottom - rectangle.top, SWP_NOMOVE
);
SetWindowPos(this->rebar, nullptr, 0, 0, rectangle.right - rectangle.left, rectangle.bottom - rectangle.top, SWP_NOMOVE);
ShowWindow(this->rebar, SW_HIDE);
this->height = 0;

View file

@ -0,0 +1,18 @@
#ifndef RAGNAROK_SOURCE_CLIENT_BROWSER_BROWSERADDRESSBAR_H
#define RAGNAROK_SOURCE_CLIENT_BROWSER_BROWSERADDRESSBAR_H
#include <windows.h>
struct BrowserAddressBar {
HWND const& host;
HWND& rebar;
HWND& combo;
int& height;
const unsigned char& visible;
WNDPROC& previous;
WNDPROC procedure;
bool Create(int width, int height);
};
#endif

View file

@ -1,4 +1,5 @@
#include "Client/BrowserAddressEdit.h"
#include "Client/Browser/BrowserAddressEdit.h"
#include "Client/Browser/BrowserMessages.h"
// OFFSET: 0x00AB21F0
// FUNCTION: fn_17412
@ -9,7 +10,7 @@ LRESULT BrowserAddressEdit::Message(HWND window, UINT message, WPARAM value, LPA
}
if (message == WM_KEYDOWN && this->activeHost) {
SendMessageA(*this->activeHost, WM_COMMAND, 1000, 0);
SendMessageA(*this->activeHost, WM_COMMAND, static_cast<WPARAM>(BrowserCommand::Navigate), 0);
return 0;
}
}

View file

@ -0,0 +1,13 @@
#ifndef RAGNAROK_SOURCE_CLIENT_BROWSER_BROWSERADDRESSEDIT_H
#define RAGNAROK_SOURCE_CLIENT_BROWSER_BROWSERADDRESSEDIT_H
#include <windows.h>
struct BrowserAddressEdit {
WNDPROC const& previous;
HWND const* const& activeHost;
LRESULT Message(HWND window, UINT message, WPARAM value, LPARAM flags);
};
#endif

View file

@ -1,16 +1,10 @@
#include "Client/BrowserClientSite.h"
#include "Client/Browser/BrowserClientSite.h"
// OFFSET: 0x00AB1310
// FUNCTION: fn_17334
BrowserClientSite::BrowserClientSite(
HWND window,
IUnknown& browser,
BrowserFactory& factory,
const int& width,
const int& height
)
: m_window(window), m_browser(&browser), m_events(*this, factory, width, height),
m_inPlace(*this, this->m_window, this->m_browser), m_documentUI(*this), m_commands(*this) {
BrowserClientSite::BrowserClientSite(HWND window, IUnknown& browser, BrowserFactory& factory, const int& width, const int& height)
: m_window(window), m_browser(&browser), m_events(*this, factory, width, height), m_inPlace(*this, this->m_window, this->m_browser), m_documentUI(*this),
m_commands(*this) {
this->m_browser->AddRef();
}
@ -40,8 +34,6 @@ HRESULT STDMETHODCALLTYPE BrowserClientSite::QueryInterface(REFIID iid, void** o
} else if (iid == IID_IOleCommandTarget) {
*output = static_cast<IOleCommandTarget*>(&this->m_commands);
} else {
// Unlike standard COM helpers, the original does not clear a failed output
// and does not AddRef a successful result.
return E_NOINTERFACE;
}

View file

@ -1,16 +1,11 @@
#ifndef RAGNAROK_SOURCE_CLIENT_BROWSERCLIENTSITE_H
#define RAGNAROK_SOURCE_CLIENT_BROWSERCLIENTSITE_H
#ifndef RAGNAROK_SOURCE_CLIENT_BROWSER_BROWSERCLIENTSITE_H
#define RAGNAROK_SOURCE_CLIENT_BROWSER_BROWSERCLIENTSITE_H
#include "Client/BrowserCommandTarget.h"
#include "Client/BrowserDocumentUI.h"
#include "Client/BrowserInPlace.h"
#include "UI/BrowserPopupDispatch.h"
#include "Client/Browser/BrowserCommandTarget.h"
#include "Client/Browser/BrowserDocumentUI.h"
#include "Client/Browser/BrowserInPlace.h"
#include "Client/Browser/BrowserPopupDispatch.h"
// Recovered site COM contracts with its owned popup-dispatch tear-off.
// Factory and renderer dimensions must outlive the site. QueryInterface does
// not acquire references; the containing browser controls this site's lifetime.
// Retains the browser until destruction. COM reference calls return one;
// lifetime is controlled by the containing CWebBrowser, not COM reference counts.
class BrowserClientSite final : public IOleClientSite {
public:
BrowserClientSite(HWND window, IUnknown& browser, BrowserFactory& factory, const int& width, const int& height);

View file

@ -1,5 +1,5 @@
#include "Client/BrowserClose.h"
#include "Client/Mouse.h"
#include "Client/Browser/BrowserClose.h"
#include "Client/Input/Mouse.h"
// OFFSET: 0x00AB24D0
// FUNCTION: fn_45432

View file

@ -0,0 +1,21 @@
#ifndef RAGNAROK_SOURCE_CLIENT_BROWSER_BROWSERCLOSE_H
#define RAGNAROK_SOURCE_CLIENT_BROWSER_BROWSERCLOSE_H
#include "Client/Browser/BrowserSiteAttachment.h"
class CMouse;
struct BrowserClose {
BrowserSiteAttachment& attachment;
IWebBrowser2*& browser;
IUnknown*& externalEvents;
HWND& host;
HWND const& browserWindow;
HWND const& applicationWindow;
int& cursorState;
CMouse& mouse;
bool Close();
};
#endif

View file

@ -1,4 +1,6 @@
#include "Client/BrowserCommandTarget.h"
#include "Client/Browser/BrowserCommandTarget.h"
#include <mshtmhst.h>
// OFFSET: 0x00AB1A80
// FUNCTION: fn_17379
@ -21,7 +23,6 @@ ULONG STDMETHODCALLTYPE BrowserCommandTarget::Release() {
// OFFSET: 0x00AB1C50
// FUNCTION: fn_17385
HRESULT STDMETHODCALLTYPE BrowserCommandTarget::QueryStatus(const GUID*, ULONG, OLECMD[], OLECMDTEXT*) {
// The original reports success without reading or publishing command flags.
return S_OK;
}
@ -29,15 +30,11 @@ HRESULT STDMETHODCALLTYPE BrowserCommandTarget::QueryStatus(const GUID*, ULONG,
// FUNCTION: fn_17353
HRESULT STDMETHODCALLTYPE BrowserCommandTarget::Exec(const GUID* group, DWORD command, DWORD, VARIANT*, VARIANT*) {
// STATIC: 0x011B0880 (CGID_DocHostCommandHandler)
static constexpr GUID documentHostCommands = {
0xF38BC242, 0xB950, 0x11D1, {0x89, 0x18, 0x00, 0xC0, 0x4F, 0xC2, 0xC8, 0x36}
};
if (!group || !IsEqualGUID(*group, documentHostCommands)) {
if (!group || !IsEqualGUID(*group, CGID_DocHostCommandHandler)) {
return OLECMDERR_E_UNKNOWNGROUP;
}
if (command == 40 || command == 41) {
if (command == OLECMDID_SHOWSCRIPTERROR || command == OLECMDID_SHOWMESSAGE) {
return S_OK;
}

View file

@ -1,15 +1,10 @@
#ifndef RAGNAROK_SOURCE_CLIENT_BROWSERCOMMANDTARGET_H
#define RAGNAROK_SOURCE_CLIENT_BROWSERCOMMANDTARGET_H
#ifndef RAGNAROK_SOURCE_CLIENT_BROWSER_BROWSERCOMMANDTARGET_H
#define RAGNAROK_SOURCE_CLIENT_BROWSER_BROWSERCOMMANDTARGET_H
// clang-format off
#include <windows.h>
#include <ole2.h>
#include <docobj.h>
// clang-format on
// CWebBrowser's site owns this tear-off interface.
// Identity delegates to that site; AddRef/Release deliberately return one.
// The caller must keep the site alive for this interface's entire lifetime.
class BrowserCommandTarget final : public IOleCommandTarget {
public:
explicit BrowserCommandTarget(IUnknown& site) : m_site(site) {
@ -19,8 +14,7 @@ public:
ULONG STDMETHODCALLTYPE AddRef() override;
ULONG STDMETHODCALLTYPE Release() override;
HRESULT STDMETHODCALLTYPE QueryStatus(const GUID* group, ULONG count, OLECMD commands[], OLECMDTEXT* text) override;
HRESULT STDMETHODCALLTYPE
Exec(const GUID* group, DWORD command, DWORD options, VARIANT* input, VARIANT* output) override;
HRESULT STDMETHODCALLTYPE Exec(const GUID* group, DWORD command, DWORD options, VARIANT* input, VARIANT* output) override;
private:
IUnknown& m_site;

View file

@ -1,5 +1,5 @@
#include "Client/BrowserCreation.h"
#include "Client/BrowserInterface.h"
#include "Client/Browser/BrowserCreation.h"
#include "Client/Browser/BrowserInterface.h"
// OFFSET: 0x00AB22B0
// FUNCTION: fn_17413

View file

@ -0,0 +1,18 @@
#ifndef RAGNAROK_SOURCE_CLIENT_BROWSER_BROWSERCREATION_H
#define RAGNAROK_SOURCE_CLIENT_BROWSER_BROWSERCREATION_H
#include "Client/Browser/BrowserAddressBar.h"
#include "Client/Browser/BrowserHostWindow.h"
#include "Client/Browser/BrowserSiteAttachment.h"
struct BrowserCreation {
IWebBrowser2*& browser;
HWND& browserWindow;
BrowserHostWindow& window;
BrowserSiteAttachment& attachment;
BrowserAddressBar& addressBar;
bool Create(HWND parent, HINSTANCE instance, int width, int height);
};
#endif

View file

@ -1,5 +1,5 @@
#include "Client/BrowserCursor.h"
#include "Client/Mouse.h"
#include "Client/Browser/BrowserCursor.h"
#include "Client/Input/Mouse.h"
#include "Render/RenderSystemBase.h"
// OFFSET: 0x00AB32E0
@ -10,9 +10,8 @@ void BrowserCursor::Set(int value) {
}
if (value != 0) {
SetCursor(LoadCursorA(nullptr, MAKEINTRESOURCEA(32512)));
// Original mouse centering queries Width then Height before replacing
// both coordinates with -100. Retain these virtual calls and their order.
SetCursor(LoadCursorA(nullptr, reinterpret_cast<LPCSTR>(IDC_ARROW)));
this->mouse.SetX(static_cast<int>(this->renderSystem.Width()) / 2);
this->mouse.SetY(static_cast<int>(this->renderSystem.Height()) / 2);
this->mouse.SetX(-100);

View file

@ -0,0 +1,19 @@
#ifndef RAGNAROK_SOURCE_CLIENT_BROWSER_BROWSERCURSOR_H
#define RAGNAROK_SOURCE_CLIENT_BROWSER_BROWSERCURSOR_H
#include <windows.h>
class CMouse;
class CRenderSystemBase;
struct BrowserCursor {
int& state;
CMouse& mouse;
CRenderSystemBase& renderSystem;
HWND const& applicationWindow;
void Set(int value);
void Poll();
};
#endif

View file

@ -1,4 +1,4 @@
#include "Client/BrowserDocumentUI.h"
#include "Client/Browser/BrowserDocumentUI.h"
// OFFSET: 0x00AB1AC0
// FUNCTION: fn_17381
@ -27,23 +27,16 @@ HRESULT STDMETHODCALLTYPE BrowserDocumentUI::ShowContextMenu(DWORD, POINT*, IUnk
// OFFSET: 0x00AB1770
// FUNCTION: fn_17359
HRESULT STDMETHODCALLTYPE BrowserDocumentUI::GetHostInfo(DOCHOSTUIINFO* info) {
// Original x86 cbSize, even when compiling for a wider host. The two optional
// string pointers are not initialized by this operation.
info->cbSize = 20;
info->dwFlags = 4;
info->dwDoubleClick = 0;
info->cbSize = sizeof(*info);
info->dwFlags = DOCHOSTUIFLAG_NO3DBORDER;
info->dwDoubleClick = DOCHOSTUIDBLCLK_DEFAULT;
return S_OK;
}
// OFFSET: 0x00AB1D80
// FUNCTION: fn_17404
HRESULT STDMETHODCALLTYPE BrowserDocumentUI::ShowUI(
DWORD,
IOleInPlaceActiveObject*,
IOleCommandTarget*,
IOleInPlaceFrame*,
IOleInPlaceUIWindow*
) {
HRESULT STDMETHODCALLTYPE BrowserDocumentUI::ShowUI(DWORD, IOleInPlaceActiveObject*, IOleCommandTarget*, IOleInPlaceFrame*, IOleInPlaceUIWindow*) {
return S_OK;
}

View file

@ -1,14 +1,10 @@
#ifndef RAGNAROK_SOURCE_CLIENT_BROWSERDOCUMENTUI_H
#define RAGNAROK_SOURCE_CLIENT_BROWSERDOCUMENTUI_H
#ifndef RAGNAROK_SOURCE_CLIENT_BROWSER_BROWSERDOCUMENTUI_H
#define RAGNAROK_SOURCE_CLIENT_BROWSER_BROWSERDOCUMENTUI_H
// clang-format off
#include <windows.h>
#include <ole2.h>
#include <mshtmhst.h>
// clang-format on
// Site-owned IDocHostUIHandler tear-off. Identity delegates to the borrowed
// site; reference calls do not manage lifetime. Unwritten outputs stay unwritten.
class BrowserDocumentUI final : public IDocHostUIHandler {
public:
explicit BrowserDocumentUI(IUnknown& site) : m_site(site) {
@ -19,13 +15,8 @@ public:
ULONG STDMETHODCALLTYPE Release() override;
HRESULT STDMETHODCALLTYPE ShowContextMenu(DWORD id, POINT* point, IUnknown* reserved, IDispatch* dispatch) override;
HRESULT STDMETHODCALLTYPE GetHostInfo(DOCHOSTUIINFO* info) override;
HRESULT STDMETHODCALLTYPE ShowUI(
DWORD id,
IOleInPlaceActiveObject* active,
IOleCommandTarget* commands,
IOleInPlaceFrame* frame,
IOleInPlaceUIWindow* document
) override;
HRESULT STDMETHODCALLTYPE
ShowUI(DWORD id, IOleInPlaceActiveObject* active, IOleCommandTarget* commands, IOleInPlaceFrame* frame, IOleInPlaceUIWindow* document) override;
HRESULT STDMETHODCALLTYPE HideUI() override;
HRESULT STDMETHODCALLTYPE UpdateUI() override;
HRESULT STDMETHODCALLTYPE EnableModeless(BOOL enable) override;

View file

@ -1,8 +1,8 @@
#include "Client/BrowserRegistry.h"
#include "Client/WebBrowser.h"
#include "Client/Browser/BrowserRegistry.h"
#include "Client/Browser/WebBrowser.h"
#include "Contents/MessageTable.h"
#include "UI/BrowserFactory.h"
#include "UI/ChatNotifications.h"
#include "Client/Browser/BrowserFactory.h"
#include "UI/Chat/ChatNotifications.h"
#include <new>
@ -13,6 +13,7 @@ CWebBrowser* BrowserFactory::Create(int width, int height) {
this->notifications.Refresh();
const char* message = LookupMessage(1578, this->languagePrefix, this->serviceType, this->language);
this->notifications.Text(message, 255, nullptr, 0, false);
return nullptr;
}

View file

@ -1,5 +1,5 @@
#ifndef RAGNAROK_SOURCE_UI_BROWSERFACTORY_H
#define RAGNAROK_SOURCE_UI_BROWSERFACTORY_H
#ifndef RAGNAROK_SOURCE_CLIENT_BROWSER_BROWSERFACTORY_H
#define RAGNAROK_SOURCE_CLIENT_BROWSER_BROWSERFACTORY_H
#include <windows.h>
@ -8,9 +8,6 @@ struct WebBrowserContext;
struct BrowserRegistry;
struct ChatNotifications;
// Ordinary browser creation is distinct from the special-browser factory.
// The limit counts all map nodes, not nonnull entries. Failed ordinary creation
// retains the allocated browser in the original; it is not published or deleted.
struct BrowserFactory {
BrowserRegistry& registry;
WebBrowserContext& context;

View file

@ -1,4 +1,4 @@
#include "Client/BrowserFrame.h"
#include "Client/Browser/BrowserFrame.h"
// OFFSET: 0x00AB2610
// FUNCTION: fn_17414
@ -9,10 +9,7 @@ void BrowserFrame::Normalize() {
RECT rectangle;
GetWindowRect(this->browserWindow, &rectangle);
if (
rectangle.right - rectangle.left != this->sizing.screenWidth ||
rectangle.bottom - rectangle.top != this->sizing.screenHeight
) {
if (rectangle.right - rectangle.left != this->sizing.screenWidth || rectangle.bottom - rectangle.top != this->sizing.screenHeight) {
return;
}

View file

@ -0,0 +1,18 @@
#ifndef RAGNAROK_SOURCE_CLIENT_BROWSER_BROWSERFRAME_H
#define RAGNAROK_SOURCE_CLIENT_BROWSER_BROWSERFRAME_H
#include "Client/Browser/BrowserCursor.h"
#include "Client/Browser/BrowserWindowSizing.h"
struct BrowserFrame {
BrowserWindowSizing& sizing;
BrowserCursor& cursor;
HWND const& host;
HWND const& browserWindow;
const bool& hasExternalEvents;
void Normalize();
void Poll();
};
#endif

View file

@ -1,4 +1,4 @@
#include "Client/BrowserHostWindow.h"
#include "Client/Browser/BrowserHostWindow.h"
// OFFSET: 0x00AB29D0
// FUNCTION: fn_45435
@ -11,10 +11,7 @@ bool BrowserHostWindow::Create(HWND parent, HINSTANCE instance, int width, int h
windowClass.lpszClassName = "ROWebBrowser";
RegisterClassExA(&windowClass);
this->host = CreateWindowExA(
0, "ROWebBrowser", this->title, WS_POPUP | WS_OVERLAPPEDWINDOW, 0, 0, width, height, parent, nullptr, instance,
nullptr
);
this->host = CreateWindowExA(0, "ROWebBrowser", this->title, WS_POPUP | WS_OVERLAPPEDWINDOW, 0, 0, width, height, parent, nullptr, instance, nullptr);
if (!this->host) {
OutputDebugStringA("failed : CreateWindow() \n");
return false;
@ -23,5 +20,6 @@ bool BrowserHostWindow::Create(HWND parent, HINSTANCE instance, int width, int h
UpdateWindow(this->host);
SetParent(this->browser, this->host);
SetWindowLongA(this->browser, GWL_STYLE, WS_CHILD);
return true;
}

View file

@ -0,0 +1,15 @@
#ifndef RAGNAROK_SOURCE_CLIENT_BROWSER_BROWSERHOSTWINDOW_H
#define RAGNAROK_SOURCE_CLIENT_BROWSER_BROWSERHOSTWINDOW_H
#include <windows.h>
struct BrowserHostWindow {
HWND& host;
HWND const& browser;
const char* const& title;
WNDPROC procedure;
bool Create(HWND parent, HINSTANCE instance, int width, int height);
};
#endif

View file

@ -1,4 +1,4 @@
#include "Client/BrowserInPlace.h"
#include "Client/Browser/BrowserInPlace.h"
// OFFSET: 0x00AB1AE0
// FUNCTION: fn_17382
@ -142,19 +142,15 @@ HRESULT STDMETHODCALLTYPE BrowserInPlaceSite::OnUIActivate() {
// OFFSET: 0x00AB1820
// FUNCTION: fn_17367
HRESULT STDMETHODCALLTYPE BrowserInPlaceSite::GetWindowContext(
IOleInPlaceFrame** frame,
IOleInPlaceUIWindow** document,
RECT*,
RECT*,
OLEINPLACEFRAMEINFO* info
) {
HRESULT STDMETHODCALLTYPE
BrowserInPlaceSite::GetWindowContext(IOleInPlaceFrame** frame, IOleInPlaceUIWindow** document, RECT*, RECT*, OLEINPLACEFRAMEINFO* info) {
*frame = &this->m_frame;
*document = nullptr;
info->fMDIApp = FALSE;
info->hwndFrame = this->m_window;
info->haccel = nullptr;
info->cAccelEntries = 0;
return S_OK;
}
@ -191,8 +187,6 @@ HRESULT STDMETHODCALLTYPE BrowserInPlaceSite::DeactivateAndUndo() {
// OFFSET: 0x00AB19F0
// FUNCTION: fn_17375
HRESULT STDMETHODCALLTYPE BrowserInPlaceSite::OnPosRectChange(const RECT* position) {
// The original requires an attached browser and retains this IOleObject
// reference, including when its subsequent in-place QueryInterface fails.
IOleObject* object;
HRESULT result = this->m_browser->QueryInterface(IID_IOleObject, reinterpret_cast<void**>(&object));
if (SUCCEEDED(result)) {

View file

@ -1,13 +1,9 @@
#ifndef RAGNAROK_SOURCE_CLIENT_BROWSERINPLACE_H
#define RAGNAROK_SOURCE_CLIENT_BROWSERINPLACE_H
#ifndef RAGNAROK_SOURCE_CLIENT_BROWSER_BROWSERINPLACE_H
#define RAGNAROK_SOURCE_CLIENT_BROWSER_BROWSERINPLACE_H
// clang-format off
#include <windows.h>
#include <ole2.h>
// clang-format on
// Site-owned tear-offs: borrowed identity, HWND and browser, with fixed-one
// reference counts. These interfaces do not own or extend the site's lifetime.
class BrowserInPlaceFrame final : public IOleInPlaceFrame {
public:
BrowserInPlaceFrame(IUnknown& site, HWND const& window) : m_site(site), m_window(window) {
@ -36,8 +32,7 @@ private:
class BrowserInPlaceSite final : public IOleInPlaceSite {
public:
BrowserInPlaceSite(IUnknown& site, HWND const& window, IUnknown* const& browser)
: m_site(site), m_window(window), m_browser(browser), m_frame(site, window) {
BrowserInPlaceSite(IUnknown& site, HWND const& window, IUnknown* const& browser) : m_site(site), m_window(window), m_browser(browser), m_frame(site, window) {
}
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void** output) override;
@ -48,13 +43,8 @@ public:
HRESULT STDMETHODCALLTYPE CanInPlaceActivate() override;
HRESULT STDMETHODCALLTYPE OnInPlaceActivate() override;
HRESULT STDMETHODCALLTYPE OnUIActivate() override;
HRESULT STDMETHODCALLTYPE GetWindowContext(
IOleInPlaceFrame** frame,
IOleInPlaceUIWindow** document,
RECT* position,
RECT* clip,
OLEINPLACEFRAMEINFO* info
) override;
HRESULT STDMETHODCALLTYPE
GetWindowContext(IOleInPlaceFrame** frame, IOleInPlaceUIWindow** document, RECT* position, RECT* clip, OLEINPLACEFRAMEINFO* info) override;
HRESULT STDMETHODCALLTYPE Scroll(SIZE extent) override;
HRESULT STDMETHODCALLTYPE OnUIDeactivate(BOOL undoable) override;
HRESULT STDMETHODCALLTYPE OnInPlaceDeactivate() override;

View file

@ -1,17 +1,17 @@
#include "Client/ApplicationActivation.h"
#include "Client/BrowserInputHandoff.h"
#include "Client/Mouse.h"
#include "Contents/ServiceOptions.h"
#include "Client/Application/ApplicationActivation.h"
#include "Client/Browser/BrowserInputHandoff.h"
#include "Client/Input/Mouse.h"
#include "Contents/Configuration/ServiceOptions.h"
// OFFSET: 0x00AB2720
// FUNCTION: fn_45433
void BrowserInputHandoff::Enter() {
if (this->service.Get(271) == 0) {
if (this->service.Get(ServiceOption::ConfineCursor) == 0) {
return;
}
POINT position{this->mouse.x, this->mouse.y};
this->service.Set(271, 0);
this->service.Set(ServiceOption::ConfineCursor, 0);
this->mouse.SetX(position.x);
this->mouse.SetY(position.y);
this->restoreOption = 1;
@ -29,7 +29,7 @@ void BrowserInputHandoff::Restore() {
POINT position;
GetCursorPos(&position);
ScreenToClient(this->applicationWindow, &position);
this->service.Set(271, 1);
this->service.Set(ServiceOption::ConfineCursor, 1);
this->mouse.SetX(position.x);
this->mouse.SetY(position.y);
SetActiveWindow(this->applicationWindow);

View file

@ -0,0 +1,21 @@
#ifndef RAGNAROK_SOURCE_CLIENT_BROWSER_BROWSERINPUTHANDOFF_H
#define RAGNAROK_SOURCE_CLIENT_BROWSER_BROWSERINPUTHANDOFF_H
#include <windows.h>
class CMouse;
struct ServiceOptions;
struct ApplicationActivation;
struct BrowserInputHandoff {
unsigned char& restoreOption;
HWND const& applicationWindow;
ServiceOptions& service;
CMouse& mouse;
ApplicationActivation& activation;
void Enter();
void Restore();
};
#endif

View file

@ -1,4 +1,4 @@
#include "Client/BrowserInterface.h"
#include "Client/Browser/BrowserInterface.h"
#include <memory>
#include <ocidl.h>
@ -6,19 +6,17 @@
// OFFSET: 0x00AB2CD0
// FUNCTION: fn_45437
bool CreateBrowserInterface(IWebBrowser2*& browser, HWND& window) {
const HRESULT result = CoCreateInstance(
CLSID_WebBrowser, nullptr, CLSCTX_INPROC_SERVER | CLSCTX_INPROC_HANDLER, IID_IWebBrowser2,
reinterpret_cast<void**>(&browser)
);
const HRESULT result =
CoCreateInstance(CLSID_WebBrowser, nullptr, CLSCTX_INPROC_SERVER | CLSCTX_INPROC_HANDLER, IID_IWebBrowser2, reinterpret_cast<void**>(&browser));
if (FAILED(result)) {
OutputDebugStringA("error : MakeWebBrowserInterface_InProc FAILED \n");
HLOCAL message = nullptr;
FormatMessageA(
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM, nullptr,
GetLastError(), 0, reinterpret_cast<char*>(&message), 0, nullptr
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM, nullptr, GetLastError(), 0,
reinterpret_cast<char*>(&message), 0, nullptr
);
// The reference locks and reports this buffer without freeing it.
OutputDebugStringA(static_cast<const char*>(LocalLock(message)));
return false;
}
@ -33,18 +31,17 @@ bool CreateBrowserInterface(IWebBrowser2*& browser, HWND& window) {
// OFFSET: 0x00AB2C10
// FUNCTION: fn_45436
bool CreateExternalBrowserInterface(IWebBrowser2*& browser, HWND& window, HWND const& host) {
const HRESULT result = CoCreateInstance(
CLSID_InternetExplorer, nullptr, CLSCTX_LOCAL_SERVER, IID_IWebBrowser2, reinterpret_cast<void**>(&browser)
);
const HRESULT result = CoCreateInstance(CLSID_InternetExplorer, nullptr, CLSCTX_LOCAL_SERVER, IID_IWebBrowser2, reinterpret_cast<void**>(&browser));
if (FAILED(result)) {
OutputDebugStringA("error : MakeWebBrowserInterface FAILED \n");
HLOCAL message = nullptr;
FormatMessageA(
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM, nullptr,
GetLastError(), 0, reinterpret_cast<char*>(&message), 0, nullptr
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM, nullptr, GetLastError(), 0,
reinterpret_cast<char*>(&message), 0, nullptr
);
OutputDebugStringA(static_cast<const char*>(LocalLock(message)));
return false;
}
@ -103,6 +100,7 @@ HRESULT AdviseBrowserEvents(IUnknown* source, IUnknown* sink, REFIID events, DWO
IConnectionPointContainer* container = nullptr;
IConnectionPoint* point = nullptr;
HRESULT result = source->QueryInterface(IID_IConnectionPointContainer, reinterpret_cast<void**>(&container));
if (SUCCEEDED(result)) {
result = container->FindConnectionPoint(events, &point);
if (SUCCEEDED(result)) {
@ -113,9 +111,11 @@ HRESULT AdviseBrowserEvents(IUnknown* source, IUnknown* sink, REFIID events, DWO
if (point) {
point->Release();
}
if (container) {
container->Release();
}
return result;
}
@ -129,6 +129,7 @@ HRESULT UnadviseBrowserEvents(IUnknown* source, REFIID events, DWORD cookie) {
IConnectionPointContainer* container = nullptr;
IConnectionPoint* point = nullptr;
HRESULT result = source->QueryInterface(IID_IConnectionPointContainer, reinterpret_cast<void**>(&container));
if (SUCCEEDED(result)) {
result = container->FindConnectionPoint(events, &point);
if (SUCCEEDED(result)) {
@ -139,8 +140,10 @@ HRESULT UnadviseBrowserEvents(IUnknown* source, REFIID events, DWORD cookie) {
if (point) {
point->Release();
}
if (container) {
container->Release();
}
return result;
}

View file

@ -0,0 +1,19 @@
#ifndef RAGNAROK_SOURCE_CLIENT_BROWSER_BROWSERINTERFACE_H
#define RAGNAROK_SOURCE_CLIENT_BROWSER_BROWSERINTERFACE_H
#include <windows.h>
#include <ole2.h>
#include <exdisp.h>
#include <string>
bool CreateBrowserInterface(IWebBrowser2*& browser, HWND& window);
bool CreateExternalBrowserInterface(IWebBrowser2*& browser, HWND& window, HWND const& host);
bool NavigateBrowser(IWebBrowser2* const& browser, HWND const& host, HWND const& title, std::string address);
HRESULT AdviseBrowserEvents(IUnknown* source, IUnknown* sink, REFIID events, DWORD* cookie);
HRESULT UnadviseBrowserEvents(IUnknown* source, REFIID events, DWORD cookie);
#endif

View file

@ -1,6 +1,6 @@
#include "Client/BrowserMessages.h"
#include "Client/BrowserRegistry.h"
#include "Client/WebBrowser.h"
#include "Client/Browser/BrowserMessages.h"
#include "Client/Browser/BrowserRegistry.h"
#include "Client/Browser/WebBrowser.h"
#include <cstdint>
@ -36,7 +36,7 @@ LRESULT BrowserMessages::Message(HWND window, UINT message, WPARAM value, LPARAM
}
break;
case WM_COMMAND:
if (static_cast<std::uint16_t>(value) == 1000 && browser) {
if (LOWORD(value) == static_cast<WORD>(BrowserCommand::Navigate) && browser) {
char address[512];
GetWindowTextA(browser->combo, address, sizeof(address));
browser->Navigate(address);

View file

@ -1,13 +1,13 @@
#ifndef RAGNAROK_SOURCE_CLIENT_BROWSERMESSAGES_H
#define RAGNAROK_SOURCE_CLIENT_BROWSERMESSAGES_H
#ifndef RAGNAROK_SOURCE_CLIENT_BROWSER_BROWSERMESSAGES_H
#define RAGNAROK_SOURCE_CLIENT_BROWSER_BROWSERMESSAGES_H
#include <windows.h>
class CWebBrowser;
struct BrowserRegistry;
// Borrowed UIWindowMgr browser registry, active browser and main HWND.
// Caller installs its native thunk; this implements the entire original body.
enum class BrowserCommand : WORD { Navigate = 1000 };
struct BrowserMessages {
BrowserRegistry& registry;
CWebBrowser*& active;

View file

@ -1,10 +1,11 @@
#include "Client/WebBrowser.h"
#include "UI/BrowserFactory.h"
#include "UI/BrowserPopupDispatch.h"
#include "Client/Browser/WebBrowser.h"
#include "Client/Browser/BrowserFactory.h"
#include "Client/Browser/BrowserPopupDispatch.h"
#include "Utility/Math/ScalarConversion.h"
#include <exdispid.h>
#include <cwchar>
#include <memory>
#include <xmmintrin.h>
// OFFSET: 0x00AB1AA0
// FUNCTION: fn_17380
@ -44,23 +45,22 @@ HRESULT STDMETHODCALLTYPE BrowserPopupDispatch::GetIDsOfNames(REFIID, LPOLESTR*,
// OFFSET: 0x00AB1880
// FUNCTION: fn_17370
HRESULT STDMETHODCALLTYPE
BrowserPopupDispatch::Invoke(DISPID id, REFIID, LCID, WORD, DISPPARAMS* args, VARIANT*, EXCEPINFO*, UINT*) {
if (id != 273) {
HRESULT STDMETHODCALLTYPE BrowserPopupDispatch::Invoke(DISPID id, REFIID, LCID, WORD, DISPPARAMS* args, VARIANT*, EXCEPINFO*, UINT*) {
if (id != DISPID_NEWWINDOW3) {
return S_OK;
}
const wchar_t* url = args->rgvarg[0].bstrVal;
// Original writes literal 11 through Cancel's by-reference boolean. Preserve
// that noncanonical true value, and write it before the factory callback.
*args->rgvarg[3].pboolVal = 11;
// STATIC: 0x01115448
// GLOBAL: gl_13426
const __m128 scale = _mm_set_ss(0.7f);
const int height = _mm_cvtt_ss2si(_mm_mul_ss(_mm_cvtsi32_ss(_mm_setzero_ps(), this->m_height), scale));
const int width = _mm_cvtt_ss2si(_mm_mul_ss(_mm_cvtsi32_ss(_mm_setzero_ps(), this->m_width), scale));
const float scale = 0.7f;
const int height = TruncateToInt(static_cast<float>(this->m_height) * scale);
const int width = TruncateToInt(static_cast<float>(this->m_width) * scale);
CWebBrowser* browser = this->m_factory.Create(width, height);
if (!browser) {
return S_OK;
}
@ -70,5 +70,6 @@ BrowserPopupDispatch::Invoke(DISPID id, REFIID, LCID, WORD, DISPPARAMS* args, VA
WideCharToMultiByte(CP_ACP, 0, url, -1, converted.get(), static_cast<int>(length), nullptr, nullptr);
converted[length] = '\0';
browser->Navigate(converted.get());
return S_OK;
}

View file

@ -1,16 +1,11 @@
#ifndef RAGNAROK_SOURCE_UI_BROWSERPOPUPDISPATCH_H
#define RAGNAROK_SOURCE_UI_BROWSERPOPUPDISPATCH_H
#ifndef RAGNAROK_SOURCE_CLIENT_BROWSER_BROWSERPOPUPDISPATCH_H
#define RAGNAROK_SOURCE_CLIENT_BROWSER_BROWSERPOPUPDISPATCH_H
// clang-format off
#include <windows.h>
#include <ole2.h>
// clang-format on
struct BrowserFactory;
// Site-owned dispatch tear-off. Identity and renderer dimensions are borrowed.
// Fixed-one reference methods match the other site tear-offs, not
// CWebEventReceiver's independently reference-counted lifetime.
class BrowserPopupDispatch final : public IDispatch {
public:
BrowserPopupDispatch(IUnknown& site, BrowserFactory& factory, const int& width, const int& height)
@ -23,16 +18,8 @@ public:
HRESULT STDMETHODCALLTYPE GetTypeInfoCount(UINT* count) override;
HRESULT STDMETHODCALLTYPE GetTypeInfo(UINT index, LCID locale, ITypeInfo** output) override;
HRESULT STDMETHODCALLTYPE GetIDsOfNames(REFIID iid, LPOLESTR* names, UINT count, LCID locale, DISPID* ids) override;
HRESULT STDMETHODCALLTYPE Invoke(
DISPID id,
REFIID iid,
LCID locale,
WORD flags,
DISPPARAMS* args,
VARIANT* result,
EXCEPINFO* error,
UINT* argumentError
) override;
HRESULT STDMETHODCALLTYPE
Invoke(DISPID id, REFIID iid, LCID locale, WORD flags, DISPPARAMS* args, VARIANT* result, EXCEPINFO* error, UINT* argumentError) override;
private:
IUnknown& m_site;

View file

@ -1,5 +1,5 @@
#include "Client/BrowserRegistry.h"
#include "Client/WebBrowser.h"
#include "Client/Browser/BrowserRegistry.h"
#include "Client/Browser/WebBrowser.h"
#include <new>
@ -28,8 +28,6 @@ void BrowserRegistry::Remove(HWND window) {
return;
}
// The reference dereferences the special browser on this miss path before
// checking it; a nonnull special owner is a caller precondition here.
if (window == this->special->host) {
delete this->special;
this->special = nullptr;

View file

@ -1,5 +1,5 @@
#ifndef RAGNAROK_SOURCE_CLIENT_BROWSERREGISTRY_H
#define RAGNAROK_SOURCE_CLIENT_BROWSERREGISTRY_H
#ifndef RAGNAROK_SOURCE_CLIENT_BROWSER_BROWSERREGISTRY_H
#define RAGNAROK_SOURCE_CLIENT_BROWSER_BROWSERREGISTRY_H
#include <map>
#include <windows.h>
@ -7,9 +7,6 @@
class CWebBrowser;
struct WebBrowserContext;
// Borrowed UIWindowMgr browser map and special-browser pointer.
// Map nodes survive browser destruction, permitting native callbacks to look up
// the original entry. The special alias is cleared before mapped destruction.
struct BrowserRegistry {
std::map<HWND, CWebBrowser*>& browsers;
CWebBrowser*& special;

View file

@ -1,5 +1,5 @@
#include "Client/BrowserInterface.h"
#include "Client/BrowserSiteAttachment.h"
#include "Client/Browser/BrowserInterface.h"
#include "Client/Browser/BrowserSiteAttachment.h"
#include <cstdint>
#include <new>
@ -7,8 +7,7 @@
// OFFSET: 0x00AB2AB0
// FUNCTION: fn_17417
bool BrowserSiteAttachment::Attach() {
this->site = new (std::nothrow)
BrowserClientSite(this->host, *this->sizing.browser, this->factory, this->renderWidth, this->renderHeight);
this->site = new (std::nothrow) BrowserClientSite(this->host, *this->sizing.browser, this->factory, this->renderWidth, this->renderHeight);
IOleObject* object;
HRESULT result = this->sizing.browser->QueryInterface(IID_IOleObject, reinterpret_cast<void**>(&object));
@ -22,6 +21,7 @@ bool BrowserSiteAttachment::Attach() {
RECT rectangle;
GetClientRect(this->host, &rectangle);
result = object->DoVerb(OLEIVERB_INPLACEACTIVATE, nullptr, this->site, 0, this->host, &rectangle);
if (SUCCEEDED(result)) {
const int width = rectangle.right - rectangle.left;
const int height = rectangle.bottom - rectangle.top;

View file

@ -0,0 +1,20 @@
#ifndef RAGNAROK_SOURCE_CLIENT_BROWSER_BROWSERSITEATTACHMENT_H
#define RAGNAROK_SOURCE_CLIENT_BROWSER_BROWSERSITEATTACHMENT_H
#include "Client/Browser/BrowserClientSite.h"
#include "Client/Browser/BrowserWindowSizing.h"
struct BrowserSiteAttachment {
BrowserWindowSizing& sizing;
HWND const& host;
BrowserClientSite*& site;
DWORD& cookie;
BrowserFactory& factory;
const int& renderWidth;
const int& renderHeight;
bool Attach();
void Detach();
};
#endif

View file

@ -1,4 +1,4 @@
#include "Client/BrowserWindowSizing.h"
#include "Client/Browser/BrowserWindowSizing.h"
// OFFSET: 0x00AB3060
// FUNCTION: fn_17421
@ -67,6 +67,7 @@ void BrowserAuxiliaryVisibility::Show(unsigned char value) {
GetClientRect(this->sizing.auxiliary, &rectangle);
top = rectangle.bottom - rectangle.top + 4;
}
this->sizing.browser->put_Top(top);
RECT rectangle;

View file

@ -1,14 +1,10 @@
#ifndef RAGNAROK_SOURCE_CLIENT_BROWSERWINDOWSIZING_H
#define RAGNAROK_SOURCE_CLIENT_BROWSERWINDOWSIZING_H
#ifndef RAGNAROK_SOURCE_CLIENT_BROWSER_BROWSERWINDOWSIZING_H
#define RAGNAROK_SOURCE_CLIENT_BROWSER_BROWSERWINDOWSIZING_H
// clang-format off
#include <windows.h>
#include <ole2.h>
#include <exdisp.h>
// clang-format on
// Borrowed IWebBrowser2 and original browser-owner dimensions. COM lifetime,
// activation and navigation are separate; this view owns no references.
struct BrowserWindowSizing {
IWebBrowser2* const& browser;
const int& screenWidth;
@ -18,13 +14,10 @@ struct BrowserWindowSizing {
int& width;
int& height;
// Exact screen dimensions are reduced by one, then optional auxiliary
// client height plus four is removed. Native setter errors are ignored.
void Resize(int requestedWidth, int requestedHeight);
void Refresh();
};
// Browser host-site presence, host HWND and auxiliary-visible byte.
struct BrowserAuxiliaryVisibility {
BrowserWindowSizing& sizing;
const bool& hasSite;

View file

@ -1,31 +1,27 @@
#include "Client/BrowserClose.h"
#include "Client/BrowserCreation.h"
#include "Client/BrowserFrame.h"
#include "Client/BrowserInputHandoff.h"
#include "Client/WebBrowser.h"
#include "Client/WebEventReceiver.h"
#include "Client/Browser/BrowserClose.h"
#include "Client/Browser/BrowserCreation.h"
#include "Client/Browser/BrowserFrame.h"
#include "Client/Browser/BrowserInputHandoff.h"
#include "Client/Browser/WebBrowser.h"
#include "Client/Browser/WebEventReceiver.h"
#include <new>
#include <utility>
namespace {
BrowserWindowSizing Sizing(CWebBrowser& owner) {
return {owner.browser, owner.screenWidth, owner.screenHeight, owner.rebar,
owner.auxiliaryVisible, owner.width, owner.height};
return {owner.browser, owner.screenWidth, owner.screenHeight, owner.rebar, owner.auxiliaryVisible, owner.width, owner.height};
}
}
// OFFSET: 0x00AB1DE0
// FUNCTION: fn_17409
CWebBrowser::CWebBrowser(WebBrowserContext& context)
: browser(nullptr), externalEvents(nullptr), site(nullptr), host(nullptr), browserWindow(nullptr), cursorState(0),
auxiliaryVisible(0), screenWidth(GetSystemMetrics(SM_CXSCREEN)), screenHeight(GetSystemMetrics(SM_CYSCREEN)),
cookie(0), rebar(nullptr), combo(nullptr), barHeight(0), width(0), height(0), restoreOption(0),
context(&context) {
: browser(nullptr), externalEvents(nullptr), site(nullptr), host(nullptr), browserWindow(nullptr), cursorState(0), auxiliaryVisible(0),
screenWidth(GetSystemMetrics(SM_CXSCREEN)), screenHeight(GetSystemMetrics(SM_CYSCREEN)), cookie(0), rebar(nullptr), combo(nullptr), barHeight(0),
width(0), height(0), restoreOption(0), context(&context) {
OutputDebugStringA("CWebBrowser() \n");
BrowserInputHandoff handoff{
this->restoreOption, context.applicationWindow, context.service, context.mouse, context.activation
};
BrowserInputHandoff handoff{this->restoreOption, context.applicationWindow, context.service, context.mouse, context.activation};
handoff.Enter();
}
@ -34,10 +30,7 @@ CWebBrowser::CWebBrowser(WebBrowserContext& context)
CWebBrowser::~CWebBrowser() {
OutputDebugStringA("~CWebBrowser() \n");
auto& dependencies = *this->context;
BrowserInputHandoff handoff{
this->restoreOption, dependencies.applicationWindow, dependencies.service, dependencies.mouse,
dependencies.activation
};
BrowserInputHandoff handoff{this->restoreOption, dependencies.applicationWindow, dependencies.service, dependencies.mouse, dependencies.activation};
handoff.Restore();
this->Close();
}
@ -49,24 +42,13 @@ bool CWebBrowser::Create(int requestedWidth, int requestedHeight) {
auto sizing = Sizing(*this);
BrowserHostWindow window{this->host, this->browserWindow, dependencies.title, dependencies.hostProcedure};
BrowserSiteAttachment attachment{
sizing,
this->host,
this->site,
this->cookie,
dependencies.popupFactory,
dependencies.renderWidth,
dependencies.renderHeight
sizing, this->host, this->site, this->cookie, dependencies.popupFactory, dependencies.renderWidth, dependencies.renderHeight
};
BrowserAddressBar addressBar{
this->host,
this->rebar,
this->combo,
this->barHeight,
this->auxiliaryVisible,
dependencies.previousEditProcedure,
dependencies.editProcedure
this->host, this->rebar, this->combo, this->barHeight, this->auxiliaryVisible, dependencies.previousEditProcedure, dependencies.editProcedure
};
BrowserCreation creation{this->browser, this->browserWindow, window, attachment, addressBar};
return creation.Create(dependencies.applicationWindow, dependencies.instance, requestedWidth, requestedHeight);
}
@ -76,17 +58,11 @@ bool CWebBrowser::Close() {
auto& dependencies = *this->context;
auto sizing = Sizing(*this);
BrowserSiteAttachment attachment{
sizing,
this->host,
this->site,
this->cookie,
dependencies.popupFactory,
dependencies.renderWidth,
dependencies.renderHeight
sizing, this->host, this->site, this->cookie, dependencies.popupFactory, dependencies.renderWidth, dependencies.renderHeight
};
BrowserClose operation{attachment, this->browser, this->externalEvents,
this->host, this->browserWindow, dependencies.applicationWindow,
BrowserClose operation{attachment, this->browser, this->externalEvents, this->host, this->browserWindow, dependencies.applicationWindow,
this->cursorState, dependencies.mouse};
return operation.Close();
}
@ -96,6 +72,7 @@ bool CWebBrowser::AttachExternalEvents(BrowserRegistry& registry) {
auto* receiver = new (std::nothrow) CWebEventReceiver(registry);
this->externalEvents = receiver;
receiver->AddRef();
return receiver->Register(this->browser, this->host);
}
@ -111,9 +88,7 @@ void CWebBrowser::Resize(int requestedWidth, int requestedHeight) {
void CWebBrowser::Poll() {
auto& dependencies = *this->context;
auto sizing = Sizing(*this);
BrowserCursor cursor{
this->cursorState, dependencies.mouse, dependencies.renderSystem, dependencies.applicationWindow
};
BrowserCursor cursor{this->cursorState, dependencies.mouse, dependencies.renderSystem, dependencies.applicationWindow};
const bool hasExternalEvents = this->externalEvents != nullptr;
BrowserFrame frame{sizing, cursor, this->host, this->browserWindow, hasExternalEvents};
frame.Poll();
@ -129,7 +104,7 @@ bool CWebBrowser::Navigate(std::string address) {
// FUNCTION: fn_17422
void CWebBrowser::ShowAuxiliary(unsigned char value) {
auto sizing = Sizing(*this);
// The original gate is external-event receiver presence at +4, not site +8.
const bool hasExternalEvents = this->externalEvents != nullptr;
BrowserAuxiliaryVisibility visibility{sizing, hasExternalEvents, this->host, this->auxiliaryVisible};
visibility.Show(value);

View file

@ -1,7 +1,7 @@
#ifndef RAGNAROK_SOURCE_CLIENT_WEBBROWSER_H
#define RAGNAROK_SOURCE_CLIENT_WEBBROWSER_H
#ifndef RAGNAROK_SOURCE_CLIENT_BROWSER_WEBBROWSER_H
#define RAGNAROK_SOURCE_CLIENT_BROWSER_WEBBROWSER_H
#include "Client/BrowserInterface.h"
#include "Client/Browser/BrowserInterface.h"
#include <cstddef>
@ -11,13 +11,8 @@ class CRenderSystemBase;
struct ServiceOptions;
struct BrowserRegistry;
struct BrowserFactory;
namespace client {
struct ApplicationActivation;
}
struct ApplicationActivation;
// Borrowed application globals, concrete popup factory and native procedures.
// All must outlive the browser. Renderer dimensions retain their original
// separately owned globals rather than querying virtuals during popup dispatch.
struct WebBrowserContext {
HWND const& applicationWindow;
HINSTANCE const& instance;
@ -25,7 +20,7 @@ struct WebBrowserContext {
CMouse& mouse;
CRenderSystemBase& renderSystem;
ServiceOptions& service;
client::ApplicationActivation& activation;
ApplicationActivation& activation;
BrowserFactory& popupFactory;
const int& renderWidth;
const int& renderHeight;
@ -34,8 +29,6 @@ struct WebBrowserContext {
WNDPROC& previousEditProcedure;
};
// Original nonpolymorphic 64-byte CWebBrowser prefix. Context follows it as a
// host dependency view; no original executable addresses are used at runtime.
class CWebBrowser {
public:
explicit CWebBrowser(WebBrowserContext& context);

View file

@ -1,13 +1,15 @@
#include "Client/BrowserRegistry.h"
#include "Client/WebEventReceiver.h"
#include "Client/Browser/BrowserRegistry.h"
#include "Client/Browser/WebEventReceiver.h"
#include <exdispid.h>
#include <mshtmdid.h>
#include <mshtml.h>
// OFFSET: 0x00AB3710
// FUNCTION: fn_17424
CWebEventReceiver::CWebEventReceiver(BrowserRegistry& registry)
: m_references(0), m_browser(nullptr), m_browserCookie(0), m_document(nullptr), m_documentCookie(0),
m_host(nullptr), m_registry(registry) {
: m_references(0), m_browser(nullptr), m_browserCookie(0), m_document(nullptr), m_documentCookie(0), m_host(nullptr), m_registry(registry) {
OutputDebugStringA("CWebEventReceiver() \n");
}
@ -22,6 +24,7 @@ bool CWebEventReceiver::Register(IWebBrowser2* browser, HWND host) {
this->m_browser = browser;
this->m_host = host;
this->m_browser->AddRef();
return SUCCEEDED(AdviseBrowserEvents(this->m_browser, this, DIID_DWebBrowserEvents2, &this->m_browserCookie));
}
@ -98,20 +101,17 @@ HRESULT CWebEventReceiver::Disconnect() {
// OFFSET: 0x00AB3B20
// FUNCTION: fn_17433
HRESULT STDMETHODCALLTYPE
CWebEventReceiver::Invoke(DISPID id, REFIID, LCID, WORD, DISPPARAMS* args, VARIANT*, EXCEPINFO*, UINT*) {
if (id == 253) {
HRESULT STDMETHODCALLTYPE CWebEventReceiver::Invoke(DISPID id, REFIID, LCID, WORD, DISPPARAMS* args, VARIANT*, EXCEPINFO*, UINT*) {
if (id == DISPID_ONQUIT) {
return this->Disconnect();
}
if (id == 259) {
if (id == DISPID_DOCUMENTCOMPLETE) {
IDispatch* browserIdentity = nullptr;
if (FAILED(this->m_browser->QueryInterface(IID_IDispatch, reinterpret_cast<void**>(&browserIdentity)))) {
return S_OK;
}
// DocumentComplete's pDisp is the second reverse-order VARIANT. The
// reference retains browserIdentity on an identity mismatch.
if (args->rgvarg[1].pdispVal != browserIdentity) {
return S_OK;
}
@ -125,7 +125,7 @@ CWebEventReceiver::Invoke(DISPID id, REFIID, LCID, WORD, DISPPARAMS* args, VARIA
return S_OK;
}
if (id != -602 && id != static_cast<DISPID>(0x8001000A) && id != 1023) {
if (id != DISPID_HTMLDOCUMENTEVENTS2_ONKEYDOWN && id != DISPID_HTMLDOCUMENTEVENTS2_ONHELP && id != DISPID_HTMLDOCUMENTEVENTS2_ONCONTEXTMENU) {
return S_OK;
}
@ -134,26 +134,26 @@ CWebEventReceiver::Invoke(DISPID id, REFIID, LCID, WORD, DISPPARAMS* args, VARIA
return S_OK;
}
if (id == -602) {
if (id == DISPID_HTMLDOCUMENTEVENTS2_ONKEYDOWN) {
long key = 0;
if (FAILED(event->get_keyCode(&key))) {
return S_OK;
}
switch (key) {
case 18:
case 112:
case 114:
case 115:
case 122:
case VK_MENU:
case VK_F1:
case VK_F3:
case VK_F4:
case VK_F11:
break;
default:
// Deliberately retained reference on the original non-filtered branch.
return S_OK;
}
}
if (id != 1023) {
if (id != DISPID_HTMLDOCUMENTEVENTS2_ONCONTEXTMENU) {
event->put_keyCode(0);
}
@ -163,5 +163,6 @@ CWebEventReceiver::Invoke(DISPID id, REFIID, LCID, WORD, DISPPARAMS* args, VARIA
cancelled.boolVal = VARIANT_FALSE;
event->put_returnValue(cancelled);
event->Release();
return id == -602 ? S_FALSE : S_OK;
return id == DISPID_HTMLDOCUMENTEVENTS2_ONKEYDOWN ? S_FALSE : S_OK;
}

View file

@ -1,13 +1,10 @@
#ifndef RAGNAROK_SOURCE_CLIENT_WEBEVENTRECEIVER_H
#define RAGNAROK_SOURCE_CLIENT_WEBEVENTRECEIVER_H
#ifndef RAGNAROK_SOURCE_CLIENT_BROWSER_WEBEVENTRECEIVER_H
#define RAGNAROK_SOURCE_CLIENT_BROWSER_WEBEVENTRECEIVER_H
#include "Client/BrowserInterface.h"
#include "Client/Browser/BrowserInterface.h"
struct BrowserRegistry;
// Original receiver starts with zero references. Caller acquires its owning
// reference before registration. Destruction only reports diagnostics; explicit
// Disconnect performs COM and registry teardown, not the destructor.
class CWebEventReceiver final : public IDispatch {
public:
explicit CWebEventReceiver(BrowserRegistry& registry);
@ -20,16 +17,8 @@ public:
HRESULT STDMETHODCALLTYPE GetTypeInfoCount(UINT* count) override;
HRESULT STDMETHODCALLTYPE GetTypeInfo(UINT index, LCID locale, ITypeInfo** output) override;
HRESULT STDMETHODCALLTYPE GetIDsOfNames(REFIID iid, LPOLESTR* names, UINT count, LCID locale, DISPID* ids) override;
HRESULT STDMETHODCALLTYPE Invoke(
DISPID id,
REFIID iid,
LCID locale,
WORD flags,
DISPPARAMS* args,
VARIANT* result,
EXCEPINFO* error,
UINT* argumentError
) override;
HRESULT STDMETHODCALLTYPE
Invoke(DISPID id, REFIID iid, LCID locale, WORD flags, DISPPARAMS* args, VARIANT* result, EXCEPINFO* error, UINT* argumentError) override;
private:
~CWebEventReceiver();

View file

@ -1,23 +0,0 @@
#ifndef RAGNAROK_SOURCE_CLIENT_BROWSERADDRESSBAR_H
#define RAGNAROK_SOURCE_CLIENT_BROWSERADDRESSBAR_H
#include <windows.h>
// Borrowed host, rebar, combo, height, visible, and shared
// previous-edit-procedure global. Caller initializes common controls and supplies
// the actual BrowserAddressEdit thunk. Native verification requires v6 controls
// for the original 100-byte x86 band; startup activation policy is not recovered.
// Failed creation retains native children; normal host destruction owns them.
struct BrowserAddressBar {
HWND const& host;
HWND& rebar;
HWND& combo;
int& height;
const unsigned char& visible;
WNDPROC& previous;
WNDPROC procedure;
bool Create(int width, int height);
};
#endif

View file

@ -1,16 +0,0 @@
#ifndef RAGNAROK_SOURCE_CLIENT_BROWSERADDRESSEDIT_H
#define RAGNAROK_SOURCE_CLIENT_BROWSERADDRESSEDIT_H
#include <windows.h>
// Borrowed original subclass procedure and active browser-host selection.
// Null activeHost denotes no active CWebBrowser, not a null HWND field inside
// an otherwise active object.
struct BrowserAddressEdit {
WNDPROC const& previous;
HWND const* const& activeHost;
LRESULT Message(HWND window, UINT message, WPARAM value, LPARAM flags);
};
#endif

View file

@ -1,24 +0,0 @@
#ifndef RAGNAROK_SOURCE_CLIENT_BROWSERCLOSE_H
#define RAGNAROK_SOURCE_CLIENT_BROWSERCLOSE_H
#include "Client/BrowserSiteAttachment.h"
class CMouse;
// Borrowed original browser fields. External events use a separate COM reference
// independent of the client-site dispatch dependency. Auxiliary HWNDs and
// cookie remain untouched even after their host destroys the native children.
struct BrowserClose {
BrowserSiteAttachment& attachment;
IWebBrowser2*& browser;
IUnknown*& externalEvents;
HWND& host;
HWND const& browserWindow;
HWND const& applicationWindow;
int& cursorState;
CMouse& mouse;
bool Close();
};
#endif

View file

@ -1,21 +0,0 @@
#ifndef RAGNAROK_SOURCE_CLIENT_BROWSERCREATION_H
#define RAGNAROK_SOURCE_CLIENT_BROWSERCREATION_H
#include "Client/BrowserAddressBar.h"
#include "Client/BrowserHostWindow.h"
#include "Client/BrowserSiteAttachment.h"
// Views must refer to the same CWebBrowser fields. Caller supplies the complete
// host procedure, edit subclass and site event dependency. No rollback on error:
// browser, host, site and native children remain published at their original steps.
struct BrowserCreation {
IWebBrowser2*& browser;
HWND& browserWindow;
BrowserHostWindow& window;
BrowserSiteAttachment& attachment;
BrowserAddressBar& addressBar;
bool Create(HWND parent, HINSTANCE instance, int width, int height);
};
#endif

View file

@ -1,21 +0,0 @@
#ifndef RAGNAROK_SOURCE_CLIENT_BROWSERCURSOR_H
#define RAGNAROK_SOURCE_CLIENT_BROWSERCURSOR_H
#include <windows.h>
class CMouse;
class CRenderSystemBase;
// Borrowed CWebBrowser cursor state and the actual global mouse/render
// owners. ShowCursor receives the full integer, not a normalized boolean.
struct BrowserCursor {
int& state;
CMouse& mouse;
CRenderSystemBase& renderSystem;
HWND const& applicationWindow;
void Set(int value);
void Poll();
};
#endif

View file

@ -1,20 +0,0 @@
#ifndef RAGNAROK_SOURCE_CLIENT_BROWSERFRAME_H
#define RAGNAROK_SOURCE_CLIENT_BROWSERFRAME_H
#include "Client/BrowserCursor.h"
#include "Client/BrowserWindowSizing.h"
// Borrowed original browser owner. Presence means the separate external event
// receiver is attached, not merely that an OLE client site exists.
struct BrowserFrame {
BrowserWindowSizing& sizing;
BrowserCursor& cursor;
HWND const& host;
HWND const& browserWindow;
const bool& hasExternalEvents;
void Normalize();
void Poll();
};
#endif

View file

@ -1,18 +0,0 @@
#ifndef RAGNAROK_SOURCE_CLIENT_BROWSERHOSTWINDOW_H
#define RAGNAROK_SOURCE_CLIENT_BROWSERHOSTWINDOW_H
#include <windows.h>
// Borrowed CWebBrowser host and browser HWND, application
// title and complete browser window procedure. This operation does not replace
// that procedure with DefWindowProc or invent the browser host-site lifecycle.
struct BrowserHostWindow {
HWND& host;
HWND const& browser;
const char* const& title;
WNDPROC procedure;
bool Create(HWND parent, HINSTANCE instance, int width, int height);
};
#endif

View file

@ -1,25 +0,0 @@
#ifndef RAGNAROK_SOURCE_CLIENT_BROWSERINPUTHANDOFF_H
#define RAGNAROK_SOURCE_CLIENT_BROWSERINPUTHANDOFF_H
#include <windows.h>
class CMouse;
struct ServiceOptions;
namespace client {
struct ApplicationActivation;
}
// Borrowed original CWebBrowser service-option latch, main HWND and global
// input owners. Restoration retains the latch; it is not a one-shot operation.
struct BrowserInputHandoff {
unsigned char& restoreOption;
HWND const& applicationWindow;
ServiceOptions& service;
CMouse& mouse;
client::ApplicationActivation& activation;
void Enter();
void Restore();
};
#endif

View file

@ -1,30 +0,0 @@
#ifndef RAGNAROK_SOURCE_CLIENT_BROWSERINTERFACE_H
#define RAGNAROK_SOURCE_CLIENT_BROWSERINTERFACE_H
// clang-format off
#include <windows.h>
#include <ole2.h>
#include <exdisp.h>
// clang-format on
#include <string>
// Caller supplies the original owner fields and controls COM initialization
// and release. Successful creation publishes HWND only when browser is nonnull;
// get_HWND failure does not change the creation result.
bool CreateBrowserInterface(IWebBrowser2*& browser, HWND& window);
// Distinct original local-server route; never falls back to the in-process
// control. Success reparents its HWND and clears Top, Left and StatusBar.
bool CreateExternalBrowserInterface(IWebBrowser2*& browser, HWND& window, HWND const& host);
// Navigation's four optional arguments alias one VT_EMPTY VARIANT. Host show,
// browser visibility and title publication occur even when Navigate fails.
bool NavigateBrowser(IWebBrowser2* const& browser, HWND const& host, HWND const& title, std::string address);
// Connection-point helpers retain native HRESULTs; cookie writes belong to
// Advise. Release the connection point before its container on every path.
HRESULT AdviseBrowserEvents(IUnknown* source, IUnknown* sink, REFIID events, DWORD* cookie);
HRESULT UnadviseBrowserEvents(IUnknown* source, REFIID events, DWORD cookie);
#endif

View file

@ -1,23 +0,0 @@
#ifndef RAGNAROK_SOURCE_CLIENT_BROWSERSITEATTACHMENT_H
#define RAGNAROK_SOURCE_CLIENT_BROWSERSITEATTACHMENT_H
#include "Client/BrowserClientSite.h"
#include "Client/BrowserWindowSizing.h"
// Borrowed original owner fields, real popup factory and renderer dimensions.
// Site publication precedes COM work and remains on failure. Detach destroys the
// site even when QueryInterface fails; it does not clear the COM client site.
struct BrowserSiteAttachment {
BrowserWindowSizing& sizing;
HWND const& host;
BrowserClientSite*& site;
DWORD& cookie;
BrowserFactory& factory;
const int& renderWidth;
const int& renderHeight;
bool Attach();
void Detach();
};
#endif

View file

@ -1,17 +1,14 @@
#include "Client/ClientOptions.h"
#include <bit>
// OFFSET: 0x0091BE20
// FUNCTION: fn_12610
int ClientOptions::Get(int id) const {
return std::bit_cast<int>(static_cast<std::uint32_t>(this->values.Get(id)));
return static_cast<int>(this->values.Get(id));
}
// OFFSET: 0x005E7970
// FUNCTION: fn_03937
void ClientOptions::Set(int id, int value, int extra) {
const std::uint64_t bits =
static_cast<std::uint32_t>(value) | (static_cast<std::uint64_t>(static_cast<std::uint32_t>(extra)) << 32);
this->values.Set(id, std::bit_cast<std::int64_t>(bits));
const std::uint64_t bits = static_cast<std::uint32_t>(value) | (static_cast<std::uint64_t>(extra) << 32);
this->values.Set(id, static_cast<std::int64_t>(bits));
}

View file

@ -3,7 +3,6 @@
#include "Contents/InstantVar.h"
// Low/high-word client operations on its CInstantVar at +0x7FA8.
struct ClientOptions {
CInstantVar& values;
int Get(int id) const;

View file

@ -1,12 +0,0 @@
#ifndef RAGNAROK_SOURCE_CLIENT_ERRORDIALOG_H
#define RAGNAROK_SOURCE_CLIENT_ERRORDIALOG_H
#include <windows.h>
class CRenderSystemBase;
// Obtained through the render-system owner.
// Keep the real owner dependency explicit until its lifecycle is reconstructed.
int ShowErrorDialog(CRenderSystemBase* renderSystem, const char* text, UINT type);
#endif

View file

@ -1,6 +1,6 @@
#include "Client/ImeInput.h"
#include "Client/TraditionalKeyInput.h"
#include "Utility/LanguageCharset.h"
#include "Client/Input/ImeInput.h"
#include "Client/Input/TraditionalKeyInput.h"
#include "Utility/Text/LanguageCharset.h"
#include <algorithm>
#include <cstring>
@ -10,6 +10,7 @@
// FUNCTION: fn_17793
LRESULT ImeInput::Message(HWND, UINT message, WPARAM value, LPARAM flags, std::uint8_t& handled) {
const auto options = static_cast<std::uint16_t>(flags);
switch (message) {
case WM_INPUTLANGCHANGE:
this->language = options;
@ -48,13 +49,13 @@ LRESULT ImeInput::Message(HWND, UINT message, WPARAM value, LPARAM flags, std::u
if (context) {
WCHAR wide[256];
char converted[256];
const auto bytes =
static_cast<std::uint32_t>(ImmGetCompositionStringW(context, GCS_RESULTSTR, wide, sizeof(wide)));
const unsigned size =
WideCharToMultiByte(this->codePage, 0, wide, bytes >> 1, converted, sizeof(converted), nullptr, nullptr);
const auto bytes = static_cast<std::uint32_t>(ImmGetCompositionStringW(context, GCS_RESULTSTR, wide, sizeof(wide)));
const unsigned size = WideCharToMultiByte(this->codePage, 0, wide, bytes >> 1, converted, sizeof(converted), nullptr, nullptr);
if (size >= sizeof(converted)) {
__fastfail(8);
__fastfail(FAST_FAIL_RANGE_CHECK_FAILURE);
}
converted[size] = 0;
ImmReleaseContext(this->input.window, context);
this->input.Insert(converted);
@ -78,6 +79,7 @@ LRESULT ImeInput::Message(HWND, UINT message, WPARAM value, LPARAM flags, std::u
} else {
this->input.compositionState = 0;
}
ImmReleaseContext(this->input.window, context);
} else {
this->input.compositionState = 0;
@ -109,5 +111,6 @@ const char* ImeInput::Candidate(int index) const {
const WCHAR* text = reinterpret_cast<const WCHAR*>(bytes + this->candidateList->dwOffset[index]);
const unsigned size = WideCharToMultiByte(this->codePage, 0, text, -1, output, sizeof(output), nullptr, nullptr);
output[std::min<unsigned>(size, 255)] = 0;
return output;
}

View file

@ -1,7 +1,7 @@
#ifndef RAGNAROK_SOURCE_CLIENT_IMEINPUT_H
#define RAGNAROK_SOURCE_CLIENT_IMEINPUT_H
#ifndef RAGNAROK_SOURCE_CLIENT_INPUT_IMEINPUT_H
#define RAGNAROK_SOURCE_CLIENT_INPUT_IMEINPUT_H
#include "Client/TextInputBuffer.h"
#include "Client/Input/TextInputBuffer.h"
#include <cstdint>
#include <imm.h>
@ -9,8 +9,6 @@
struct TraditionalKeyInput;
// Borrowed CLanguage fields, with optional concrete CLanguageTC key view.
// Base/TH/ARB composition hooks are established empty entries.
struct ImeInput {
TextInputBuffer& input;
std::uint16_t& language;
@ -24,11 +22,8 @@ struct ImeInput {
int& compositionCursor;
TraditionalKeyInput* traditional;
// Original ignores the passed HWND and uses the global main-window handle
// borrowed by input. Flags are truncated to the low WORD.
LRESULT Message(HWND unused, UINT message, WPARAM value, LPARAM flags, std::uint8_t& handled);
// Shared 256-byte output; later successful lookups overwrite prior strings.
// Original checks index < count only (no negative-index guard).
const char* Candidate(int index) const;
};

View file

@ -1,5 +1,5 @@
#include "Client/InputCharset.h"
#include "Utility/LanguageCharset.h"
#include "Client/Input/InputCharset.h"
#include "Utility/Text/LanguageCharset.h"
#include <cstdio>

View file

@ -1,5 +1,5 @@
#ifndef RAGNAROK_SOURCE_CLIENT_INPUTCHARSET_H
#define RAGNAROK_SOURCE_CLIENT_INPUTCHARSET_H
#ifndef RAGNAROK_SOURCE_CLIENT_INPUT_INPUTCHARSET_H
#define RAGNAROK_SOURCE_CLIENT_INPUT_INPUTCHARSET_H
#include <cstdint>
@ -9,7 +9,7 @@ struct InputCharset {
const std::uint16_t& alternateLanguage;
const char* Prefix(bool alternate) const;
// Shared selection used by composition refresh/language-change handling.
unsigned CodePage(unsigned fallback) const;
};

View file

@ -1,11 +1,8 @@
#include "Client/Mouse.h"
#include "Render/DCSurface.h"
#include "Client/Input/Mouse.h"
#include "Render/DeviceContext/DCSurface.h"
#include <bit>
#include <windows.h>
// clang-format off
#include <mmsystem.h>
// clang-format on
#include <timeapi.h>
// OFFSET: 0x006370C0
// FUNCTION: fn_04724
@ -20,11 +17,12 @@ void CMouse::Update() {
return;
}
this->deltaX = std::bit_cast<int>(static_cast<std::uint32_t>(this->pendingX) - static_cast<std::uint32_t>(this->x));
this->deltaY = std::bit_cast<int>(static_cast<std::uint32_t>(this->pendingY) - static_cast<std::uint32_t>(this->y));
this->deltaX = this->pendingX - this->x;
this->deltaY = this->pendingY - this->y;
this->x = this->pendingX;
this->y = this->pendingY;
const std::uint32_t now = timeGetTime();
for (unsigned index = 0; index < 2; ++index) {
if (this->deltaX != 0 || this->deltaY != 0) {
this->pressTicks[index] = now - this->doubleClickTime;
@ -71,6 +69,7 @@ int CMouse::Center() {
const int halfHeight = static_cast<int>(GetRenderSystemHolder()->Height()) / 2;
this->pendingY = halfHeight;
this->y = halfHeight;
return halfHeight;
}
@ -120,7 +119,7 @@ void CMouse::Message(CMouse& global, HWND mainWindow, HWND source, UINT message,
this->pendingButtons[1] = 0;
break;
case WM_MOUSEWHEEL:
this->pendingWheel = std::bit_cast<std::int16_t>(static_cast<std::uint16_t>(keys >> 16));
this->pendingWheel = GET_WHEEL_DELTA_WPARAM(keys);
break;
}
}

View file

@ -1,11 +1,9 @@
#ifndef RAGNAROK_SOURCE_CLIENT_MOUSE_H
#define RAGNAROK_SOURCE_CLIENT_MOUSE_H
#ifndef RAGNAROK_SOURCE_CLIENT_INPUT_MOUSE_H
#define RAGNAROK_SOURCE_CLIENT_INPUT_MOUSE_H
#include <cstdint>
#include <windows.h>
// RTTI CMouse. Defaults below are the original
// static-data initializer, not evidence of a separate allocating constructor.
class CMouse {
public:
virtual ~CMouse();
@ -14,9 +12,7 @@ public:
int Center();
void SetX(int value);
void SetY(int value);
// Message position comes from GetCursorPos/mainWindow, not lParam or source.
// The original resets the global mouse on first message; pass that owner
// separately so non-global instances retain the same distinction.
void Message(CMouse& global, HWND mainWindow, HWND source, UINT message, WPARAM keys, LPARAM unused);
/* 0004 */ int x = 0;

View file

@ -1,9 +1,8 @@
#include "Client/TextInputBuffer.h"
#include "UI/UIWindow.h"
#include "UI/WindowManagerWindows.h"
#include "Client/Input/TextInputBuffer.h"
#include "UI/Window/UIWindow.h"
#include "UI/Window/WindowManagerWindows.h"
#include <algorithm>
#include <bit>
#include <cstdint>
#include <cstring>
#include <imm.h>
@ -14,7 +13,7 @@ void TextInputBuffer::CancelComposition() {
HIMC context = ImmGetContext(this->window);
if (context) {
ImmNotifyIME(context, 0x15, 4, 0);
ImmNotifyIME(context, NI_COMPOSITIONSTR, CPS_CANCEL, 0);
ImmReleaseContext(this->window, context);
}
@ -34,8 +33,7 @@ void TextInputBuffer::DeleteSelection() {
}
const int begin = std::min(this->cursor, this->anchor);
const auto length =
static_cast<std::uint32_t>(std::max(this->cursor, this->anchor)) - static_cast<std::uint32_t>(begin);
const int length = std::max(this->cursor, this->anchor) - begin;
this->text.erase(static_cast<std::size_t>(begin), length);
this->cursor = begin;
this->anchor = begin;
@ -50,9 +48,7 @@ void TextInputBuffer::DeleteSelection() {
void TextInputBuffer::Insert(const char* value) {
this->DeleteSelection();
this->text.insert(static_cast<std::size_t>(this->cursor), value, std::strlen(value));
this->anchor = std::bit_cast<std::int32_t>(
static_cast<std::uint32_t>(std::strlen(value)) + static_cast<std::uint32_t>(this->cursor)
);
this->anchor = this->cursor + static_cast<int>(std::strlen(value));
this->cursor = this->anchor;
if (this->suggestionsEnabled && this->chatOpen && this->chatInput && this->focused == this->chatInput) {
@ -77,9 +73,7 @@ void TextInputBuffer::CopyDisplayText(std::string& output) const {
}
if (!this->candidate.empty()) {
output.insert(
static_cast<std::size_t>(this->cursor), this->candidate.c_str(), std::strlen(this->candidate.c_str())
);
output.insert(static_cast<std::size_t>(this->cursor), this->candidate.c_str(), std::strlen(this->candidate.c_str()));
}
}
@ -102,8 +96,7 @@ void TextInputBuffer::RefreshComposition(unsigned codePage) {
WCHAR wide[256];
char converted[256];
const auto bytes = static_cast<std::uint32_t>(ImmGetCompositionStringW(context, GCS_COMPSTR, wide, sizeof(wide)));
const unsigned size =
WideCharToMultiByte(codePage, 0, wide, bytes >> 1, converted, sizeof(converted), nullptr, nullptr);
const unsigned size = WideCharToMultiByte(codePage, 0, wide, bytes >> 1, converted, sizeof(converted), nullptr, nullptr);
ImmReleaseContext(this->window, context);
this->candidate.assign(converted, size);
@ -122,8 +115,7 @@ void TextInputBuffer::RefreshComposition(unsigned codePage) {
// OFFSET: 0x00ACD5C0
// FUNCTION: fn_17765
void TextInputBuffer::CopySelection(bool password) {
const auto difference = static_cast<std::uint32_t>(this->cursor) - static_cast<std::uint32_t>(this->anchor);
const auto length = std::bit_cast<std::int32_t>(difference) < 0 ? 0u - difference : difference;
const int length = std::max(this->cursor, this->anchor) - std::min(this->cursor, this->anchor);
if (!length || !OpenClipboard(this->window)) {
return;
}
@ -138,6 +130,7 @@ void TextInputBuffer::CopySelection(bool password) {
} else {
std::memcpy(data, this->text.data() + begin, length);
}
data[length] = 0;
GlobalUnWire(memory);
EmptyClipboard();
@ -200,7 +193,7 @@ void TextInputBuffer::MoveForward(unsigned codePage) {
const auto length = static_cast<std::uint32_t>(this->text.size());
const auto position = static_cast<std::uint32_t>(this->cursor);
if (position > length) {
this->cursor = std::bit_cast<int>(length);
this->cursor = static_cast<int>(length);
} else if (position < length) {
const char* begin = this->text.c_str();
this->cursor = static_cast<int>(CharNextExA(static_cast<WORD>(codePage), begin + position, 0) - begin);
@ -214,6 +207,7 @@ void TextInputBuffer::Character(unsigned value, LPARAM, unsigned codePage) {
if (this->cursor == this->anchor) {
this->MoveBack(codePage);
}
this->DeleteSelection();
return;
}
@ -222,8 +216,6 @@ void TextInputBuffer::Character(unsigned value, LPARAM, unsigned codePage) {
return;
}
// Keep the original little-endian DWORD representation and stop at its first
// zero byte; valid WM_CHAR payloads provide that terminator within the word.
char bytes[sizeof(value)];
std::memcpy(bytes, &value, sizeof(value));
this->Insert(bytes);
@ -232,13 +224,7 @@ void TextInputBuffer::Character(unsigned value, LPARAM, unsigned codePage) {
// OFFSET: 0x00ACE880
// FUNCTION: fn_17792
void TextInputBuffer::KeyDown(
unsigned key,
LPARAM,
unsigned codePage,
bool password,
UIWindow* blockedPasteFocus,
WindowManagerWindows& windows,
UIWindow* const& chatArrows
unsigned key, LPARAM, unsigned codePage, bool password, UIWindow* blockedPasteFocus, WindowManagerWindows& windows, UIWindow* const& chatArrows
) {
const auto cut = [&]() {
this->CopySelection(password);
@ -266,6 +252,7 @@ void TextInputBuffer::KeyDown(
cut();
break;
}
return;
}
@ -285,6 +272,7 @@ void TextInputBuffer::KeyDown(
this->cursor = std::max(static_cast<int>(this->text.size()), 0);
break;
}
return;
}
@ -305,6 +293,7 @@ void TextInputBuffer::KeyDown(
} else {
this->MoveForward(codePage);
}
this->anchor = this->cursor;
}
break;

View file

@ -0,0 +1,57 @@
#ifndef RAGNAROK_SOURCE_CLIENT_INPUT_TEXTINPUTBUFFER_H
#define RAGNAROK_SOURCE_CLIENT_INPUT_TEXTINPUTBUFFER_H
#include <string>
#include <windows.h>
class UIWindow;
class WindowManagerWindows;
class TextInputSuggestions {
public:
virtual void Update(const char* text) = 0;
protected:
~TextInputSuggestions() = default;
};
struct TextInputBuffer {
std::string& text;
int& cursor;
int& anchor;
std::string& composition;
std::string& candidate;
int& compositionState;
HWND& window;
const bool& suggestionsEnabled;
UIWindow* const& focused;
UIWindow* const& chatInput;
const bool& chatOpen;
TextInputSuggestions& suggestions;
void CancelComposition();
void DeleteSelection();
void Insert(const char* value);
void Select(int anchor, int cursor);
void CopyDisplayText(std::string& output) const;
void Selection(int& anchor, int& cursor) const;
void SelectionRange(int& begin, int& end) const;
void RefreshComposition(unsigned codePage);
void CopySelection(bool password);
void Paste(UIWindow* blockedFocus, WindowManagerWindows& windows);
void MoveBack(unsigned codePage);
void MoveForward(unsigned codePage);
void Character(unsigned value, LPARAM unused, unsigned codePage);
void KeyDown(
unsigned key, LPARAM unused, unsigned codePage, bool password, UIWindow* blockedPasteFocus, WindowManagerWindows& windows, UIWindow* const& chatArrows
);
};
#endif

View file

@ -1,4 +1,4 @@
#include "Client/TraditionalKeyInput.h"
#include "Client/Input/TraditionalKeyInput.h"
#include "Network/TextEncoding.h"
#include <windows.h>
@ -7,17 +7,16 @@
void TraditionalKeyInput::InitializeMappings() {
// STATIC: 0x011594E0
// GLOBAL: gl_13427
static constexpr std::uint8_t bytes[] = {0xA3, 0x74, 0xA3, 0x78, 0xA3, 0xBE, 0xA3, 0xBF, 0xA3, 0xA4, 0xA3, 0xBD,
0xA3, 0xBB, 0xA3, 0xAB, 0xA3, 0xAF, 0xA3, 0xB3, 0xA3, 0x76, 0xA3, 0xA7,
0xA3, 0x74, 0xA3, 0x74, 0xA3, 0x74, 0xA3, 0xA2, 0xA3, 0xA6, 0xA3, 0xA9,
0xA3, 0xAC, 0xA3, 0xB9, 0xA3, 0xAD, 0xA3, 0xB1, 0xA3, 0xAA, 0xA3, 0xBA,
0xA3, 0xB0, 0xA3, 0xB4, 0xA3, 0x75, 0xA3, 0xA1, 0xA3, 0x7A, 0xA3, 0xA5,
0xA3, 0x74, 0xA3, 0xA3, 0xA3, 0x79, 0xA3, 0x74, 0xA3, 0xA8, 0xA3, 0x77,
0xA3, 0xB7, 0xA3, 0xB5, 0xA3, 0xAE, 0xA3, 0xB2, 0xA3, 0xB6};
static constexpr std::uint8_t bytes[] = {0xA3, 0x74, 0xA3, 0x78, 0xA3, 0xBE, 0xA3, 0xBF, 0xA3, 0xA4, 0xA3, 0xBD, 0xA3, 0xBB, 0xA3, 0xAB, 0xA3,
0xAF, 0xA3, 0xB3, 0xA3, 0x76, 0xA3, 0xA7, 0xA3, 0x74, 0xA3, 0x74, 0xA3, 0x74, 0xA3, 0xA2, 0xA3, 0xA6,
0xA3, 0xA9, 0xA3, 0xAC, 0xA3, 0xB9, 0xA3, 0xAD, 0xA3, 0xB1, 0xA3, 0xAA, 0xA3, 0xBA, 0xA3, 0xB0, 0xA3,
0xB4, 0xA3, 0x75, 0xA3, 0xA1, 0xA3, 0x7A, 0xA3, 0xA5, 0xA3, 0x74, 0xA3, 0xA3, 0xA3, 0x79, 0xA3, 0x74,
0xA3, 0xA8, 0xA3, 0x77, 0xA3, 0xB7, 0xA3, 0xB5, 0xA3, 0xAE, 0xA3, 0xB2, 0xA3, 0xB6};
static constexpr char categories[] = "11441443331111111132331233111121111133333";
static constexpr unsigned char keys[] = "1234567890ABCDEFGHIJKLNMOPQRSTUVWXYZ\xBD\xBA\xBC\xBE\xBF";
this->unknown04C1 = 0;
for (auto& mapping : this->mappings) {
mapping.category = 4;
}
@ -50,6 +49,7 @@ void TraditionalKeyInput::Key(int virtualKey) {
if (!this->keys.empty()) {
this->keys.pop_back();
}
return;
}
@ -59,6 +59,7 @@ void TraditionalKeyInput::Key(int virtualKey) {
break;
}
}
this->keys.push_back(key);
}
@ -72,6 +73,7 @@ const char* TraditionalKeyInput::DisplayText() const {
// FUNCTION: fn_17778
const char* TraditionalKeyInput::Display() {
char bytes[8] = {};
for (std::uint8_t key : this->keys) {
const auto& mapping = this->mappings[key];
if (mapping.category < 4) {
@ -96,6 +98,7 @@ int TraditionalKeyInput::Count() const {
if (this->keys.size() == 1 && this->mappings[this->keys.back()].category == 4) {
return 0;
}
return static_cast<int>(this->keys.size());
}

View file

@ -1,5 +1,5 @@
#ifndef RAGNAROK_SOURCE_CLIENT_TRADITIONALKEYINPUT_H
#define RAGNAROK_SOURCE_CLIENT_TRADITIONALKEYINPUT_H
#ifndef RAGNAROK_SOURCE_CLIENT_INPUT_TRADITIONALKEYINPUT_H
#define RAGNAROK_SOURCE_CLIENT_INPUT_TRADITIONALKEYINPUT_H
#include <array>
#include <cstdint>
@ -11,15 +11,12 @@ struct TraditionalKeyMapping {
std::uint8_t bytes[3];
};
// Borrowed CLanguageTC fields; not a substitute for its base-language/IME
// lifecycle. Key sequence is +0xB8, mappings +0xC0, display +0x58, flag +0x4C1.
struct TraditionalKeyInput {
std::list<std::uint8_t>& keys;
std::array<TraditionalKeyMapping, 256>& mappings;
std::string& display;
std::uint8_t& unknown04C1;
// Unmapped byte triples are deliberately untouched; their category becomes 4.
void InitializeMappings();
void Key(int virtualKey);
void DefaultKey(int virtualKey);

View file

@ -1,46 +0,0 @@
#include "Client/Launcher.h"
#include <cstring>
#include <windows.h>
namespace client {
// OFFSET: 0x00E58820
// FUNCTION: fn_24363
bool RestartFromCommandLine(char* commandLine) {
char* marker = std::strstr(commandLine, "/launcherRESTART:");
if (!marker) {
return false;
}
STARTUPINFOA startup = {};
startup.cb = sizeof(startup);
startup.dwFlags = STARTF_USESHOWWINDOW;
startup.wShowWindow = SW_SHOWNORMAL;
PROCESS_INFORMATION process;
// Original behavior ignores CreateProcessA failure and still returns true.
CreateProcessA(
nullptr, marker + std::strlen("/launcherRESTART:"), nullptr, nullptr, FALSE, 0, nullptr, nullptr, &startup,
&process
);
CloseHandle(process.hProcess);
CloseHandle(process.hThread);
return true;
}
// OFFSET: 0x00E5D390
// FUNCTION: fn_24380
void ExitForProtectionCheck(const char* commandLine) {
if (std::strstr(commandLine, "/check_themida")) {
ExitProcess(0);
}
}
// OFFSET: 0x00E5D390
// FUNCTION: fn_24380
bool AcquireInstanceMutex(HANDLE* mutex) {
*mutex = CreateMutexA(nullptr, TRUE, "MutexInit");
return GetLastError() != ERROR_ALREADY_EXISTS;
}
}

View file

@ -1,18 +0,0 @@
#ifndef RAGNAROK_SOURCE_CLIENT_LAUNCHER_H
#define RAGNAROK_SOURCE_CLIENT_LAUNCHER_H
#include <windows.h>
namespace client {
// Reconstructed semantic name for the original launcher restart branch.
// A mutable buffer is required because CreateProcessA may modify its tail.
bool RestartFromCommandLine(char* commandLine);
// Named source extractions of the established WinMain guard blocks.
void ExitForProtectionCheck(const char* commandLine);
bool AcquireInstanceMutex(HANDLE* mutex);
}
#endif

View file

@ -1,4 +1,4 @@
#include "Client/ActiveGameMode.h"
#include "Client/Mode/ActiveGameMode.h"
// FUNCTION: fn_17831
CGameMode* CWorld::ActiveGameMode() {

Some files were not shown because too many files have changed in this diff Show more