Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- -- NOTE: NOT THE SAME AS game:GetService('KeyframeSequenceProvider'):RegisterKeyframeSequence()
- -- - CHL
- local ks2Hash = {}
- local util = require(script.util)
- local constants = require(script.constants)
- -- variables
- -- base
- local newBaseCharDict = util.misc:arrayToCharDict(constants.newBase:split'')
- local str2Int = util.base:factStrToNumFromBase(newBaseCharDict)
- local int2Str = util.base:factNumToStrFromBase(newBaseCharDict)
- local sciFiNota2Rational = util.scientificNotation:factSciFiNotifToNum(newBaseCharDict)
- local rational2SciFiNota = util.scientificNotation:factNumToSciFiNotif(newBaseCharDict)
- -- misc
- local isCompressed = true
- local classnameSets
- local defaultTagSubsitutions = not isCompressed and {
- BEGIN = 'BEGIN';
- END = 'END';
- CREATE = 'CREATE';
- ENDINDEX = 'ENDINDEX';
- ENDRATIONAL = 'ENDRATIONAL';
- BEGINSTRING = 'BEGINSTRING';
- ENDSTRING = 'ENDSTRING';
- ENDCFRAME = 'ENDCFRAME';
- } or {
- BEGIN = 'q';
- END = 'w';
- CREATE = 'e';
- ENDINDEX = 'r';
- ENDRATIONAL = 't';
- BEGINSTRING = 'y';
- ENDSTRING = 'u';
- ENDCFRAME = 'i';
- }
- local cacheRef = {}
- local cacheRefCount = 0
- -- functions
- function valueToNumber(value)
- local newValue = {value}
- local valueType = typeof(value)
- if valueType == 'string'then
- newValue = {value:byte(1, #value)}
- end
- return newValue
- end
- function valueToString(value, tagSubs)
- local valueType = typeof(value)
- local newValue = value
- local nums = valueToNumber(value)
- -- ok this may need polishing
- if valueType == 'string'then
- local tagSub1 = tagSubs.BEGINSTRING;
- newValue = '||'.. tagSub1 .. '||'
- for ind, byte in next, nums do
- local str = int2Str(byte)
- if #str == 1 then
- str = newBaseCharDict[0] .. str
- end
- nums[ind] = str
- end
- newValue ..= table.concat(nums, '') .. '||'.. tagSubs.ENDSTRING ..'||'
- elseif valueType == 'CFrame'then
- local tagSub1 = tagSubs.ENDCFRAME
- local components = {value:GetComponents()}
- for i, component in next, components do
- local scifiNotat = rational2SciFiNota(component)
- components[i] = scifiNotat.sign .. scifiNotat.rational .. '|' .. scifiNotat.exponent
- end
- newValue = table.concat(components, '|') .. '||' .. tagSub1 .. '||'
- end
- return newValue
- end
- function cacheify(val)
- cacheRefCount += 1
- cacheRef[val] = cacheRefCount
- end
- function serialize(inst, tagSubs)
- tagSubs = tagSubs or defaultTagSubsitutions
- assert(type(tagSubs) == 'table')
- local propertySet = assert(classnameSets[inst.ClassName])
- local res = '||' .. tagSubs.CREATE .. '||'
- -- start with classname
- local className = inst.ClassName
- local refIndex = cacheRef[className]
- if refIndex then
- res ..= int2Str(refIndex) .. '||' .. tagSubs.ENDINDEX .. '||'
- else
- res ..= valueToString(className, tagSubs)
- cacheify(className)
- end
- -- cache instance
- cacheify(inst)
- -- do properties
- for _, set in next, propertySet do
- if type(set) == 'string'then
- set = {set}
- end
- local instValue = inst[set[1]]
- local pType = set[2] or typeof(instValue)
- local expectedStr
- -- for each type of value
- if pType == 'Instance' then
- local vInst = cacheRef[instValue] or 0
- expectedStr = int2Str(vInst) .. '||'.. tagSubs.ENDINDEX .. '||'
- elseif pType == 'string'then
- local refIndex = cacheRef[instValue]
- if refIndex then
- expectedStr = int2Str(refIndex) .. '||'.. tagSubs.ENDINDEX .. '||'
- else
- expectedStr = valueToString(instValue, tagSubs)
- cacheify(instValue)
- end
- elseif pType == 'boolean'then
- local numRep = instValue and 1 or 0
- expectedStr = int2Str(numRep)
- elseif pType == 'EnumItem'then
- local numRep = instValue.Value
- expectedStr = int2Str(numRep)
- elseif pType == 'number'then -- including ints and rationals
- local num = instValue
- local sciFiNotat = rational2SciFiNota(num)
- expectedStr = sciFiNotat.sign .. sciFiNotat.rational .. '|' .. sciFiNotat.exponent .. '||'.. tagSubs.ENDRATIONAL .. '||'
- elseif pType == 'CFrame'then
- expectedStr = valueToString(instValue, tagSubs)
- else
- warn('got unknown type', pType)
- end
- res ..= expectedStr
- end
- return res
- end
- -- keyframeSequence to hash
- function ks2Hash:export(keyframeSequence, tagSubstitutions)
- tagSubstitutions = tagSubstitutions or defaultTagSubsitutions
- assert(
- typeof(keyframeSequence) == 'Instance' and keyframeSequence:IsA('KeyframeSequence') and
- type(tagSubstitutions) == 'table'
- )
- local sameTagSubs = true
- -- check if we need to see changed tags + check if they are there
- for tagFrom, tagTo in next, defaultTagSubsitutions do
- assert(type(tagSubstitutions[tagFrom]) == 'string')
- if tagTo ~= tagSubstitutions[tagFrom]then
- sameTagSubs = false
- break
- end
- end
- local res = '\nKS2Hash conversion by CHL\n'
- if not sameTagSubs then
- -- write new tag subsitutions (still considered a comment tho).
- res ..= '\nGot new tag subsitutions (use as the 2nd argument)\n + You can also fix any escape sequences\n\n{'
- for tagFrom, tagTo in next, tagSubstitutions do
- res ..= '\n\t' .. tagFrom .. ' = \'' .. tagTo .. '\';'
- end
- res ..= '\n}\n\n'
- end
- res ..= '||'.. tagSubstitutions.BEGIN .. '||'
- cacheRef = {}
- cacheRefCount = 0
- res ..= serialize(keyframeSequence, tagSubstitutions)
- for _, inst in next, keyframeSequence:GetDescendants()do
- res ..= serialize(inst, tagSubstitutions)
- end
- res ..= '||' .. tagSubstitutions.END .. '||'
- return res
- end
- -- hash to keyframeSequence
- function ks2Hash:import(str, keyframeSequenceParent, tagSubs)
- keyframeSequenceParent = keyframeSequenceParent or workspace
- tagSubs = tagSubs or defaultTagSubsitutions
- assert(type(str) == 'string' and typeof(keyframeSequenceParent) == 'Instance' and
- type(tagSubs) == 'table')
- for i in next, defaultTagSubsitutions do
- assert(type(tagSubs[i]) == 'string')
- end
- -- main
- local p = 1
- local mode = 'None'
- local cache = {}
- local currentInstanceIndex
- local currentPropertyIndex = 1
- local result = {}
- -- functions for string fun
- local function getStr(a, b)
- return str:sub(a or p, b or p)
- end
- local function printCharactersInPRange(chars)
- chars = chars or 3
- for a = -chars, chars do
- print('[' .. a .. '] = ' .. getStr(p + a, p + a))
- end
- end
- local function checkStr(checkStr, noSkip)
- local res = false
- local offset = #checkStr - 1
- res = getStr(p, p + offset) == checkStr
- if res and not noSkip then
- p += offset
- end
- return res
- end
- local function getContentInString(beginSubStr, endSubStr)
- p += (beginSubStr and #beginSubStr - 1) or -1
- local beginP = p + 1
- while not checkStr(endSubStr) do
- p += 1
- if getStr() == ''then
- error('something really went wrong')
- end
- end
- local endP = p - #endSubStr
- local result = getStr(beginP, endP)
- return result
- end
- local function getStringFromPos()
- local str
- if checkStr('||' .. tagSubs.BEGINSTRING .. '||', true) then
- local subHash = getContentInString('||' .. tagSubs.BEGINSTRING .. '||', '||' .. tagSubs.ENDSTRING .. '||')
- local bytes = {}
- for i = 1, #subHash / 2 do
- local byte = str2Int(subHash:sub(i * 2 - 1, i * 2))
- table.insert(bytes, byte)
- end
- str = string.char(unpack(bytes))
- table.insert(cache, str)
- else
- local subHash = getContentInString(nil, '||' .. tagSubs.ENDINDEX .. '||')
- local cacheIndex = str2Int(subHash)
- str = cache[cacheIndex]
- if not str then
- print(cacheIndex, cache)
- end
- end
- return str
- end
- -- the main loop
- while true do
- local char = getStr()
- -- end if we reach there
- if char == '' then
- break
- end
- -- the body
- if mode == 'None'and checkStr('||'.. tagSubs.BEGIN ..'||') then
- mode = 'Begin'
- elseif mode == 'Begin'then
- if checkStr('||'.. tagSubs.END .. '||') then
- mode = 'None'
- elseif checkStr('||'.. tagSubs.CREATE .. '||') then
- mode = 'Create'
- end
- elseif mode == 'Create'then
- if checkStr('||'.. tagSubs.END .. '||')then
- mode = 'None'
- else
- --create instance
- local className = getStringFromPos()
- local inst = Instance.new(className, workspace)
- if className == 'KeyframeSequence'then
- table.insert(result, inst)
- end
- table.insert(cache, inst)
- currentInstanceIndex = #cache
- mode = 'PropertyChange'
- end
- elseif mode == 'PropertyChange'then
- if checkStr('||' .. tagSubs.END .. '||')then
- mode = 'None'
- else
- local inst = cache[currentInstanceIndex]
- local propertiesSet = classnameSets[inst.ClassName]
- local property = propertiesSet[currentPropertyIndex]
- local pType
- if type(property)=='table'then
- pType = property[2]
- property = property[1]
- end
- pType = pType or typeof(inst[property])
- local newValue
- if pType == 'Instance' then
- local subHash = getContentInString(nil, '||' .. tagSubs.ENDINDEX .. '||')
- local index = str2Int(subHash)
- newValue = cache[index] or keyframeSequenceParent
- elseif pType == 'string'then
- newValue = getStringFromPos()
- elseif pType == 'boolean'then
- local numRep = getStr()
- newValue = str2Int(numRep) == 1
- elseif pType == 'EnumItem' then
- local numRep = getStr()
- newValue = str2Int(numRep)
- elseif pType == 'number'then
- local scifiNotif = getContentInString(nil, '||' .. tagSubs.ENDRATIONAL .. '||'):split'|'
- local rational, exponent = unpack(scifiNotif)
- local sign, absRational = rational:sub(1,1), rational:sub(2)
- local num = sciFiNota2Rational{
- exponent = exponent;
- sign = sign;
- rational = absRational
- }
- newValue = num
- elseif pType == 'CFrame'then
- local strs = getContentInString(nil, '||' .. tagSubs.ENDCFRAME .. '||'):split'|'
- local componentsArgs = {}
- local currentSciFiNotat
- for i, str in next, strs do
- local isRational = i % 2 == 1
- if isRational then
- -- rational + sign
- currentSciFiNotat = {
- sign = str:sub(1, 1);
- rational = str:sub(2)
- }
- else
- -- exponent
- currentSciFiNotat.exponent = str
- local num = sciFiNota2Rational(currentSciFiNotat)
- table.insert(componentsArgs, num)
- end
- end
- newValue = CFrame.new(unpack(componentsArgs))
- else
- error'got unknown type'
- end
- inst[property] = newValue
- currentPropertyIndex += 1
- if currentPropertyIndex > #propertiesSet then
- mode = 'Begin'
- currentPropertyIndex = 1
- end
- end
- end
- p += 1
- end
- return result
- end
- -- assign
- classnameSets = {
- KeyframeSequence = {
- {'Parent', 'Instance'};
- 'Name';
- 'Loop';
- 'Priority'
- };
- Keyframe = {
- {'Parent', 'Instance'};
- 'Time';
- };
- Pose = {
- {'Parent', 'Instance'};
- 'Name';
- 'CFrame';
- 'EasingDirection';
- 'EasingStyle';
- 'Weight'
- }
- }
- -- return
- return ks2Hash
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement