1. We have added the ability to collapse/expand forum categories and widgets on forum home.
    Dismiss Notice
  2. Photobucket has changed its policy concerning hotlinking images and now requires an account with a $399.00 annual fee to allow hotlink. More information is available at: this link.
    Dismiss Notice
  3. All Civ avatars are brought back and available for selection in the Avatar Gallery! There are 945 avatars total.
    Dismiss Notice
  4. To make the site more secure, we have installed SSL certificates and enabled HTTPS for both the main site and forums.
    Dismiss Notice
  5. Civ6 is released! Order now! (Amazon US | Amazon UK | Amazon CA | Amazon DE | Amazon FR)
    Dismiss Notice
  6. Dismiss Notice
  7. Forum account upgrades are available for ad-free browsing.
    Dismiss Notice

Saving/Loading simple tables with a game

Discussion in 'Civ6 - Utilities, Code Snippets & Art Assets' started by Gedemon, Jan 21, 2017.

  1. Gedemon

    Gedemon Modder Moderator

    Joined:
    Oct 4, 2004
    Messages:
    7,108
    Location:
    France
    Not fully tested, so use it carefully, I've no idea of the size limit and performance on large table.

    I tested it by saving/loading a table with all plots coordinates of a small map and some data for each plot.

    In a lua file loaded as an <UserInterface> component (as GameConfiguration.SetValue doesn't exist in scripts contexts):
    Code:
    -----------------------------------------------------------------------------------------
    --    FILE:     SaveLoad.lua
    --  Gedemon (2017)
    --  Loading/Saving simple tables with the game file using Pickle Table for serialization
    --  http://lua-users.org/wiki/PickleTable
    -----------------------------------------------------------------------------------------
    
    ----------------------------------------------
    -- Pickle.lua
    -- A table serialization utility for lua
    -- Steve Dekorte, http://www.dekorte.com, Apr 2000
    -- Freeware
    ----------------------------------------------
    
    function pickle(t)
      return Pickle:clone():pickle_(t)
    end
    
    Pickle = {
      clone = function (t) local nt={}; for i, v in pairs(t) do nt[i]=v end return nt end
    }
    
    function Pickle:pickle_(root)
      if type(root) ~= "table" then
        error("can only pickle tables, not ".. type(root).."s")
      end
      self._tableToRef = {}
      self._refToTable = {}
      local savecount = 0
      self:ref_(root)
      local s = ""
    
      while #(self._refToTable) > savecount do
        savecount = savecount + 1
        local t = self._refToTable[savecount]
        s = s.."{\n"
        for i, v in pairs(t) do
            s = string.format("%s[%s]=%s,\n", s, self:value_(i), self:value_(v))
        end
        s = s.."},\n"
      end
    
      return string.format("{%s}", s)
    end
    
    function Pickle:value_(v)
      local vtype = type(v)
      if     vtype == "string" then return string.format("%q", v)
      elseif vtype == "number" then return v
      elseif vtype == "boolean" then return tostring(v)
      elseif vtype == "table" then return "{"..self:ref_(v).."}"
      else --error("pickle a "..type(v).." is not supported")
      end
    end
    
    function Pickle:ref_(t)
      local ref = self._tableToRef[t]
      if not ref then
        if t == self then error("can't pickle the pickle class") end
        table.insert(self._refToTable, t)
        ref = #(self._refToTable)
        self._tableToRef[t] = ref
      end
      return ref
    end
    
    ----------------------------------------------
    -- unpickle
    ----------------------------------------------
    
    function unpickle(s)
      if type(s) ~= "string" then
        error("can't unpickle a "..type(s)..", only strings")
      end
      local gentables = loadstring("return "..s)
      local tables = gentables()
    
      for tnum = 1, #(tables) do
        local t = tables[tnum]
        local tcopy = {}; for i, v in pairs(t) do tcopy[i] = v end
        for i, v in pairs(tcopy) do
          local ni, nv
          if type(i) == "table" then ni = tables[i[1]] else ni = i end
          if type(v) == "table" then nv = tables[v[1]] else nv = v end
          t[i] = nil
          t[ni] = nv
        end
      end
      return tables[1]
    end
    
    
    
    -----------------------------------------------------------------------------------------
    -- Load / Save
    -- Using Civ6 GameConfiguration
    -----------------------------------------------------------------------------------------
    
    -- save
    function SaveTableToSlot(t, sSlotName)
        local s = pickle(t)
        GameConfiguration.SetValue(sSlotName, s)
    end
    
    -- load
    function LoadTableFromSlot(sSlotName)
        local s = GameConfiguration.GetValue(sSlotName)
        if s then
            local t = unpickle(s)
            return t
        else
            print("ERROR: can't load table from ".. tostring(sSlotName))
        end
    end
    
    function Initialize()
        ExposedMembers.SaveTableToSlot = SaveTableToSlot
        ExposedMembers.LoadTableFromSlot = LoadTableFromSlot
    end
    Initialize()
    usage (from any context) :
    > ExposedMembers.SaveTableToSlot(t, "myTable")
    > t = ExposedMembers.LoadTableFromSlot("myTable")


    When to save if you can't do it at specific times ?

    Code:
    -- this Lua event is called when listing files on the save/load menu
    function SaveMyTable()
        ExposedMembers.SaveTableToSlot(myTable, "myTable")
    end
    LuaEvents.FileListQueryComplete.Add( SaveMyTable )
    
    -- could get the quicksave key here
    function OnInputHandler( pInputStruct:table )
        local uiMsg = pInputStruct:GetMessageType();
        if uiMsg == KeyEvents.KeyDown then
            if pInputStruct:GetKey() == Keys.VK_F5 then -- but the binding can be changed...
                ExposedMembers.SaveTableToSlot(myTable, "myTable")
            end
        end
        -- pInputStruct:IsShiftDown() and pInputStruct:IsAltDown()
    end
    ContextPtr:SetInputHandler( OnInputHandler, true )
    
    -- Or on this event for quick save
    function OnInputAction( actionID )
        if actionID == Input.GetActionId("QuickSave") then
            ExposedMembers.SaveTableToSlot(myTable, "myTable")
        end
    end
    Events.InputActionTriggered( OnInputAction )
     
    Last edited: Mar 21, 2017

Share This Page