MetaDen Restorations Changelog
All notable changes to this project are documented in this file.
[0.4.5] - 2026-03-22
Added
- Admin "Move to me" action (
server/admin.lua,client/admin.lua,client/restoration.lua,ui/src/pages/ActiveWrecksPage.tsx):- New Move button on each row of the Active Wrecks admin page teleports a wreck to the admin's current position.
- Server callback
metaden-restoration:admin:moveWreckupdates DB coordinates (wrecks + zones) and broadcasts the change. - New
metaden-restoration:client:RelocateWreckevent cleans up the old entity/zone and creates a fresh streaming zone at the new location.
- Styled CSS tooltips on admin action buttons (
ui/src/pages/ActiveWrecksPage.tsx):- Replaced native
titleattributes with themed hover tooltips using Tailwindgroup/group-hoverpattern.
- Replaced native
Changed
- Crafting bench access logic (
client/client.lua,server/server.lua):- Empty or nil
JobWhitelistnow means unrestricted access (previously blocked everyone). - Server returns
-1sentinel for scrapping level whenmetaden-skillsis unavailable, allowing the client to skip the skill gate entirely.
- Empty or nil
- Entity tracking sync on hoist movement (
client/restoration.lua):updateWreckLocationnow detects whenCreatePropIfNeededhas replaced the entity handle and syncsloadedWrecks/OwnedWreckstracking tables accordingly, deleting the old underground entity.
Fixed
- Hoist wreck not visible after placement (
client/restoration.lua):- Hoist move updated the entity position but never recreated the streaming zone; the wreck was invisible until relog.
RelocateWrecknow handles full zone lifecycle.
- Hoist move updated the entity position but never recreated the streaming zone; the wreck was invisible until relog.
- Wreck collision after hoist release (
client/client.lua):- Corrected
ReleaseWreckFromHoistto applySetEntityCollisionbeforeFreezeEntityPositionto prevent the prop falling through the ground.
- Corrected
utilsnil global error (client/client.lua):- Fixed case mismatch —
utils.materialNameToItemName→Utils.materialNameToItemName(shared export uses capitalU).
- Fixed case mismatch —
buildLegacyWreckKeynil in admin.lua (server/admin.lua):- Added local copies of
normalizeCoord,buildLegacyWreckKey, andbuildNormalizedWreckKeysinceadmin.lualoads alphabetically beforeserver.lua.
- Added local copies of
- Admin move wreck not spawning (
client/restoration.lua):RemoveWreckdeleted both entity and zone but nothing recreated them. Replaced withRelocateWreckwhich cleans up and creates a fresh streaming zone.
- Duplicate wreck after hoist + admin move (
client/restoration.lua):- Fixed Lua type mismatch: NUI sends
wreckIdas string butOwnedWrecksstores numbers —tonumber()normalization added. - Removed if/else short-circuit that skipped
OwnedWreckssweep whenloadedWrecksentry was found.
- Fixed Lua type mismatch: NUI sends
Removed
AdminModelCommandconfig and/restoration_addmodelchat command (config.lua,server/server.lua,server/admin.lua,client/admin.lua):- Fully superseded by the Model Pool page in the admin UI.
[0.4.4] - 2026-03-06
Added
- Trader Store (
config.lua,server/server.lua,server/admin.lua,client/trader.lua,client/admin.lua,ui/):- New Browse Store target option on the trader ped — players can purchase parts and materials directly from the trader.
- Store items are stored in a new
veh_restoration_store_itemsdatabase table. - Stock tracking with optional maximum stock and lazy restock: stock is topped up automatically the next time the store is opened (no background polling loop).
- Optional
conditionmetadata — if set, sold items receive aConditionmetadata tag (e.g.condition = 75→{ Condition = '75%' }). - Seed items seeded on resource start from
Config.TraderPed.Store.ItemsviaINSERT IGNORE(item name is the unique key); all live values are managed in-game via the admin panel. Store.Enabledconfig flag — setfalseto completely hide the target option.- Five new admin callbacks (
admin:getStoreItems,admin:addStoreItem,admin:updateStoreItem,admin:removeStoreItem,admin:restockStoreItem) backed by the admin ACE check. - New Store page in the admin NUI panel: summary stats (total items, unlimited-stock count, out-of-stock count), paginated table with stock badges, and per-row edit / manual-restock / delete actions.
- Migration SQL (
migrations/2026-03-06-store-items.sql):CREATE TABLE IF NOT EXISTS veh_restoration_store_items.
- Data migration SQL (
migrations/2026-03-06-material-keys-item-names.sql):- Converts legacy
veh_restoration_wrecks.state.materialskeys to new direct item-name keys. - Covers legacy keys including
seats,axle,tires,sparkPlugs,oilPump,driveShaft,cylinderHead,batteryCables,fuelTank, andmetal.
- Converts legacy
Changed
- Hard cutover to direct item-name material keys (
config.lua,shared/utils.lua,server/*.lua,client/restoration.lua):- Removed
MaterialToItemMapindirection from restoration flow. - Material keys now directly match inventory item names (for example
tire,sparkplugs,axleparts,oil_pump,metalscrap). ITEM_CONTRACT.Materials, per-type requirement tables, stage transitions, and restoration section dependencies now use direct item keys.
- Removed
- Currency picker simplified in admin UI (
ui/src/pages/ModelPoolPage.tsx,ui/src/pages/StorePage.tsx):- Removed the hardcoded
Gold Coin (item)preset from the currency selector. - The three options are now: Cash, Bank, and Item… (free-text input for any inventory item name).
- Removed the hardcoded
Breaking
- Servers upgrading from pre-
0.4.4must run the migration SQL before going live if they want to preserve active restoration progress.
[0.4.3] - 2026-03-06
Added
- Trader Tips & FAQ menu (
shared/trader_tips.lua,client/trader.lua):- Added a dedicated
Tips & FAQtrader target option. - Added a config-backed FAQ source file (
shared/trader_tips.lua) exposed asConfig.TraderPed.Tips. - Tips are shown in a context menu and open into per-topic dialogs for readability.
- Seeded with guidance for:
- where to get an
engine_hoist - how to grab/move wrecks (tow truck + hoist flows)
- why adding materials can fail (missing item, unmet dependencies, item condition expectations)
- where to get an
- Added a dedicated
- Context-aware restoration blocker hints (
client/restoration.lua):- Material menu entries now show dynamic blocker hints (for example
Complete first: ...orMissing item: ...). - Selecting a blocked material now explains the exact reason instead of failing with a generic message.
- Material menu entries now show dynamic blocker hints (for example
Changed
- Item setup discoverability and contract centralization (
config.lua,shared/utils.lua,server/server.lua,README.md):- Introduced
ITEM_CONTRACTas the single naming contract for restoration materials/items. Config.Materials,Config.MaterialToItemMap, andConfig.RawMaterialsnow derive from that contract.- Added
Config.RequiredInventoryItemsand startup validation logging to detect config/inventory drift early. - Documented item setup entrypoint and compatibility mapping (
tiresmaterial ->tireinventory item).
- Introduced
- Flatbed release configuration surface (
config.lua,README.md):- Added tunables for flatbed drop behavior and occupancy checks:
FlatbedDropDistanceBehindFlatbedDropClearanceRadiusFlatbedDropCheckVehiclesFlatbedDropCheckObjects
- Added tunables for flatbed drop behavior and occupancy checks:
Fixed
- Missing restoration-related inventory items (
inventory/ox_inventory.lua):- Added missing
fiberandcarbonentries expected by config reward/crafting flows. - Removed orphaned
ironfrom this resource inventory set.
- Added missing
- Flatbed release false-positive blocking (
client/client.lua):- Removed unreliable native occupancy call path that produced blocked releases in clear spaces.
- Reworked clearance checks to use deterministic nearby entity scans.
- Flatbed drop spawning under/inside tow truck (
client/client.lua):- Drop position now uses a model-aware minimum behind-distance based on flatbed dimensions.
- Uses entity-relative world offset placement so drop consistently resolves behind the bed.
- Flatbed occupancy checks missing real collisions (
client/client.lua):- Clearance now uses entity footprint radius from model dimensions (not just entity origin point distance).
- Object checks now evaluate all nearby objects instead of networked/mission-only filtering.
Upgrade Notes
- New config keys available:
FlatbedDropDistanceBehindFlatbedDropClearanceRadiusFlatbedDropCheckVehiclesFlatbedDropCheckObjects
- Trader FAQ content now lives in
shared/trader_tips.luaand is read asConfig.TraderPed.Tips. - Behavior change: blocked restoration materials are now selectable to show precise guidance (dependencies/missing item) instead of silently appearing unavailable.
- Behavior change: flatbed release now enforces occupancy checks and uses a model-aware drop point behind the truck.
- Recommended post-update check: restart the resource and verify startup logs for item contract validation output.
[0.4.2] - 2026-03-03
Fixed
CancelRestorationwreck not deleted from world (client/restoration.lua):- The entity reference passed from the ox_target
onSelectclosure became stale after the 15-secondalertDialog+progressBarawait chain. The function now resolves the authoritative entity fromloadedWrecks[wreckId]first, falling back to the closure-captured handle only if the table entry is absent. loadedWrecks[wreckId]was never set tonilafterDeleteEntity, allowing zone re-entry to bypass the duplicate-spawn guard inloadWreckand recreate the prop. Now explicitly nilled.OwnedWrecks[entity]was never cleared, leaving a dead handle that could allow zone re-entry to queue anotherrequestLoadWreck. Now explicitly nilled.loadedZones[wreckId]was removed via:remove()but not nilled, causing theRemoveWreckserver event handler to call:remove()a second time on the already-dead zone object. Now nilled immediately after removal.restorationDatawas not cleared after cancellation, leaving stale ownership/progress state visible inSetupTargetOptionsandcalculateProgress. Now reset to{}.- The server event was incorrectly referencing
restorationData.id(outer upvalue, potentially stale at time of execution) instead of thewreckIdparameter captured at call time.
- The entity reference passed from the ox_target
CancelRestorationanimation hung indefinitely (client/restoration.lua):- The previous animation dict (
anim@melee@large_wpn@streamed@attack) is a streamed dict that cannot be loaded in a normalRequestAnimDictloop. Thewhile not HasAnimDictLoaded do Wait(0) endloop hung forever, blockingTaskPlayAnimand theprogressBarcall that follows, making the destroy flow appear completely unresponsive. - Replaced with
mini@repair/fixing_a_ped(the same reliable dict used elsewhere in this file). - Added a 5-second timeout to the anim dict load loop, consistent with the model-loading pattern used throughout the file.
TaskPlayAnimis now guarded onHasAnimDictLoadedso a timeout does not error.
- The previous animation dict (
- Metabridge callback race condition (
fxmanifest.lua):@ox_lib/init.luaandox_libdependency were removed in 0.4.0 as part of the full metabridge abstraction. However, withoutlibavailable in this resource's Lua state,MetaBridgeClient.requestCallbackAwaitcould not use thelib.callback.awaitfast path and fell through toTriggerServerEvent('MetaBridge:invokeCallback', ...). Combined with the metabridge 1.0.4 fix (invokeCallback now silently returns on missing callbacks), callbacks now resolve correctly via the fallback path.- Restored
'@ox_lib/init.lua'as the first entry inshared_scriptsand'ox_lib'todependenciessolib.callback.await / lib.callback.registerare used on both the client and server, bypassing the bridge event bus entirely for all callbacks.
[0.4.1] - 2026-03-03
Added
- Pre-completion system (
config.lua,server/server.lua):- When a new wreck is created, a random percentage of its required material/part slots are pre-filled with a random partial amount (between 1 and the required count for that slot).
- Trader-purchased wrecks use a higher configured percentage range than world wrecks, so bought wrecks feel more complete from the start.
- The slot selection always guarantees at least one raw-material slot and at least one part slot are included when enough slots are being pre-filled and both categories exist for the wreck type.
- Configured via
Config.PreCompletion:Enabled— set tofalseto disable entirely.WorldWreck = { MinPercent = 0, MaxPercent = 20 }— wrecks started in the open world.TraderWreck = { MinPercent = 20, MaxPercent = 50 }— wrecks purchased from the trader.
- New internal helper
generatePrecompletedState(wreckType, minPercent, maxPercent)on the server (not exported).
- Mission shortcut in Browse Wrecks menu (
client/trader.lua):- A Request Mission entry is injected at the top of the Browse Wrecks context menu so players can request a mission without needing a separate ped interaction.
- Visibility is gated at menu-open time via
GetResourceState('metaden-skills') == 'started'(in addition toConfig.TraderPed.Skills.Enabled), so the option disappears automatically if the resource is not running.
- Mission deduplication (
server/server.lua):- Before assigning a mission the server queries
metaden_player_missionsfor all missions the player already hasactive. - The candidate pool is shuffled and the first mission the player does not already hold is selected.
- If every configured mission is already active, the callback returns
{ success = false, reason = 'You already have all available missions active.' }and the player is notified accordingly.
- Before assigning a mission the server queries
[0.4.0] - 2026-02-27
Added
- Trader Ped (
client/trader.lua):- Spawns via a metabridge proximity point — only created when the player is within
Config.TraderPed.SpawnRadius(default 30 m, actual spawn at 15 m). - Configured entirely in
Config.TraderPed(model, coords, spawn radius, delivery coords, skills settings). - Browse Wrecks target option — opens a context menu of purchasable wrecks from the model pool with price display.
- Request Mission target option — assigns a random restoration mission via
metaden-skills(shown only whenConfig.TraderPed.Skills.Enabled = trueand the resource is running).
- Spawns via a metabridge proximity point — only created when the player is within
- Wreck purchase system (
server/server.lua):- New server callback
metaden-restoration:server:getWrecksForSale— returns pool entries whereprice > 0. - New server callback
metaden-restoration:server:buyWreck— validates limits, deducts payment, consumes the pool row, inserts the wreck/zone records, and firesloadWreckdirectly to the buyer. - Payment resolves through
Config.CurrencyMap— supports ox_inventory items (e.g.money) and framework money accounts (e.g.bank) configured per currency label. - Initial wreck prop is derived from
wreckTypeat purchase time, not from the vehicle model name.
- New server callback
- Mission assignment callback (
metaden-restoration:server:requestRestorationMission) — picks randomly fromConfig.TraderPed.Skills.Missionsand callsexports['metaden-skills']:AssignMissionToPlayer. - Admin NUI panel (
client/admin.lua,server/admin.lua,ui/):- Model Pool page — view, add, and remove entries from
veh_restoration_model_poolwith wreck type, model, price, and currency fields. - Missions page — assign a
metaden-skillsmission to any player by citizen ID. - Player Stats page — per-player lookup and global leaderboard with dual animated progress bars (wrecks + resources), by-type bar chart, and character name display.
- Active Wrecks page — view all live wrecks with restoration progress, set waypoint to any wreck, and force-delete wrecks.
- Leaderboard rows show character first and last name (resolved via
players.charinfo) alongside citizen ID. - Rank colouring: gold
#1, silver#2, bronze#3. - Themed to MetaDen brand: cyan
#00d4ff, purple#7c5cff, pink#ff4fd8.
- Model Pool page — view, add, and remove entries from
Changed
- Full metabridge abstraction —
ox_libandox_targetare no longer hard dependencies of this resource. Every previously directlib.*andexports.ox_target:*call now goes throughMetaBridgeClient.*:- Progress bars, context menus, and alert dialogs →
MetaBridgeClient.progressBar / registerContext / showContext / alertDialog. - Entity targets (local entity add/remove, model add/remove, box zones) →
MetaBridgeClient.addTargetLocalEntity / removeTargetLocalEntity / addTargetModel / removeTargetModel / addTargetBoxZone. - Proximity sphere zones (wreck streaming) →
MetaBridgeClient.addZoneSphere. - Proximity points (trader ped spawn) →
MetaBridgeClient.addPoint. - Model loading in trader ped spawn →
MetaBridgeClient.requestModel.
- Progress bars, context menus, and alert dialogs →
fxmanifest.luaupdated:@ox_lib/init.luaremoved fromshared_scripts;ox_libandox_targetremoved fromdependencies. Onlymetabridge(andoxmysql) remain as explicit dependencies.Config.CurrencyMapintroduced — maps currency labels used in the model pool to the actual framework money type and whether it is an inventory item:cash = { value = 'money', item = true }— routes to ox_inventorymoneyitem balance.bank = { value = 'bank', item = false }— routes to framework bank account.
WreckedBikespool cleaned up — removedbkr_int_01_bike(interior mesh, not a valid world prop). Onlyprop_rub_bike_03is valid for spawnable bike wrecks.- Admin callbacks enforce ACE checks server-side only;
IsPlayerAceAllowedis no longer called from the client.
Database
veh_restoration_model_pool— addedprice INT UNSIGNED DEFAULT 0andcurrency VARCHAR(50) DEFAULT 'cash'columns.- Added index
idx_veh_restoration_model_pool_price. admin:getPlayerStatsandadmin:getAllPlayerStatsnow JOINplayersoncitizenidto returnfirstNameandlastNamefromcharinfo.
[0.3.0] - 2026-02-23
Added
- Weighted progress configuration via
Config.ProgressWeights:- raw materials contribution (default
20%) - parts contribution (default
80%)
- raw materials contribution (default
- Admin rare-model injection command:
/restoration_addmodel <car|bike|pickup|van> <modelName>- ACE permission configurable via
Config.AdminModelCommand.AcePermission.
- Consumable rare-model queue table:
veh_restoration_model_pool. - Persistent restoration ranking tables:
veh_restoration_player_statsveh_restoration_player_type_stats.
- Ranking callbacks:
metaden-restoration:server:getPlayerRankingStats(targetCitizenId?)metaden-restoration:server:getRankingLeaderboard(wreckType?, limit?).
- Mission stat publishing hooks for
metaden-skillsintegration:- search totals/by type
- materials added totals/by key
- restoration completions totals/by type.
Changed
- Server-side progress calculation now uses weighted group progress instead of pure amount totals.
- Client-side displayed progress now matches the server weighted calculation.
- New restorations now consume a queued rare model first (if available), then fallback to config model lists.
Database
- Added
veh_restoration_model_pooltable and index. - Added
veh_restoration_player_statsandveh_restoration_player_type_statstables with leaderboard indexes.
[0.2.0] - 2026-02-21
Added
- Configurable active restoration limits:
MaxWrecksPerPlayerMaxWrecksByRole
- Restoration expiration cleanup on resource start via
ExpirationDays. - Multi-wreck ownership model with
ownerCitizenIdand unique wreck IDs. - Normalized wreck key tracking (
wreckKeyNormalized) to stabilize moved-wreck lookups. - Config-driven restoration sections with
MaterialMenuSectionsByType(Default,Car,Bike,Pickup,Van).
Changed
- Removed direct framework coupling from restorations flow and aligned player/job/identifier handling to bridge APIs.
- Removed direct inventory coupling from restorations flow and migrated item checks/removals/metadata handling through bridge methods.
- Completion flow now uses bridge vehicle ownership/spawn APIs.
- Wreck ownership checks now validate against
ownerCitizenIdand wreck ID references.
Database
- Added/used
ownerCitizenIdonveh_restoration_wrecks. - Added/used
wreckKeyNormalizedonveh_restoration_wrecks. - Added owner/key/timestamp indexes for restoration lookup and cleanup performance.
- Updated zone relation/indexing to use wreck IDs consistently.
Breaking
MaterialMenuSectionsis replaced byMaterialMenuSectionsByType.- Existing configs must be updated to the new menu section format.
- This release assumes bridge-based inventory methods are available for active inventory adapter.
