Compare commits
10 Commits
Author | SHA1 | Date | |
---|---|---|---|
5ca5ce8bac | |||
d245d00706 | |||
17d90c2699 | |||
5929cdff5f | |||
5eaf701f91 | |||
11cad0c721 | |||
014cc7dc20 | |||
0802e82456 | |||
c66ce4400e | |||
9517395e1e |
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
_*
|
@ -1,97 +0,0 @@
|
||||
-- Copyright (C) 2025 snoutie
|
||||
-- Authors: snoutie (copyright@achtarmig.org)
|
||||
-- This program is free software: you can redistribute it and/or modify
|
||||
-- it under the terms of the GNU Affero General Public License as published
|
||||
-- by the Free Software Foundation, either version 3 of the License, or
|
||||
-- (at your option) any later version.
|
||||
|
||||
-- This program 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 Affero General Public License for more details.
|
||||
|
||||
-- You should have received a copy of the GNU Affero General Public License
|
||||
-- along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
local M = {}
|
||||
|
||||
M.dependencies = { 'career_career', 'career_modules_computer', 'career_modules_inventory', 'career_modules_payment',
|
||||
'career_modules_playerAttributes' }
|
||||
|
||||
local function tprint(tbl, indent)
|
||||
if not indent then indent = 0 end
|
||||
local toprint = string.rep(" ", indent) .. "{\r\n"
|
||||
indent = indent + 2
|
||||
for k, v in pairs(tbl) do
|
||||
toprint = toprint .. string.rep(" ", indent)
|
||||
if (type(k) == "number") then
|
||||
toprint = toprint .. "[" .. k .. "] = "
|
||||
elseif (type(k) == "string") then
|
||||
toprint = toprint .. k .. "= "
|
||||
end
|
||||
if (type(v) == "number") then
|
||||
toprint = toprint .. v .. ",\r\n"
|
||||
elseif (type(v) == "string") then
|
||||
toprint = toprint .. "\"" .. v .. "\",\r\n"
|
||||
elseif (type(v) == "table") then
|
||||
toprint = toprint .. tprint(v, indent + 2) .. ",\r\n"
|
||||
else
|
||||
toprint = toprint .. "\"" .. tostring(v) .. "\",\r\n"
|
||||
end
|
||||
end
|
||||
toprint = toprint .. string.rep(" ", indent - 2) .. "}"
|
||||
return toprint
|
||||
end
|
||||
|
||||
local function retrieve_favourite()
|
||||
local fav_veh_id = career_modules_inventory.getFavoriteVehicle()
|
||||
local vid = career_modules_inventory.getVehicleIdFromInventoryId(fav_veh_id)
|
||||
|
||||
if vid then
|
||||
local old_veh = be:getObjectByID(vid)
|
||||
old_veh:queueLuaCommand("beamstate.save()")
|
||||
end
|
||||
|
||||
extensions.core_jobsystem.create(
|
||||
function(job)
|
||||
job.sleep(0.2)
|
||||
local veh = career_modules_inventory.spawnVehicle(fav_veh_id, 2)
|
||||
local vehh = be:getObjectByID(career_modules_inventory.getVehicleIdFromInventoryId(fav_veh_id))
|
||||
local location = { pos = vehh:getPosition(), rot = quat(0, 0, 1, 0) * quat(vehh:getRefNodeRotation()) }
|
||||
local garage = career_modules_inventory.getClosestGarage(location.pos)
|
||||
freeroam_facilities.teleportToGarage(garage.id, vehh, false)
|
||||
veh:queueLuaCommand("beamstate.load()")
|
||||
end
|
||||
)
|
||||
end
|
||||
|
||||
local function onComputerAddFunctions(menuData, computerFunctions)
|
||||
if menuData.computerFacility.functions["vehicleInventory"] then
|
||||
local computerFunctionData = {
|
||||
id = "retrieve_damaged",
|
||||
label = "Retrieve Favourite Damaged",
|
||||
callback = retrieve_favourite,
|
||||
order = 1
|
||||
}
|
||||
if menuData.tutorialPartShoppingActive or menuData.tutorialTuningActive then
|
||||
computerFunctionData.disabled = true
|
||||
computerFunctionData.reason = career_modules_computer.reasons.tutorialActive
|
||||
end
|
||||
computerFunctions.general[computerFunctionData.id] = computerFunctionData
|
||||
end
|
||||
end
|
||||
|
||||
local function onSaveCurrentSaveSlot(currentSavePath, oldSaveDate, vehiclesThumbnailUpdate)
|
||||
local vs = career_modules_inventory.getVehicles()
|
||||
for id, _ in pairs(vs) do
|
||||
local vid = career_modules_inventory.getVehicleIdFromInventoryId(id)
|
||||
|
||||
local veh = be:getObjectByID(vid)
|
||||
veh:queueLuaCommand("beamstate.save()")
|
||||
end
|
||||
end
|
||||
|
||||
M.onSaveCurrentSaveSlot = onSaveCurrentSaveSlot
|
||||
M.onComputerAddFunctions = onComputerAddFunctions
|
||||
|
||||
return M
|
99
lua/ge/extensions/career/vehicleRetrieval.lua
Normal file
99
lua/ge/extensions/career/vehicleRetrieval.lua
Normal file
@ -0,0 +1,99 @@
|
||||
-- Copyright (C) 2025 snoutie
|
||||
-- Authors: snoutie (copyright@achtarmig.org)
|
||||
-- This program is free software: you can redistribute it and/or modify
|
||||
-- it under the terms of the GNU Affero General Public License as published
|
||||
-- by the Free Software Foundation, either version 3 of the License, or
|
||||
-- (at your option) any later version.
|
||||
|
||||
-- This program 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 Affero General Public License for more details.
|
||||
|
||||
-- You should have received a copy of the GNU Affero General Public License
|
||||
-- along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
local M = {}
|
||||
|
||||
M.dependencies = { 'career_modules_inventory', 'freeroam_facilities', "career_vehicleSaveSystem",
|
||||
"career_modules_permissions", 'career_modules_valueCalculator' }
|
||||
|
||||
local career_modules_inventory_removeVehicleObject
|
||||
local vehicleObjectsToRemove = {}
|
||||
|
||||
local function spawnVehicle(inventoryId, callback)
|
||||
if career_modules_inventory.getVehicleIdFromInventoryId(inventoryId) then
|
||||
callback()
|
||||
else
|
||||
career_modules_inventory.spawnVehicle(inventoryId, nil, callback)
|
||||
end
|
||||
end
|
||||
|
||||
local function Retrieve(inventoryId)
|
||||
career_vehicleSaveSystem.EnqueueVehicleToSave(inventoryId)
|
||||
if not career_vehicleSaveSystem.SaveVehicle(inventoryId) then
|
||||
career_vehicleSaveSystem.DequeueVehicleToSave(inventoryId)
|
||||
end
|
||||
|
||||
local vehicleValue = career_modules_valueCalculator.getInventoryVehicleValue(inventoryId, true)
|
||||
local currentVehicleValue = career_modules_valueCalculator.getInventoryVehicleValue(inventoryId)
|
||||
|
||||
career_vehicleSaveSystem.CheckSavedAsync(function()
|
||||
extensions.core_jobsystem.create(
|
||||
function(job)
|
||||
career_vehicleSaveSystem.SetFade(true)
|
||||
job.sleep(1)
|
||||
spawnVehicle(inventoryId, function()
|
||||
career_vehicleSaveSystem.TeleportVehicle(inventoryId, false)
|
||||
career_vehicleSaveSystem.LoadVehicle(inventoryId, currentVehicleValue < vehicleValue)
|
||||
end)
|
||||
end
|
||||
)
|
||||
end)
|
||||
end
|
||||
|
||||
local function onComputerAddFunctions(menuData, computerFunctions)
|
||||
if menuData.computerFacility.functions["vehicleInventory"] then
|
||||
local favouriteVehicleId = career_modules_inventory.getFavoriteVehicle()
|
||||
|
||||
local computerFunctionData = {
|
||||
id = "retrieve_damaged",
|
||||
label = "Retrieve Favourite Damaged",
|
||||
callback = function() Retrieve(favouriteVehicleId) end,
|
||||
order = 1
|
||||
}
|
||||
|
||||
local repairPermission = career_modules_permissions.getStatusForTag("vehicleRepair",
|
||||
{ inventoryId = favouriteVehicleId })
|
||||
|
||||
if not repairPermission["allow"] then
|
||||
computerFunctionData.disabled = true
|
||||
computerFunctionData.reason = { type = "text", label = "Vehicle is being repaired." }
|
||||
end
|
||||
|
||||
if menuData.tutorialPartShoppingActive or menuData.tutorialTuningActive then
|
||||
computerFunctionData.disabled = true
|
||||
computerFunctionData.reason = career_modules_computer.reasons.tutorialActive
|
||||
end
|
||||
computerFunctions.general[computerFunctionData.id] = computerFunctionData
|
||||
end
|
||||
end
|
||||
|
||||
local function RemoveVehicleObject(inventoryId)
|
||||
table.insert(vehicleObjectsToRemove, inventoryId)
|
||||
career_vehicleSaveSystem.EnqueueVehicleToSave(inventoryId)
|
||||
career_vehicleSaveSystem.SaveVehicle(inventoryId)
|
||||
career_vehicleSaveSystem.CheckSavedAsync(function()
|
||||
career_modules_inventory_removeVehicleObject(inventoryId)
|
||||
end)
|
||||
end
|
||||
|
||||
local function onCareerActive()
|
||||
career_modules_inventory_removeVehicleObject = career_modules_inventory.removeVehicleObject
|
||||
career_modules_inventory.removeVehicleObject = RemoveVehicleObject
|
||||
end
|
||||
|
||||
M.onComputerAddFunctions = onComputerAddFunctions
|
||||
M.onCareerActive = onCareerActive
|
||||
|
||||
return M
|
248
lua/ge/extensions/career/vehicleSaveSystem.lua
Normal file
248
lua/ge/extensions/career/vehicleSaveSystem.lua
Normal file
@ -0,0 +1,248 @@
|
||||
-- Copyright (C) 2025 snoutie
|
||||
-- Authors: snoutie (copyright@achtarmig.org)
|
||||
-- This program is free software: you can redistribute it and/or modify
|
||||
-- it under the terms of the GNU Affero General Public License as published
|
||||
-- by the Free Software Foundation, either version 3 of the License, or
|
||||
-- (at your option) any later version.
|
||||
|
||||
-- This program 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 Affero General Public License for more details.
|
||||
|
||||
-- You should have received a copy of the GNU Affero General Public License
|
||||
-- along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
local M = {}
|
||||
|
||||
M.dependencies = { 'freeroam_facilities', 'ui_fadeScreen', 'career_career', 'career_saveSystem',
|
||||
'career_modules_inventory' }
|
||||
|
||||
local extensionName = "career_vehicleSaveSystem"
|
||||
local vehicleSaves_temp = "/temp/career/vehicle_saves"
|
||||
|
||||
local function CreateDirectories(dir)
|
||||
local p = path.dirname(dir)
|
||||
if not FS:directoryExists(p) then
|
||||
CreateDirectories(string.sub(p, 1, #p - 1))
|
||||
end
|
||||
FS:directoryCreate(dir)
|
||||
end
|
||||
|
||||
local function ClearDirectory(dir)
|
||||
local files = FS:findFiles(dir .. "/", '*', 0, false, true)
|
||||
for i = 1, tableSize(files) do
|
||||
FS:remove(files[i])
|
||||
end
|
||||
end
|
||||
|
||||
local function CopySaves(from, to)
|
||||
local save_folders = FS:directoryList(from, false, true)
|
||||
for i = 1, tableSize(save_folders) do
|
||||
local folder_dir, folder_name, _ = path.split(save_folders[i])
|
||||
FS:directoryCreate(to .. "/" .. folder_name)
|
||||
local save_files = FS:findFiles(folder_dir .. folder_name .. "/", '*.json', 0, false, false)
|
||||
for n = 1, tableSize(save_files) do
|
||||
local file_dir, file_name, file_ext = path.split(save_files[n])
|
||||
FS:remove(to .. "/" .. folder_name .. "/" .. file_name)
|
||||
FS:copyFile(file_dir .. file_name, to .. "/" .. folder_name .. "/" .. file_name)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function LoadFiles(from)
|
||||
ClearDirectory(vehicleSaves_temp)
|
||||
CopySaves(from, vehicleSaves_temp)
|
||||
end
|
||||
|
||||
local function SaveFiles(to)
|
||||
CopySaves(vehicleSaves_temp, to)
|
||||
end
|
||||
|
||||
local function GetVehicleSaveFile(root, inventoryId)
|
||||
local path = root .. "/" .. inventoryId
|
||||
CreateDirectories(path)
|
||||
|
||||
return path .. "/save.json"
|
||||
end
|
||||
|
||||
local function EnqueueVehicleToSave(inventoryId)
|
||||
log("I", "saving", "enqueued vehicle " .. inventoryId)
|
||||
M.queuedVehicleSaves[inventoryId] = true
|
||||
end
|
||||
|
||||
local function DequeueVehicleToSave(inventoryId)
|
||||
log("I", "saving", "dequeued vehicle " .. inventoryId)
|
||||
M.queuedVehicleSaves[inventoryId] = nil
|
||||
end
|
||||
|
||||
local function TeleportVehicle(inventoryId, delayed, callback)
|
||||
log("I", "loading", "teleporting vehicle " .. inventoryId)
|
||||
|
||||
local veh = be:getObjectByID(career_modules_inventory.getVehicleIdFromInventoryId(inventoryId))
|
||||
local location = { pos = veh:getPosition(), rot = quat(0, 0, 1, 0) * quat(veh:getRefNodeRotation()) }
|
||||
local garage = career_modules_inventory.getClosestGarage(location.pos)
|
||||
|
||||
extensions.core_jobsystem.create(function(job)
|
||||
if delayed then
|
||||
job.sleep(1)
|
||||
end
|
||||
freeroam_facilities.teleportToGarage(garage.id, veh, false)
|
||||
|
||||
if callback then
|
||||
callback()
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
local fadeInProgress = false
|
||||
local function SetFade(fade)
|
||||
if fadeInProgress and fade then
|
||||
return
|
||||
end
|
||||
if not fadeInProgress and not fade then
|
||||
return
|
||||
end
|
||||
if fade then
|
||||
ui_fadeScreen.start(0.5)
|
||||
fadeInProgress = true
|
||||
else
|
||||
ui_fadeScreen.stop(0.5)
|
||||
fadeInProgress = false
|
||||
end
|
||||
end
|
||||
|
||||
local function VehiclesSaved()
|
||||
if next(M.queuedVehicleSaves) == nil then
|
||||
log('I', 'saving', 'all vehicles saved')
|
||||
return true
|
||||
else
|
||||
log('I', 'saving', 'still saving vehicles')
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
local function CheckSavedAsync(callback)
|
||||
extensions.core_jobsystem.create(
|
||||
function(job)
|
||||
while true do
|
||||
if VehiclesSaved() then
|
||||
break
|
||||
end
|
||||
job.sleep(0.1)
|
||||
end
|
||||
if callback then
|
||||
callback()
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
local function SaveVehicle(inventoryId)
|
||||
local saveFile = GetVehicleSaveFile(vehicleSaves_temp, inventoryId)
|
||||
|
||||
local vehicleId = career_modules_inventory.getVehicleIdFromInventoryId(inventoryId)
|
||||
if vehicleId then
|
||||
log('I', 'saving', 'saving vehicle ' .. inventoryId .. " to " .. saveFile)
|
||||
local object = be:getObjectByID(vehicleId)
|
||||
object:queueLuaCommand("beamstate.save(\"" ..
|
||||
saveFile ..
|
||||
"\"); obj:queueGameEngineLua('career_vehicleSaveSystem.DequeueVehicleToSave(" .. inventoryId .. ")');")
|
||||
return true
|
||||
else
|
||||
log('I', 'saving', 'vehicle ' .. inventoryId .. " not spawned")
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
local function FinishedLoading(inventoryId)
|
||||
M.SetFade(false)
|
||||
local veh = be:getObjectByID(career_modules_inventory.getVehicleIdFromInventoryId(inventoryId))
|
||||
local pos, _ = freeroam_facilities.getGaragePosRot(career_modules_inventory.getClosestGarage(), veh)
|
||||
career_modules_playerDriving.showPosition(pos)
|
||||
end
|
||||
|
||||
local function LoadVehicle(inventoryId, loadDamaged)
|
||||
local saveFile = GetVehicleSaveFile(vehicleSaves_temp, inventoryId)
|
||||
|
||||
local vehicleId = career_modules_inventory.getVehicleIdFromInventoryId(inventoryId)
|
||||
if vehicleId then
|
||||
log("I", "loading", "loading vehicle from " .. saveFile)
|
||||
if loadDamaged then
|
||||
local object = be:getObjectByID(vehicleId)
|
||||
object:queueLuaCommand(
|
||||
"beamstate.load(\"" .. saveFile .. "\"); " ..
|
||||
"for key, value in pairs(v.data.controller) do " ..
|
||||
" if value['fileName'] == 'advancedCouplerControl' then " ..
|
||||
" local c = controller.getController(value['name']) " ..
|
||||
" if c['reset'] then " ..
|
||||
" c['reset']() " ..
|
||||
" end " ..
|
||||
" end " ..
|
||||
" end; " ..
|
||||
" obj:queueGameEngineLua(' " ..
|
||||
" career_vehicleSaveSystem.TeleportVehicle( " ..
|
||||
" " .. inventoryId .. ", " ..
|
||||
" true, " ..
|
||||
" function() " ..
|
||||
" career_vehicleSaveSystem.FinishedLoading(" .. inventoryId .. ")" ..
|
||||
" end) " ..
|
||||
" ');"
|
||||
)
|
||||
else
|
||||
FinishedLoading(inventoryId)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function onSaveCurrentSaveSlotAsyncStart()
|
||||
career_saveSystem.registerAsyncSaveExtension(extensionName)
|
||||
end
|
||||
|
||||
local function onSaveCurrentSaveSlot(currentSavePath, oldSaveDate, vehiclesThumbnailUpdate)
|
||||
local vehicles = career_modules_inventory.getVehicles()
|
||||
|
||||
for id, _ in pairs(vehicles) do
|
||||
EnqueueVehicleToSave(id)
|
||||
end
|
||||
|
||||
for id, _ in pairs(M.queuedVehicleSaves) do
|
||||
if not SaveVehicle(id) then
|
||||
DequeueVehicleToSave(id)
|
||||
end
|
||||
end
|
||||
CheckSavedAsync(function()
|
||||
SaveFiles(currentSavePath .. "/career/vehicle_saves")
|
||||
career_saveSystem.asyncSaveExtensionFinished(extensionName)
|
||||
end)
|
||||
end
|
||||
|
||||
local function onCareerActive()
|
||||
local _, saveSlot = career_saveSystem.getCurrentSaveSlot()
|
||||
local vehicleSaves_saveSlot = saveSlot .. "/career/vehicle_saves"
|
||||
|
||||
CreateDirectories(vehicleSaves_saveSlot)
|
||||
CreateDirectories(vehicleSaves_temp)
|
||||
|
||||
LoadFiles(vehicleSaves_saveSlot)
|
||||
end
|
||||
|
||||
M.queuedVehicleSaves = {}
|
||||
|
||||
M.SaveVehicle = SaveVehicle
|
||||
M.LoadVehicle = LoadVehicle
|
||||
M.FinishedLoading = FinishedLoading
|
||||
|
||||
M.TeleportVehicle = TeleportVehicle
|
||||
|
||||
M.SetFade = SetFade
|
||||
|
||||
M.CheckSavedAsync = CheckSavedAsync
|
||||
|
||||
M.EnqueueVehicleToSave = EnqueueVehicleToSave
|
||||
M.DequeueVehicleToSave = DequeueVehicleToSave
|
||||
|
||||
M.onSaveCurrentSaveSlotAsyncStart = onSaveCurrentSaveSlotAsyncStart
|
||||
M.onSaveCurrentSaveSlot = onSaveCurrentSaveSlot
|
||||
M.onCareerActive = onCareerActive
|
||||
|
||||
return M
|
@ -15,12 +15,14 @@
|
||||
|
||||
local M = {}
|
||||
|
||||
M.dependencies = { 'career_career', 'career_modules_payment', 'career_modules_playerAttributes' }
|
||||
M.dependencies = { 'career_career' }
|
||||
|
||||
extensions.load("career_retrievedamaged")
|
||||
extensions.load("career_vehicleSaveSystem")
|
||||
extensions.load("career_vehicleRetrieval")
|
||||
|
||||
M.onInit = function()
|
||||
setExtensionUnloadMode(M, "manual")
|
||||
end
|
||||
|
||||
|
||||
return M
|
||||
|
Loading…
Reference in New Issue
Block a user