mirror of
https://github.com/brues-code/ClassicAPI.git
synced 2026-11-14 07:00:37 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3009c6d8d2 | ||
|
|
b83bb5b52b |
@@ -49,6 +49,7 @@ Util\Vector4D.lua
|
||||
Util\UiMapPoint.lua
|
||||
Util\UIParent.lua
|
||||
Util\ActionButton.lua
|
||||
Util\Cooldown.lua
|
||||
Util\WorldMap.lua
|
||||
Util\AuraDurationModifiers.lua
|
||||
Util\AuraUtil.lua
|
||||
|
||||
@@ -347,14 +347,25 @@ end
|
||||
-- Goes right above Key Bindings. Stock anchors Key Bindings under Interface
|
||||
-- Options and Turtle under its single Options button, so the new button takes
|
||||
-- over whatever anchor Key Bindings has and Key Bindings moves under it.
|
||||
-- Buttons other addons add at the top of the menu are unaffected.
|
||||
--
|
||||
-- The splice waits for the menu's first show. Other addons insert their own
|
||||
-- buttons the same way -- ShaguTweaks anchors "Advanced Options" under
|
||||
-- Interface Options and moves Key Bindings under it -- and they load after
|
||||
-- us. Splicing at load time would claim the slot first, and the later addon
|
||||
-- would anchor its button on the same spot as ours. By the first show every
|
||||
-- addon has placed its buttons, so ours goes into the chain as it stands.
|
||||
local menuButton = CreateFrame("Button", "GameMenuButtonAddOnOptions", GameMenuFrame, "GameMenuButtonTemplate")
|
||||
menuButton:SetText(ADDON_OPTIONS)
|
||||
local point, relativeTo, relativePoint, x, y = GameMenuButtonKeybindings:GetPoint()
|
||||
menuButton:SetPoint(point, relativeTo, relativePoint, x, y)
|
||||
GameMenuButtonKeybindings:ClearAllPoints()
|
||||
GameMenuButtonKeybindings:SetPoint(point, menuButton, relativePoint, x, y)
|
||||
GameMenuFrame:SetHeight(GameMenuFrame:GetHeight() + menuButton:GetHeight() - y)
|
||||
local spliced
|
||||
GameMenuFrame:HookScript("OnShow", function()
|
||||
if spliced then return end
|
||||
spliced = true
|
||||
local point, relativeTo, relativePoint, x, y = GameMenuButtonKeybindings:GetPoint()
|
||||
menuButton:SetPoint(point, relativeTo, relativePoint, x, y)
|
||||
GameMenuButtonKeybindings:ClearAllPoints()
|
||||
GameMenuButtonKeybindings:SetPoint(point, menuButton, relativePoint, x, y)
|
||||
GameMenuFrame:SetHeight(GameMenuFrame:GetHeight() + menuButton:GetHeight() - y)
|
||||
end)
|
||||
menuButton:SetScript("OnClick", function()
|
||||
PlaySound("igMainMenuOption")
|
||||
ShowUIPanel(frame)
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
-- CooldownFrame_SetTimer for both kinds of cooldown frame. A Cooldown frame
|
||||
-- (CreateFrame("Cooldown") or <Cooldown>) takes 4.3.4's body (Cooldown.lua),
|
||||
-- which hands the timer to the frame's own SetCooldown. Every other frame is
|
||||
-- one of 1.12's indicator Models (CooldownFrameTemplate, as the action, bag,
|
||||
-- spellbook and paper-doll buttons build theirs) and keeps 1.12's body, which
|
||||
-- drives the model's sweep from CooldownFrame_OnUpdateModel.
|
||||
|
||||
function CooldownFrame_SetTimer(this, start, duration, enable)
|
||||
if ( this:IsObjectType("Cooldown") ) then
|
||||
if ( start and start > 0 and duration > 0 and enable > 0 ) then
|
||||
this:SetCooldown(start, duration);
|
||||
this:Show();
|
||||
else
|
||||
this:Hide();
|
||||
end
|
||||
return;
|
||||
end
|
||||
if ( start > 0 and duration > 0 and enable > 0) then
|
||||
this.start = start;
|
||||
this.duration = duration;
|
||||
this.stopping = 0;
|
||||
this:SetSequence(0);
|
||||
this:Show();
|
||||
else
|
||||
this:Hide();
|
||||
end
|
||||
end
|
||||
+23
-21
@@ -6496,7 +6496,8 @@ ignores a negative `id`.
|
||||
|
||||
### `CreateFrame("Cooldown" [, name, parent, template])`
|
||||
|
||||
Creates a cooldown frame. The frame shows a cooldown sweep.
|
||||
Creates a cooldown frame. The frame shows a dark sweep that moves clockwise
|
||||
over its area, then a short flash, then hides itself.
|
||||
|
||||
```lua
|
||||
local cd = CreateFrame("Cooldown", nil, button, "CooldownFrameTemplate")
|
||||
@@ -6505,43 +6506,44 @@ cd:IsObjectType("Cooldown") -- true
|
||||
cd:SetCooldown(GetTime(), 10) -- start, duration in seconds
|
||||
cd:SetReverse(false)
|
||||
cd:GetReverse() -- false
|
||||
cd:SetDrawEdge(false)
|
||||
cd:GetDrawEdge() -- false
|
||||
cd:SetDrawEdge(true)
|
||||
cd:GetDrawEdge() -- true
|
||||
```
|
||||
|
||||
| Method | Notes |
|
||||
| --- | --- |
|
||||
| `cooldown:SetCooldown(start, duration)` | Sets the sweep. `start` and `duration` are numbers in seconds. `start` is a time value, for example the value that `GetTime()` returns. The frame shows the sweep. If `start` or `duration` is not positive, the frame hides. |
|
||||
| `cooldown:SetReverse(reverse)` / `cooldown:GetReverse()` | Sets and returns the reverse flag. The flag is `false` when the frame is created. |
|
||||
| `cooldown:SetDrawEdge(drawEdge)` / `cooldown:GetDrawEdge()` | Sets and returns the draw-edge flag. The flag is `false` when the frame is created. |
|
||||
| `cooldown:SetCooldown(start, duration)` | Starts the sweep and shows the frame. `start` and `duration` are numbers in seconds. `start` is a time value, for example the value that `GetTime()` returns. When `duration` is over, the frame shows the flash for one second and then hides. |
|
||||
| `cooldown:SetReverse(reverse)` / `cooldown:GetReverse()` | Sets and returns the reverse flag. With the flag set, the sweep starts full and becomes empty. At the end, the frame stays shown with no flash. The flag is `false` when the frame is created. |
|
||||
| `cooldown:SetDrawEdge(drawEdge)` / `cooldown:GetDrawEdge()` | Sets and returns the draw-edge flag. With the flag set, a bright line moves along the edge of the sweep. The flag is `false` when the frame is created. |
|
||||
|
||||
If `start` or `duration` is not a number, `SetCooldown` gives the error
|
||||
`Usage: <name>:SetCooldown(start, duration)`.
|
||||
|
||||
You can also use `CooldownFrame_SetTimer(cd, start, duration, 1)` to set
|
||||
the sweep.
|
||||
The draw-edge flag applies from the next `SetCooldown` call.
|
||||
|
||||
The reverse flag and the draw-edge flag do not change the sweep picture.
|
||||
The getter methods return the values that the setter methods set.
|
||||
You can also use `CooldownFrame_SetTimer(cd, start, duration, enable)`.
|
||||
This function calls `SetCooldown` on a cooldown frame. If `start`,
|
||||
`duration`, or `enable` is not more than 0, it hides the frame.
|
||||
|
||||
Use these methods on a cooldown frame. A call on a frame of another type
|
||||
gives an error.
|
||||
Only cooldown frames have these five methods.
|
||||
|
||||
XML files can also create a cooldown frame with a `<Cooldown>` element:
|
||||
A new cooldown frame has a sweep that is already over. If the frame is
|
||||
shown before the first `SetCooldown` call, it hides itself after one
|
||||
second.
|
||||
|
||||
XML files can also create a cooldown frame with a `<Cooldown>` element.
|
||||
The `reverse` and `drawEdge` attributes set the two flags:
|
||||
|
||||
```xml
|
||||
<Frames>
|
||||
<Cooldown name="$parentCooldown" inherits="CooldownFrameTemplate"/>
|
||||
<Cooldown name="$parentCooldown" inherits="CooldownFrameTemplate" drawEdge="true"/>
|
||||
</Frames>
|
||||
```
|
||||
|
||||
Every cooldown frame shows the sweep, also without a template. Its
|
||||
`template` and `inherits` templates apply after the sweep, so they can
|
||||
change it.
|
||||
|
||||
A cooldown frame starts without anchors. Give it a position with
|
||||
`SetPoint`, `SetAllPoints`, or `<Anchors>`. `CooldownFrameTemplate` sets
|
||||
the frame to the full size of its parent.
|
||||
A cooldown frame needs no template. A cooldown frame starts without
|
||||
anchors. Give it a position with `SetPoint`, `SetAllPoints`, or
|
||||
`<Anchors>`. `CooldownFrameTemplate` sets the frame to the full size of
|
||||
its parent, and the frame starts hidden.
|
||||
|
||||
### `frame:SetShown(shown)`
|
||||
|
||||
|
||||
+131
-14
@@ -3817,16 +3817,6 @@ enum Offsets {
|
||||
// GetEffectiveAlpha calls it for its `self` type check, then reads the
|
||||
// byte.
|
||||
FUN_SCRIPT_FRAME_GETALPHA = 0x00774DC0,
|
||||
// Region GetObjectType / IsObjectType (Region table 0x0087C9B8 entries
|
||||
// 0/1, ctx VAR_REGION_METHOD_REGISTRY) and Frame GetFrameType /
|
||||
// IsFrameType (Frame table 0x00878EC0 entries 0/1, ctx
|
||||
// VAR_FRAME_METHOD_REGISTRY), per docs/raw_methods.txt.
|
||||
// `Frame::Cooldown` re-registers these names on the Model registry and
|
||||
// delegates to them for every frame that is not a marked Cooldown.
|
||||
FUN_SCRIPT_REGION_GETOBJECTTYPE = 0x007A11D0,
|
||||
FUN_SCRIPT_REGION_ISOBJECTTYPE = 0x007A1290,
|
||||
FUN_SCRIPT_FRAME_GETFRAMETYPE = 0x00773640,
|
||||
FUN_SCRIPT_FRAME_ISFRAMETYPE = 0x00773700,
|
||||
|
||||
// Hyperlink scripts. ScrollingMessageFrame and SimpleHTML share a base
|
||||
// whose GetScriptByName override (0x007A3700, in the vtables at slots
|
||||
@@ -10840,10 +10830,123 @@ enum Offsets {
|
||||
// FUN_0048FBF0 after LoadScriptFunctions and before FrameXML loads — and
|
||||
// the glue UI's FUN_0046A400.
|
||||
FUN_FRAMEXML_REGISTER_FACTORY = 0x006EE880,
|
||||
// The "Model" factory from that default list: allocates the 0x3DC-byte
|
||||
// CSimpleModel and constructs it on `parent` (0x0076C8E0).
|
||||
// `CSimpleFrame *__fastcall(CSimpleFrame *parent)`.
|
||||
FUN_FRAMEXML_CREATE_MODEL = 0x006EECF0,
|
||||
|
||||
// ---- Subclassing CSimpleFrame (Frame::Cooldown) -------------------------
|
||||
// The "Frame" factory of the default list (0x006EEC10) is
|
||||
// `SMemAlloc(SIMPLEFRAME_SIZE, file, line, 0)` then the constructor
|
||||
// `CSimpleFrame::CSimpleFrame` — `__thiscall(frame, parent)`, `ret 4` —
|
||||
// which stores VTBL_SIMPLEFRAME at +0 and VTBL_SIMPLEFRAME_LAYOUT at
|
||||
// OFF_FRAME_LAYOUT_SUBOBJECT (0x007692E5 / 0x007692EB). Every derived
|
||||
// factory (Model 0x006EECF0: 0x3DC bytes, CSimpleModel ctor) has the same
|
||||
// shape. Slot 0's deleting destructor (0x00769380) runs the destructor
|
||||
// body FUN_FRAME_DESTRUCTOR and SMemFrees the block, so a larger block
|
||||
// from SMemAlloc frees cleanly. The vtables are 36 and 11 slots: the main
|
||||
// one ends where the layout one's successor (title region, 0x0081C528)
|
||||
// begins, and the layout one ends at VTBL_SIMPLEFRAME (benilla-re
|
||||
// ui/frames, dumped from the exe).
|
||||
SIMPLEFRAME_SIZE = 0x314,
|
||||
FUN_SIMPLEFRAME_CONSTRUCTOR = 0x00769090,
|
||||
VTBL_SIMPLEFRAME = 0x0081C498,
|
||||
VTBL_SIMPLEFRAME_SLOTS = 36,
|
||||
VTBL_SIMPLEFRAME_LAYOUT = 0x0081C46C,
|
||||
VTBL_SIMPLEFRAME_LAYOUT_SLOTS = 11,
|
||||
// Main-vtable slots, all __thiscall (CSimpleFrame's own in brackets):
|
||||
// +0x00 deleting destructor (this, flags), ret 4 [0x00769380]
|
||||
// +0x08 GetScriptMethod (this, L, name) -> int, ret 8 [0x00778590]:
|
||||
// FUN_FRAMESCRIPT_PUSH_METHOD on the class hash, else the base
|
||||
// class's lookup — the `__index` dispatcher's per-class step
|
||||
// +0x10 IsA (this, int typeId) -> bool, ret 4 [0x00484780]
|
||||
// +0x18 IsObjectType (this, const char *) -> bool, ret 4 [0x004847B0]
|
||||
// +0x1C GetObjectType (this) -> const char * [0x00484800]:
|
||||
// what Script GetObjectType (0x007A11D0) and GetFrameType
|
||||
// (0x00773640) push, after IsA(Region/Frame id) via +0x10
|
||||
// +0x38 OnFrameUpdate (this, float elapsedSec), ret 4 [0x0076B2C0]:
|
||||
// the update walk's per-frame call (CSimpleTop 0x00765707);
|
||||
// runs OnUpdate
|
||||
// +0x44 EmitLayer (this, batch, int layer), ret 8 [0x0076B3A0]:
|
||||
// the level rebuild's per-frame call (0x007659ED) — 4.3.4's
|
||||
// OnFrameRender(batch, layer)
|
||||
// +0x84 Hide (this) / +0x88 Show (this): the visibility half of 1.12's
|
||||
// Show/Hide; Script Show/Hide (0x00775750/0x00775810) and the XML
|
||||
// `hidden` attribute (0x007698A6/0x007698BA) first write
|
||||
// OFF_FRAME_SHOWN 1/0, then call these.
|
||||
// (+0x28 is VTBL_FRAME_SET_FRAME_ALPHA.)
|
||||
VTBL_FRAME_DELETING_DESTRUCTOR = 0x00,
|
||||
VTBL_FRAME_GET_SCRIPT_METHOD = 0x08,
|
||||
VTBL_FRAME_IS_A = 0x10,
|
||||
VTBL_FRAME_IS_OBJECT_TYPE = 0x18,
|
||||
VTBL_FRAME_GET_OBJECT_TYPE = 0x1C,
|
||||
VTBL_FRAME_ON_FRAME_UPDATE = 0x38,
|
||||
VTBL_FRAME_EMIT_LAYER = 0x44,
|
||||
VTBL_FRAME_HIDE = 0x84,
|
||||
VTBL_FRAME_SHOW = 0x88,
|
||||
// Layout-vtable slots, `this` = the layout sub-object:
|
||||
// +0x00 OnFrameSizeChanged (this, const float *oldRect), ret 4
|
||||
// [0x0076B580]
|
||||
// +0x04 deleting destructor thunk: `sub ecx, 0x24; jmp 0x00769380`
|
||||
// (0x0076C410) — it does NOT go through slot 0
|
||||
// +0x08 VTBL_XML_NODE_LOADER (FUN_XML_FRAME_LOAD)
|
||||
// +0x0C GetLayoutParent (this) -> layout or 0 [0x0076C6E0]
|
||||
VTBL_LAYOUT_ON_FRAME_SIZE_CHANGED = 0x00,
|
||||
VTBL_LAYOUT_DELETING_DESTRUCTOR = 0x04,
|
||||
VTBL_LAYOUT_GET_LAYOUT_PARENT = 0x0C,
|
||||
// CLayoutFrame::LoadXML's `setAllPoints="true"` (0x00767800) is
|
||||
// FUN_LAYOUT_SET_ALL_POINTS(layout, GetLayoutParent(), 1).
|
||||
//
|
||||
// CSimpleFrame::NotifyLayerChanged — `void __thiscall(frame, int layer)`,
|
||||
// `ret 4`: marks one draw layer for a rebuild, in the frame's own mask
|
||||
// when it draws itself (FRAME_FLAG_SCROLLED), else in its level's when
|
||||
// the frame is visible. Nothing to mark when it is not: showing it
|
||||
// joins the level, which rebuilds it.
|
||||
FUN_FRAME_NOTIFY_LAYER_CHANGED = 0x0076A990,
|
||||
|
||||
// ---- Per-class method hashes --------------------------------------------
|
||||
// Every frame class keeps its Lua methods in a Storm hash of 10 dwords
|
||||
// (0x28 bytes): +0x00 the node allocator vtable VTBL_METHOD_HASH_ALLOCATOR,
|
||||
// +0x04 the node link offset 0xC, +0x08/+0x0C an empty list (head = &+0x08,
|
||||
// tail = &+0x08 | 1), +0x10..+0x20 zero (the bucket array), +0x24 the
|
||||
// bucket mask, -1 until the first registration allocates 4 buckets.
|
||||
// That is the whole static initializer (Model's 0x0076F5F0, Frame's
|
||||
// 0x00778310 — both store 0x00806CB8). FUN_REGISTER_FRAME_METHODS fills
|
||||
// one (it always appends a node: re-registering a name it holds without
|
||||
// unregistering first leaves the old node and its stale ref), and
|
||||
// FrameScriptUnregisterMethods — `void __fastcall(hash)` — unrefs each
|
||||
// function in the live Lua state and frees the nodes, keeping the
|
||||
// buckets for the next registration.
|
||||
// FrameScriptPushMethod — `int __fastcall(L, const char *name, hash)`,
|
||||
// callee pops `hash`: pushes registry[ref] and answers 1 when found.
|
||||
VTBL_METHOD_HASH_ALLOCATOR = 0x00806CB8,
|
||||
METHOD_HASH_SIZE = 0x28,
|
||||
FUN_FRAMESCRIPT_PUSH_METHOD = 0x00702000,
|
||||
FUN_FRAMESCRIPT_UNREGISTER_METHODS = 0x00701F20,
|
||||
// CGGameUI::UnregisterScriptFunctions — `void __cdecl(void)`: the mirror
|
||||
// of LoadScriptFunctions, called from the game UI's shutdown (0x00490CBA)
|
||||
// on /reload and logout while the game Lua state is still open. Releases
|
||||
// the class hashes (GameTooltip, Minimap, PlayerModel, ...) with
|
||||
// FUN_FRAMESCRIPT_UNREGISTER_METHODS and unregisters the globals.
|
||||
FUN_GAMEUI_UNREGISTER_SCRIPT_FUNCTIONS = 0x00490CE0,
|
||||
|
||||
// ---- Layer batch quads ----------------------------------------------------
|
||||
// A layer batch (0x30 bytes, benilla-re ui/draworder) counts its entries
|
||||
// at +0x04 and keeps its quads in an array at +0x08: capacity, count
|
||||
// (+0x0C), records (+0x10), growth step. A record is 0x1C bytes: device
|
||||
// texture (FUN_TEXTURE_GET_RENDERABLE), float[4][3] positions, float[4][2]
|
||||
// texcoords, blend mode, colour pointer or 0, colour stride (4 = one
|
||||
// colour per vertex, 0 = one for all), pixel shader or 0. The texture
|
||||
// emit FUN_00772FD0 writes exactly that after reserving one record with
|
||||
// FUN_RENDERBATCH_RESERVE_QUADS — `void __thiscall(array, extra, round)`,
|
||||
// `ret 8`, a no-op while there is room. The batch keeps the POINTERS and
|
||||
// re-reads them on every draw (FUN_0076FB00: a 4-vertex strip with the
|
||||
// indices {0,1,2,3} at 0x00878CDC, so the triangles are 0-1-2 and
|
||||
// 1-2-3); it is rebuilt only when a layer is marked changed. A record
|
||||
// with a colour and a blend mode below 2 draws with blend 2 (alpha), the
|
||||
// same promotion 3.3.5's SortByTexture makes.
|
||||
FUN_RENDERBATCH_RESERVE_QUADS = 0x00773280,
|
||||
OFF_RENDERBATCH_ENTRY_COUNT = 0x04,
|
||||
OFF_RENDERBATCH_QUADS = 0x08,
|
||||
OFF_RENDERBATCH_QUAD_COUNT = 0x0C,
|
||||
OFF_RENDERBATCH_QUAD_RECORDS = 0x10,
|
||||
RENDERBATCH_QUAD_SIZE = 0x1C,
|
||||
// CLayoutFrame::ClearAllPoints — `void __fastcall(layout)`, layout =
|
||||
// object + OFF_FRAME_LAYOUT_SUBOBJECT. Frees all 9 anchor slots and
|
||||
// unlinks the frame from each relative frame. Script ClearAllPoints
|
||||
@@ -11029,6 +11132,20 @@ enum Offsets {
|
||||
// load — calling it each frame IS the residency reference (what the
|
||||
// minimap's masked draw does for its mask at 0x004ec65c).
|
||||
FUN_TEXTURE_LOAD_BY_PATH = 0x00449D90,
|
||||
// TextureCreateWithCallback — `HTEXTURE __fastcall(uint32 w, uint32 h,
|
||||
// uint32 mips, uint32 format, uint32 flags, void *owner, callback, const
|
||||
// char *name, int force)`: a named texture whose texels `callback`
|
||||
// supplies, never deduplicated by name. The portrait cache (0x00525F58:
|
||||
// 64x64, 1 mip, GXTEX_FORMAT_ARGB8888, FUN_GX_TEXFLAGS_INIT(1, 0,0, 0,0,0,
|
||||
// 1, 0), "Portrait2") is the model. The callback is `void
|
||||
// __fastcall(uint32 command, uint32 w, uint32 h, uint32 face, uint32
|
||||
// level, void *owner, uint32 *stride, const void **texels)`, `ret 0x18`;
|
||||
// on GXTEX_CMD_LATCH it answers stride = w * 4 and the texels, which it
|
||||
// keeps (the portrait's 0x00525AE0 hands its cached array over without a
|
||||
// copy), and ignores every other command.
|
||||
FUN_TEXTURE_CREATE_WITH_CALLBACK = 0x00449BF0,
|
||||
GXTEX_FORMAT_ARGB8888 = 2,
|
||||
GXTEX_CMD_LATCH = 1,
|
||||
PTR_TEXLOAD_DESC_VTBL = 0x007FFA10,
|
||||
FUN_GX_TEXFLAGS_INIT = 0x0058A980,
|
||||
FUN_TEXTURE_GET_RENDERABLE = 0x0044ACF0,
|
||||
|
||||
@@ -167,10 +167,16 @@ const WidgetSystem kWidgetSystems[] = {
|
||||
{Offsets::VAR_MODEL_METHOD_REGISTRY, "SimpleModelAPI"},
|
||||
};
|
||||
|
||||
// Hashes of the frame classes this DLL adds (NameWidgetSystem).
|
||||
std::vector<WidgetSystem> g_ownWidgetSystems;
|
||||
|
||||
const char *WidgetSystemFor(const void *registry) {
|
||||
for (const WidgetSystem &w : kWidgetSystems)
|
||||
if (reinterpret_cast<const void *>(w.registry) == registry)
|
||||
return w.system;
|
||||
for (const WidgetSystem &w : g_ownWidgetSystems)
|
||||
if (reinterpret_cast<const void *>(w.registry) == registry)
|
||||
return w.system;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -659,6 +665,12 @@ void RecordFrameMethods(const void *registry, const Game::Lua::FrameMethodEntry
|
||||
}
|
||||
}
|
||||
|
||||
void NameWidgetSystem(const void *registry, const char *system) {
|
||||
if (WidgetSystemFor(registry) != nullptr)
|
||||
return;
|
||||
g_ownWidgetSystems.push_back({reinterpret_cast<uintptr_t>(registry), system});
|
||||
}
|
||||
|
||||
void RecordEnum(const char *parent, const char *sub, const Game::Lua::EnumIntegerEntry *entries,
|
||||
int count, const char *system) {
|
||||
if (g_pass == ENV_NONE || sub == nullptr)
|
||||
|
||||
@@ -34,6 +34,9 @@ void RecordGlobal(const char *name, const Game::Doc::Function *doc);
|
||||
void RecordTable(const char *table, const char *name, const Game::Doc::Function *doc);
|
||||
void RecordFrameMethods(const void *registry, const Game::Lua::FrameMethodEntry *table,
|
||||
int count, const Game::Doc::Method *docs, int docCount);
|
||||
// Names the widget system of a method hash this DLL owns (a frame class it
|
||||
// adds), alongside the engine registries the exporter already knows.
|
||||
void NameWidgetSystem(const void *registry, const char *system);
|
||||
void RecordEnum(const char *parent, const char *sub, const Game::Lua::EnumIntegerEntry *entries,
|
||||
int count, const char *system);
|
||||
|
||||
|
||||
+791
-251
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,62 @@
|
||||
// This file is part of ClassicAPI.
|
||||
//
|
||||
// ClassicAPI is free software: you can redistribute it and/or modify it under the terms
|
||||
// of the GNU General Public License as published by the Free Software Foundation, either
|
||||
// version 3 of the License, or (at your option) any later version.
|
||||
//
|
||||
// ClassicAPI is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
// PURPOSE. See the GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License along with
|
||||
// ClassicAPI. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#include "frame/RenderBatch.h"
|
||||
|
||||
#include "Game.h"
|
||||
#include "Offsets.h"
|
||||
|
||||
namespace Frame::RenderBatch {
|
||||
|
||||
namespace {
|
||||
|
||||
using GetRenderable_t = void *(__fastcall *)(void *texture, int load, void *callback);
|
||||
using ReserveQuads_t = void(__thiscall *)(void *array, uint32_t extra, int round);
|
||||
|
||||
struct QuadRecord {
|
||||
void *deviceTexture;
|
||||
const C3Vector *positions;
|
||||
const C2Vector *texCoords;
|
||||
uint32_t blend;
|
||||
const uint32_t *color;
|
||||
uint32_t colorStride;
|
||||
void *shader;
|
||||
};
|
||||
static_assert(sizeof(QuadRecord) == Offsets::RENDERBATCH_QUAD_SIZE, "quad record layout");
|
||||
|
||||
} // namespace
|
||||
|
||||
void QueueStrip(void *batch, void *texture, Blend blend, const C3Vector *positions,
|
||||
const C2Vector *texCoords, const uint32_t *color) {
|
||||
// Loading on demand, as the texture emit does: a texture still streaming
|
||||
// is finished here, so the first rebuild already draws it.
|
||||
void *device = reinterpret_cast<GetRenderable_t>(Offsets::FUN_TEXTURE_GET_RENDERABLE)(
|
||||
texture, 1, nullptr);
|
||||
if (device == nullptr)
|
||||
return;
|
||||
reinterpret_cast<ReserveQuads_t>(Offsets::FUN_RENDERBATCH_RESERVE_QUADS)(
|
||||
Game::Ptr<uint8_t>(batch, Offsets::OFF_RENDERBATCH_QUADS), 1, 1);
|
||||
uint32_t &count = Game::Ref<uint32_t>(batch, Offsets::OFF_RENDERBATCH_QUAD_COUNT);
|
||||
QuadRecord &r = Game::Ref<QuadRecord *>(batch, Offsets::OFF_RENDERBATCH_QUAD_RECORDS)[count];
|
||||
r.deviceTexture = device;
|
||||
r.positions = positions;
|
||||
r.texCoords = texCoords;
|
||||
r.blend = blend;
|
||||
r.color = color;
|
||||
r.colorStride = 0;
|
||||
r.shader = nullptr;
|
||||
++count;
|
||||
++Game::Ref<uint32_t>(batch, Offsets::OFF_RENDERBATCH_ENTRY_COUNT);
|
||||
}
|
||||
|
||||
} // namespace Frame::RenderBatch
|
||||
@@ -0,0 +1,50 @@
|
||||
// This file is part of ClassicAPI.
|
||||
//
|
||||
// ClassicAPI is free software: you can redistribute it and/or modify it under the terms
|
||||
// of the GNU General Public License as published by the Free Software Foundation, either
|
||||
// version 3 of the License, or (at your option) any later version.
|
||||
//
|
||||
// ClassicAPI is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
// PURPOSE. See the GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License along with
|
||||
// ClassicAPI. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#pragma once
|
||||
|
||||
// Geometry a frame draws itself, queued into the layer batch its EmitLayer
|
||||
// slot is handed — 4.3.4's CRenderBatch::Queue, in the one shape 1.12's batch
|
||||
// draws: a four-vertex strip (triangles 0-1-2 and 1-2-3). See the Offsets.h
|
||||
// "Layer batch quads" block.
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace Frame::RenderBatch {
|
||||
|
||||
struct C3Vector {
|
||||
float x, y, z;
|
||||
};
|
||||
|
||||
struct C2Vector {
|
||||
float x, y;
|
||||
};
|
||||
|
||||
// Blend modes (EGxBlend).
|
||||
enum Blend : uint32_t {
|
||||
BLEND_OPAQUE = 0,
|
||||
BLEND_ALPHA_KEY = 1,
|
||||
BLEND_ALPHA = 2,
|
||||
BLEND_ADD = 3,
|
||||
};
|
||||
|
||||
// Appends one strip of `texture` (an HTEXTURE) to `batch`, the way a
|
||||
// texture region emits itself (FUN_00772FD0). `color` is one BGRA colour for
|
||||
// all four vertices. The batch keeps the three pointers and reads them on
|
||||
// every draw until its layer is rebuilt, so they must stay valid and may be
|
||||
// rewritten in place to animate. Adds nothing when the texture has no device
|
||||
// texture.
|
||||
void QueueStrip(void *batch, void *texture, Blend blend, const C3Vector *positions,
|
||||
const C2Vector *texCoords, const uint32_t *color);
|
||||
|
||||
} // namespace Frame::RenderBatch
|
||||
@@ -0,0 +1,100 @@
|
||||
// This file is part of ClassicAPI.
|
||||
//
|
||||
// ClassicAPI is free software: you can redistribute it and/or modify it under the terms
|
||||
// of the GNU General Public License as published by the Free Software Foundation, either
|
||||
// version 3 of the License, or (at your option) any later version.
|
||||
//
|
||||
// ClassicAPI is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
// PURPOSE. See the GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License along with
|
||||
// ClassicAPI. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#include "texture/Load.h"
|
||||
|
||||
#include "Game.h"
|
||||
#include "Offsets.h"
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace Texture {
|
||||
|
||||
namespace {
|
||||
|
||||
using HandleRelease_t = void(__fastcall *)(void *handle);
|
||||
using SysMsgAdd_t = int(__fastcall *)(void *status, uint32_t level);
|
||||
using StatusDestroy_t = void(__thiscall *)(void *status);
|
||||
using TexFlagsInit_t = void *(__thiscall *)(void *self, uint32_t blend, int, int, int, int, int,
|
||||
uint32_t, int);
|
||||
using TextureLoad_t = uint32_t(__fastcall *)(const char *path, void *desc, uint32_t flags, int,
|
||||
int);
|
||||
|
||||
using CreateWithCallback_t = void *(__fastcall *)(uint32_t w, uint32_t h, uint32_t mips,
|
||||
uint32_t format, uint32_t flags, void *owner,
|
||||
void *callback, const char *name, int force);
|
||||
|
||||
struct TexLoadDesc {
|
||||
void *vtbl;
|
||||
int32_t field4;
|
||||
void *self8;
|
||||
uint32_t fieldC;
|
||||
int32_t field10;
|
||||
};
|
||||
|
||||
// SetTexture's flags: the default filter, clamped, one mip level.
|
||||
uint32_t DefaultFlags() {
|
||||
uint32_t flags = 0;
|
||||
const uint32_t blend = Game::Read<uint32_t>(Offsets::VAR_TEXTURE_BLEND_DEFAULT);
|
||||
reinterpret_cast<TexFlagsInit_t>(Offsets::FUN_GX_TEXFLAGS_INIT)(&flags, blend, 0, 0, 0, 0, 0,
|
||||
1, 0);
|
||||
return flags;
|
||||
}
|
||||
|
||||
// The texel source of CreateFromPixels, the portrait cache's 0x00525AE0 with
|
||||
// the array as the owner.
|
||||
void __fastcall LatchPixels(uint32_t command, uint32_t width, uint32_t /*height*/,
|
||||
uint32_t /*face*/, uint32_t /*level*/, void *owner, uint32_t *stride,
|
||||
const void **texels) {
|
||||
if (command != Offsets::GXTEX_CMD_LATCH)
|
||||
return;
|
||||
*stride = width * 4;
|
||||
*texels = owner;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void ReleaseHandle(void *handle) {
|
||||
if (handle != nullptr)
|
||||
reinterpret_cast<HandleRelease_t>(Offsets::FUN_HANDLE_RELEASE)(handle);
|
||||
}
|
||||
|
||||
// Same failure test and cleanup as SetTexture: a status level of 2 or more
|
||||
// closes the green fallback and passes the status to the (silent)
|
||||
// system-message printer; the status is destroyed either way.
|
||||
void *LoadByPath(const char *path) {
|
||||
TexLoadDesc desc;
|
||||
desc.vtbl = reinterpret_cast<void *>(Offsets::PTR_TEXLOAD_DESC_VTBL);
|
||||
desc.field4 = 8;
|
||||
desc.self8 = &desc.self8;
|
||||
desc.fieldC = reinterpret_cast<uintptr_t>(&desc.self8) | 1u;
|
||||
desc.field10 = 0;
|
||||
void *handle = reinterpret_cast<void *>(reinterpret_cast<TextureLoad_t>(
|
||||
Offsets::FUN_TEXTURE_LOAD_BY_PATH)(path, &desc, DefaultFlags(), 0, 1));
|
||||
if (desc.field10 >= 2) {
|
||||
ReleaseHandle(handle);
|
||||
handle = nullptr;
|
||||
reinterpret_cast<SysMsgAdd_t>(Offsets::FUN_SYSMSG_ADD_STATUS)(&desc, 4);
|
||||
}
|
||||
reinterpret_cast<StatusDestroy_t>(Offsets::FUN_FRAMESCRIPT_STATUS_RESET)(&desc);
|
||||
return handle;
|
||||
}
|
||||
|
||||
void *CreateFromPixels(const char *name, uint32_t width, uint32_t height,
|
||||
const uint32_t *texels) {
|
||||
return reinterpret_cast<CreateWithCallback_t>(Offsets::FUN_TEXTURE_CREATE_WITH_CALLBACK)(
|
||||
width, height, 1, Offsets::GXTEX_FORMAT_ARGB8888, DefaultFlags(),
|
||||
const_cast<uint32_t *>(texels), reinterpret_cast<void *>(&LatchPixels), name, 0);
|
||||
}
|
||||
|
||||
} // namespace Texture
|
||||
@@ -0,0 +1,38 @@
|
||||
// This file is part of ClassicAPI.
|
||||
//
|
||||
// ClassicAPI is free software: you can redistribute it and/or modify it under the terms
|
||||
// of the GNU General Public License as published by the Free Software Foundation, either
|
||||
// version 3 of the License, or (at your option) any later version.
|
||||
//
|
||||
// ClassicAPI is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
// PURPOSE. See the GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License along with
|
||||
// ClassicAPI. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#pragma once
|
||||
|
||||
// Path -> HTEXTURE, the load CSimpleTexture::SetTexture (FUN_00770200) makes.
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace Texture {
|
||||
|
||||
// The loaded handle, or nullptr when the file does not load. Linear filter,
|
||||
// clamped, the flags SetTexture's own call builds. The caller owns one
|
||||
// reference and drops it with ReleaseHandle.
|
||||
void *LoadByPath(const char *path);
|
||||
|
||||
// Drops one reference on a handle (FUN_HANDLE_RELEASE). Null is a no-op.
|
||||
void ReleaseHandle(void *handle);
|
||||
|
||||
// A one-mip `width` x `height` texture of ARGB8888 `texels`, through the
|
||||
// engine's own procedural path (FUN_TEXTURE_CREATE_WITH_CALLBACK) with the
|
||||
// same flags as LoadByPath. The engine reads `texels` whenever it uploads the
|
||||
// texture, so they must outlive the handle. Never deduplicated: each call is
|
||||
// a new texture.
|
||||
void *CreateFromPixels(const char *name, uint32_t width, uint32_t height,
|
||||
const uint32_t *texels);
|
||||
|
||||
} // namespace Texture
|
||||
+3
-48
@@ -54,6 +54,7 @@
|
||||
|
||||
#include "Game.h"
|
||||
#include "Offsets.h"
|
||||
#include "texture/Load.h"
|
||||
#include "texture/Mask.h"
|
||||
#include "texture/Transform.h"
|
||||
#include "ui/FrameObject.h"
|
||||
@@ -96,56 +97,10 @@ std::unordered_map<void *, std::vector<void *>> g_baseMasks;
|
||||
// Regions minted by CreateMaskTexture — a mask-source allow-list.
|
||||
std::unordered_set<void *> g_maskRegions;
|
||||
|
||||
// --- path -> HTEXTURE loader (mirrors FUN_00770200's SetTexture load) --------
|
||||
|
||||
using HandleRelease_t = void(__fastcall *)(void *handle);
|
||||
using SysMsgAdd_t = int(__fastcall *)(void *status, uint32_t level);
|
||||
using StatusDestroy_t = void(__thiscall *)(void *status);
|
||||
|
||||
void ReleaseHandle(void *handle) {
|
||||
if (handle != nullptr)
|
||||
reinterpret_cast<HandleRelease_t>(Offsets::FUN_HANDLE_RELEASE)(handle);
|
||||
}
|
||||
|
||||
using TexFlagsInit_t = void *(__thiscall *)(void *self, uint32_t blend, int, int, int, int, int,
|
||||
uint32_t, int);
|
||||
using TextureLoad_t = uint32_t(__fastcall *)(const char *path, void *desc, uint32_t flags, int,
|
||||
int);
|
||||
using GetRenderable_t = void *(__fastcall *)(void *hTex, int force, void *);
|
||||
|
||||
struct TexLoadDesc {
|
||||
void *vtbl;
|
||||
int32_t field4;
|
||||
void *self8;
|
||||
uint32_t fieldC;
|
||||
int32_t field10;
|
||||
};
|
||||
|
||||
// The loaded handle, or nullptr when the file does not load. Same failure
|
||||
// test and cleanup as SetTexture: a status level of 2 or more closes the
|
||||
// green fallback and passes the status to the (silent) system-message
|
||||
// printer; the status is destroyed either way.
|
||||
void *LoadByPath(const char *path) {
|
||||
TexLoadDesc desc;
|
||||
desc.vtbl = reinterpret_cast<void *>(Offsets::PTR_TEXLOAD_DESC_VTBL);
|
||||
desc.field4 = 8;
|
||||
desc.self8 = &desc.self8;
|
||||
desc.fieldC = reinterpret_cast<uintptr_t>(&desc.self8) | 1u;
|
||||
desc.field10 = 0;
|
||||
uint32_t flags = 0;
|
||||
const uint32_t blend = Game::Read<uint32_t>(Offsets::VAR_TEXTURE_BLEND_DEFAULT);
|
||||
reinterpret_cast<TexFlagsInit_t>(Offsets::FUN_GX_TEXFLAGS_INIT)(&flags, blend, 0, 0, 0, 0, 0,
|
||||
1, 0);
|
||||
void *handle = reinterpret_cast<void *>(reinterpret_cast<TextureLoad_t>(
|
||||
Offsets::FUN_TEXTURE_LOAD_BY_PATH)(path, &desc, flags, 0, 1));
|
||||
if (desc.field10 >= 2) {
|
||||
ReleaseHandle(handle);
|
||||
handle = nullptr;
|
||||
reinterpret_cast<SysMsgAdd_t>(Offsets::FUN_SYSMSG_ADD_STATUS)(&desc, 4);
|
||||
}
|
||||
reinterpret_cast<StatusDestroy_t>(Offsets::FUN_FRAMESCRIPT_STATUS_RESET)(&desc);
|
||||
return handle;
|
||||
}
|
||||
using Texture::LoadByPath;
|
||||
using Texture::ReleaseHandle;
|
||||
|
||||
// Drops a region's path mask and its handle reference.
|
||||
void ClearPathMask(void *region) {
|
||||
|
||||
+2
-2
@@ -24,8 +24,8 @@
|
||||
// `Frame::Attributes`' `<Attributes>`), so — like `Frame::RunnerHook` and
|
||||
// `Tick::WorldTick` — this module owns the hook and fans out. Subscribers run
|
||||
// after the engine has loaded the node, in static-init order, which must not
|
||||
// matter; `AutoSubscribeBefore` ones run before it (`Frame::Cooldown` loads
|
||||
// its base template there). The hook also runs the loader through `Xml::Inherits::LoadFrame`,
|
||||
// matter; `AutoSubscribeBefore` ones run before it (`Xml::Mixin` applies a
|
||||
// frame's mixins there). The hook also runs the loader through `Xml::Inherits::LoadFrame`,
|
||||
// which reads `inherits` as a list. Declare a file-scope
|
||||
// static const Xml::FrameLoad::AutoSubscribe _sub{&OnFrameNode};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user