From 3386d0daa578571ae2878b2632f783bb06957cc9 Mon Sep 17 00:00:00 2001 From: mrSkortch Date: Sun, 8 May 2016 04:20:52 -0600 Subject: [PATCH] Update DB slightRefactor-start Update not pushed live at time of update due to a few bugs. Wanted to get commit in. Fixed typo with mist.utils.NMToMeters causing function not to work. added Logger 'dbLog' to mist DB code inserted do-end blocks to make DB code block shorter in length Purpose of DB updating refactor is to more accurately keep unit tables updated correctly. In the old system only 'byName' DBs were updated if a group/unit name was duplicated. So it was possible for multiple units to share the same name in unitsByNum, byCat, etc. The process of how it checks added groups and units has been altered slightly. Groups spawned with player controlled units will not be updated. The conditions for whether or not the table gets updated are as follows: If groupName is already in DB then check if its groupId, country, or coalition changed. If nothing has changed then it checks if the newly spawned units exist in a DB entry and if so it will verify if the unitId ort ype have changed. Any single update prompts the DB to update accordingly. --- mist.lua | 291 +++++++++++++++++++++++++++++++++---------------------- 1 file changed, 173 insertions(+), 118 deletions(-) diff --git a/mist.lua b/mist.lua index 1dfed03..0977370 100644 --- a/mist.lua +++ b/mist.lua @@ -35,7 +35,7 @@ mist = {} -- don't change these mist.majorVersion = 4 mist.minorVersion = 2 -mist.build = 66 +mist.build = 68 -- forward declaration of log shorthand local log @@ -44,6 +44,9 @@ do -- the main scope local coroutines = {} local tempSpawnedUnits = {} -- birth events added here + local tempSpawnedGroups = {} + local tempSpawnGroupsCounter = 0 + local mistAddedObjects = {} -- mist.dynAdd unit data added here local mistAddedGroups = {} -- mist.dynAdd groupdata added here local writeGroups = {} @@ -64,6 +67,8 @@ do -- the main scope mist.nextGroupId = 1 mist.nextUnitId = 1 + local dbLog + local function initDBs() -- mist.DBs scope mist.DBs = {} @@ -368,7 +373,7 @@ do -- the main scope mist.DBs.unitsByCat[unit_data.category] = mist.DBs.unitsByCat[unit_data.category] or {} -- future-proofing against new categories... table.insert(mist.DBs.unitsByCat[unit_data.category], mist.utils.deepCopy(unit_data)) - --log:info('inserting $1', unit_data.unitName) + dbLog:info('inserting $1', unit_data.unitName) table.insert(mist.DBs.unitsByNum, mist.utils.deepCopy(unit_data)) if unit_data.skill and (unit_data.skill == "Client" or unit_data.skill == "Player") then @@ -405,13 +410,13 @@ do -- the main scope local original_key = key --only for duplicate runtime IDs. local key_ind = 1 while mist.DBs.deadObjects[key] do - --log:warn('duplicate runtime id of previously dead object key: $1', key) + dbLog:warn('duplicate runtime id of previously dead object key: $1', key) key = tostring(original_key) .. ' #' .. tostring(key_ind) key_ind = key_ind + 1 end if mist.DBs.aliveUnits and mist.DBs.aliveUnits[val.object.id_] then - --log:info('object found in alive_units') + --dbLog:info('object found in alive_units') val.objectData = mist.utils.deepCopy(mist.DBs.aliveUnits[val.object.id_]) local pos = Object.getPosition(val.object) if pos then @@ -420,7 +425,7 @@ do -- the main scope val.objectType = mist.DBs.aliveUnits[val.object.id_].category elseif mist.DBs.removedAliveUnits and mist.DBs.removedAliveUnits[val.object.id_] then -- it didn't exist in alive_units, check old_alive_units - --log:info('object found in old_alive_units') + --dbLog:info('object found in old_alive_units') val.objectData = mist.utils.deepCopy(mist.DBs.removedAliveUnits[val.object.id_]) local pos = Object.getPosition(val.object) if pos then @@ -429,13 +434,13 @@ do -- the main scope val.objectType = mist.DBs.removedAliveUnits[val.object.id_].category else --attempt to determine if static object... - --log:info('object not found in alive units or old alive units') + --dbLog:info('object not found in alive units or old alive units') local pos = Object.getPosition(val.object) if pos then local static_found = false for ind, static in pairs(mist.DBs.unitsByCat.static) do if ((pos.p.x - static.point.x)^2 + (pos.p.z - static.point.y)^2)^0.5 < 0.1 then --really, it should be zero... - --log:info('correlated dead static object to position') + dbLog:info('correlated dead static object to position') val.objectData = static val.objectPos = pos.p val.objectType = 'static' @@ -489,7 +494,7 @@ do -- the main scope if lunits[i].category ~= 'static' then -- can't get statics with Unit.getByName :( local unit = lUnit.getByName(lunits[i].unitName) if unit then - --log:info("unit named $1 alive!", lunits[i].unitName) -- spammy + --dbLog:info("unit named $1 alive!", lunits[i].unitName) -- spammy local pos = unit:getPosition() local newtbl = ldeepcopy(lunits[i]) if pos then @@ -515,19 +520,16 @@ do -- the main scope end end - local function dbUpdate(event) + local function dbUpdate(event, objType) + dbLog:info('dbUpdate') local newTable = {} - newTable.startTime = 0 - if type(event) == 'string' then -- if name of an object. local newObject - local newType = 'group' if Group.getByName(event) then newObject = Group.getByName(event) elseif StaticObject.getByName(event) then newObject = StaticObject.getByName(event) - newType = 'static' -- log:info('its static') else log:info('WTF') @@ -538,7 +540,7 @@ do -- the main scope newTable.groupId = tonumber(newObject:getID()) newTable.groupName = newObject:getName() local unitOneRef - if newType == 'static' then + if objType == 'static' then unitOneRef = newObject newTable.countryId = tonumber(newObject:getCountry()) newTable.coalitionId = tonumber(newObject:getCoalition()) @@ -561,11 +563,11 @@ do -- the main scope end end for catData, catId in pairs(Unit.Category) do - if newType == 'group' and Group.getByName(newTable.groupName):isExist() then + if objType == 'group' and Group.getByName(newTable.groupName):isExist() then if catId == Group.getByName(newTable.groupName):getCategory() then newTable.category = string.lower(catData) end - elseif newType == 'static' and StaticObject.getByName(newTable.groupName):isExist() then + elseif objType == 'static' and StaticObject.getByName(newTable.groupName):isExist() then if catId == StaticObject.getByName(newTable.groupName):getCategory() then newTable.category = string.lower(catData) end @@ -592,7 +594,7 @@ do -- the main scope end newTable.units = {} - if newType == 'group' then + if objType == 'group' then for unitId, unitData in pairs(unitOneRef) do newTable.units[unitId] = {} newTable.units[unitId].unitName = unitData:getName() @@ -684,91 +686,92 @@ do -- the main scope newTable.timeAdded = timer.getAbsTime() -- only on the dynGroupsAdded table. For other reference, see start time --mist.debug.dumpDBs() --end - + dbLog:info('endDbUpdate') return newTable end - local function checkSpawnedEvents() - if #tempSpawnedUnits > 0 then - local groupsToAdd = {} - local added = false - local ltemp = tempSpawnedUnits - local ltable = table - - local updatesPerRun = math.ceil(#tempSpawnedUnits/20) + --[[DB update code... FRACK. I need to refactor some of it. + + The problem is that the DBs need to account better for shared object names. Needs to write over some data and outright remove other. + + If groupName is used then entire group needs to be rewritten + what to do with old groups units DB entries?. Names cant be assumed to be the same. + + + -- new spawn event check. + -- event handler filters everything into groups: tempSpawnedGroups + -- this function then checks DBs to see if data has changed + ]] + local function checkSpawnedEventsNew() + if tempSpawnedGroupsCounter > 0 then + --[[local updatesPerRun = math.ceil(#tempSpawnedGroupsCounter/20) if updatesPerRun < 5 then updatesPerRun = 5 - end - for x = 1, #tempSpawnedUnits do - local spawnedObj = ltemp[x] - if spawnedObj and spawnedObj:isExist() then - local found = false - for name, val in pairs(groupsToAdd) do - if spawnedObj:getCategory() == 1 then -- normal groups - if mist.stringMatch(spawnedObj:getGroup():getName(), name) == true then - found = true - break - end - elseif spawnedObj:getCategory() == 3 or spawnedObj:getCategory() == 6 then -- static objects - if mist.stringMatch(spawnedObj:getName(), name) == true then - found = true + end]] + + dbLog:info('iterate') + for name, gType in pairs(tempSpawnedGroups) do + dbLog:info(name) + local updated = false + + if mist.DBs.groupsByName[name] then + -- first check group level properties, groupId, countryId, coalition + dbLog:info('Found in DBs, check if updated') + local dbTable = mist.DBs.groupsByName[name] + local _u + if gType ~= 'static' then + local _g = Group.getByName(name) + _u = _g:getUnit(1) + if dbTable.groupId ~= _g:getID() or _u:getCountry() ~= dbTable.countryId or _u:getCoalition() ~= coalition.side[string.upper(dbTable.coaltionId)] then + dbLog:info('Group Data mismatch') + updated = true + end + + end + end + + if updated == false and gType ~= 'static' then -- time to check units + dbLog:info('No Group Mismatch, Check Units') + for index, uObject in pairs(Group.getByName(name):getUnits()) do + dbLog:info(index) + if mist.DBs.unitsByName[uObject:getName()] then + dbLog:info('UnitByName table exists') + local uTable = mist.DBs.unitsByName[uObject:getName()] + if uObject:getID() ~= uTable.unitId or uObject:getTypeName() ~= uTable.type then + dbLog:info('Unit Data mismatch') + updated = true break end end end - -- for some reason cargo objects are returning as category == 6. - if found == false then - added = true - if spawnedObj:getCategory() == 1 then -- normal groups - groupsToAdd[spawnedObj:getGroup():getName()] = true - elseif spawnedObj:getCategory() == 3 or spawnedObj:getCategory() == 6 then -- static objects - groupsToAdd[spawnedObj:getName()] = true - end - - end end - - table.remove(ltemp, x) - if x%updatesPerRun == 0 then - coroutine.yield() + + if updated == true or not mist.DBs.groupsByName[name] then + dbLog:info('Get Table') + writeGroups[#writeGroups+1] = {data = dbUpdate(name, gType), isUpdated = updated} + end - end - - if added == true then - for groupName, val in pairs(groupsToAdd) do - local dataChanged = false - if mist.DBs.groupsByName[groupName] then - for _index, data in pairs(mist.DBs.groupsByName[groupName]) do - if data.unitName ~= spawnedObj:getName() and data.unitId ~= spawnedObj:getID() and data.type ~= spawnedObj:getTypeName() then - dataChanged = true - break - end - end - if dataChanged == false then - groupsToAdd[groupName] = false - end - end - if groupsToAdd[groupName] == true or not mist.DBs.groupsByName[groupName] then - writeGroups[#writeGroups + 1] = dbUpdate(groupName) - end - end - end - end + -- Work done, so remove + tempSpawnedGroups[name] = nil + tempSpawnedGroupsCounter = tempSpawnedGroupsCounter - 1 + end + end end - + local function updateDBTables() - local i = 0 - for index, newTable in pairs(writeGroups) do - i = i + 1 - end + local i = #writeGroups + local savesPerRun = math.ceil(i/10) if savesPerRun < 5 then savesPerRun = 5 end if i > 0 then + dbLog:info('updateDBTables') local ldeepCopy = mist.utils.deepCopy for x = 1, i do - local newTable = writeGroups[x] + dbLog:info(writeGroups[x]) + local newTable = writeGroups[x].data + local updated = writeGroups[x].isUpdated local mistCategory if type(newTable.category) == 'string' then mistCategory = string.lower(newTable.category) @@ -787,17 +790,43 @@ do -- the main scope mistCategory = 'ship' newTable.category = mistCategory end + dbLog:info('Update unitsBy') for newId, newUnitData in pairs(newTable.units) do + dbLog:info(newId) newUnitData.category = mistCategory if newUnitData.unitId then + dbLog:info('byId') mist.DBs.unitsById[tonumber(newUnitData.unitId)] = ldeepCopy(newUnitData) end - + dbLog:info(updated) + if mist.DBs.unitsByName[newUnitData.unitName] and updated == true then--if unit existed before and something was updated, write over the entry for a given unit name just in case. + dbLog:info('Updating Unit Tables') + for i = 1, #mist.DBs.unitsByCat[mistCategory] do + if mist.DBs.unitsByCat[mistCategory][i].unitName == newUnitData.unitName then + dbLog:info('Entry Found, Rewriting for unitsByCat') + mist.DBs.unitsByCat[mistCategory][i] = ldeepCopy(newUnitData) + break + end + end + for i = 1, #mist.DBs.unitsByNum do + if mist.DBs.unitsByNum[i].unitName == newUnitData.unitName then + dbLog:info('Entry Found, Rewriting for unitsByNum') + mist.DBs.unitsByNum[i] = ldeepCopy(newUnitData) + break + end + end + + else + dbLog:info('Unitname not in use, add as normal') + mist.DBs.unitsByCat[mistCategory][#mist.DBs.unitsByCat[mistCategory] + 1] = ldeepCopy(newUnitData) + mist.DBs.unitsByNum[#mist.DBs.unitsByNum + 1] = ldeepCopy(newUnitData) + end mist.DBs.unitsByName[newUnitData.unitName] = ldeepCopy(newUnitData) - mist.DBs.unitsByCat[mistCategory][#mist.DBs.unitsByCat[mistCategory] + 1] = ldeepCopy(newUnitData) - mist.DBs.unitsByNum[#mist.DBs.unitsByNum + 1] = ldeepCopy(newUnitData) + + end -- this is a really annoying DB to populate. Gotta create new tables in case its missing + dbLog:info('write mist.DBs.units') if not mist.DBs.units[newTable.coalition] then mist.DBs.units[newTable.coalition] = {} end @@ -809,7 +838,20 @@ do -- the main scope if not mist.DBs.units[newTable.coalition][newTable.country][mistCategory] then mist.DBs.units[newTable.coalition][(newTable.country)][mistCategory] = {} end - mist.DBs.units[newTable.coalition][(newTable.country)][mistCategory][#mist.DBs.units[newTable.coalition][(newTable.country)][mistCategory] + 1] = ldeepCopy(newTable) + + if updated == true then + dbLog:info('Updating DBsUnits') + for i = 1, #mist.DBs.units[newTable.coalition][(newTable.country)][mistCategory] do + if mist.DBs.units[newTable.coalition][(newTable.country)][mistCategory][i].groupName == newTable.groupName then + dbLog:info('Entry Found, Rewriting') + mist.DBs.units[newTable.coalition][(newTable.country)][mistCategory][i] = ldeepCopy(newTable) + break + end + end + else + mist.DBs.units[newTable.coalition][(newTable.country)][mistCategory][#mist.DBs.units[newTable.coalition][(newTable.country)][mistCategory] + 1] = ldeepCopy(newTable) + end + if newTable.groupId then mist.DBs.groupsById[newTable.groupId] = ldeepCopy(newTable) @@ -826,13 +868,34 @@ do -- the main scope if timer.getTime() > lastUpdateTime then lastUpdateTime = timer.getTime() end + dbLog:info('endUpdateTables') end end local function groupSpawned(event) -- dont need to add units spawned in at the start of the mission if mist is loaded in init line if event.id == world.event.S_EVENT_BIRTH and timer.getTime0() < timer.getAbsTime() then - table.insert(tempSpawnedUnits,(event.initiator)) + dbLog:info('unitSpawnEvent') + if not Unit.getPlayerName(event.initiator) then -- simple player check, will need to later check to see if unit was spawned with a player in a flight + table.insert(tempSpawnedUnits,(event.initiator)) + ------- + -- New functionality below. + ------- + if Object.getCategory(event.initiator) == 1 then + dbLog:info('Object is a Unit') + dbLog:info(Unit.getGroup(event.initiator):getName()) + if not tempSpawnedGroups[Unit.getGroup(event.initiator):getName()] then + dbLog:info('added') + tempSpawnedGroups[Unit.getGroup(event.initiator):getName()] = 'group' + tempSpawnedGroupsCounter = tempSpawnGroupsCounter + 1 + end + elseif Object.getCategory(event.initiator) == 3 or Object.getCategory(event.initiator) == 6 then + dbLog:info('Object is Static') + tempSpawnedGroups[StaticObject.getName(event.initiator)] = 'static' + tempSpawnedGroupsCounter = tempSpawnGroupsCounter + 1 + end + + end end end @@ -938,7 +1001,7 @@ do -- the main scope --[[ local function addClientsToActive(event) if event.id == world.event.S_EVENT_PLAYER_ENTER_UNIT or event.id == world.event.S_EVENT_BIRTH then - log:info(mist.utils.tableShow(event)) + log:info(event) if Unit.getPlayerName(event.initiator) then log:info(Unit.getPlayerName(event.initiator)) local newU = mist.utils.deepCopy(mist.DBs.unitsByName[Unit.getName(event.initiator)]) @@ -964,10 +1027,12 @@ do -- the main scope function mist.init() -- create logger mist.log = mist.Logger:new("MIST") + dbLog = mist.Logger:new('MISTDB', 'info') + log = mist.log -- log shorthand -- set warning log level, showing only -- warnings and errors - log:setLevel("warning") + log:setLevel("info") log:info("initializing databases") initDBs() @@ -988,10 +1053,12 @@ do -- the main scope function mist.main() timer.scheduleFunction(mist.main, {}, timer.getTime() + 0.01) --reschedule first in case of Lua error - writeDbTableCounter = writeDbTableCounter + 1 - if writeDbTableCounter == 10 then - writeDbTableCounter = 0 + updateTenthSecond = updateTenthSecond + 1 + if updateTenthSecond == 10 then + updateTenthSecond = 0 + checkSpawnedEventsNew() + if not coroutines.updateDBTables then coroutines.updateDBTables = coroutine.create(updateDBTables) end @@ -1003,21 +1070,6 @@ do -- the main scope end end - checkSpawnEventsCounter = checkSpawnEventsCounter + 1 - if checkSpawnEventsCounter == 10 then - checkSpawnEventsCounter = 0 - - if not coroutines.checkSpawnedEvents then - coroutines.checkSpawnedEvents = coroutine.create(checkSpawnedEvents) - end - - coroutine.resume(coroutines.checkSpawnedEvents) - - if coroutine.status(coroutines.checkSpawnedEvents) == 'dead' then - coroutines.checkSpawnedEvents = nil - end - end - --updating alive units updateAliveUnitsCounter = updateAliveUnitsCounter + 1 if updateAliveUnitsCounter == 5 then @@ -1408,7 +1460,10 @@ do -- the main scope end return false end +end +-- Begin common funcs +do --- Returns MGRS coordinates as string. -- @tparam string MGRS MGRS coordinates -- @tparam number acc the accuracy of each easting/northing. @@ -3462,70 +3517,70 @@ do -- mist.util scope --- Converts angle in radians to degrees. -- @param angle angle in radians -- @return angle in degrees - function mist.utils.toDegree (angle) + function mist.utils.toDegree(angle) return angle*180/math.pi end --- Converts angle in degrees to radians. -- @param angle angle in degrees -- @return angle in degrees - function mist.utils.toRadian (angle) + function mist.utils.toRadian(angle) return angle*math.pi/180 end --- Converts meters to nautical miles. -- @param meters distance in meters -- @return distance in nautical miles - function mist.utils.metersToNM (meters) + function mist.utils.metersToNM(meters) return meters/1852 end --- Converts meters to feet. -- @param meters distance in meters -- @return distance in feet - function mist.utils.metersToFeet (meters) + function mist.utils.metersToFeet(meters) return meters/0.3048 end --- Converts nautical miles to meters. -- @param nm distance in nautical miles -- @return distance in meters - function mist.utils.NMToMeters (nm) - return NM*1852 + function mist.utils.NMToMeters(nm) + return nm*1852 end --- Converts feet to meters. -- @param feet distance in feet -- @return distance in meters - function mist.utils.feetToMeters (feet) + function mist.utils.feetToMeters(feet) return feet*0.3048 end --- Converts meters per second to knots. -- @param mps speed in m/s -- @return speed in knots - function mist.utils.mpsToKnots (mps) + function mist.utils.mpsToKnots(mps) return mps*3600/1852 end --- Converts meters per second to kilometers per hour. -- @param mps speed in m/s -- @return speed in km/h - function mist.utils.mpsToKmph (mps) + function mist.utils.mpsToKmph(mps) return mps*3.6 end --- Converts knots to meters per second. -- @param knots speed in knots -- @return speed in m/s - function mist.utils.knotsToMps (knots) + function mist.utils.knotsToMps(knots) return knots*1852/3600 end --- Converts kilometers per hour to meters per second. -- @param kmph speed in km/h -- @return speed in m/s - function mist.utils.kmphToMps (kmph) + function mist.utils.kmphToMps(kmph) return kmph/3.6 end