Skip to content

Instantly share code, notes, and snippets.

@sparr
Created January 12, 2026 22:08
Show Gist options
  • Select an option

  • Save sparr/f2dfad8e58ae45d7e15fb2acbfb1a170 to your computer and use it in GitHub Desktop.

Select an option

Save sparr/f2dfad8e58ae45d7e15fb2acbfb1a170 to your computer and use it in GitHub Desktop.
Alchemy Factory mod attempt for blueprint loading modification
-- =========================
-- Userdata converters
-- =========================
-- The return types below are lua tables with all the same keys as the parameter, and values either copied or converted
-- TODO find a way to automatically produce accurate types for the returns with converted values
---@param v FIntVector userdata
---@return FIntVector v table
local function TableFromFIntVector(v)
return { X = v.X, Y = v.Y, Z = v.Z }
end
---@param v FVector userdata
---@return FVector v table
local function TableFromFVector(v)
return { X = v.X, Y = v.Y, Z = v.Z }
end
---@param p FIntPoint userdata
---@return FIntPoint p table
local function TableFromFIntPoint(p)
return { X = p.X, Y = p.Y }
end
---@param gg FGridGroup the GridGroup as userdata
---@return FGridGroup gg the GridGroup as a table
local function TableFromFGridGroup(gg)
return {
Pivot = TableFromFIntVector(gg.Pivot),
GridArea = TableFromFIntPoint(gg.GridArea),
}
end
---@param rcd FRelationCatapultData userdata
---@return FRelationCatapultData rcd table
local function TableFromFRelationCatapultData(rcd)
return {
PendingSettleKey = rcd.PendingSettleKey,
SelfSettleKey = rcd.SelfSettleKey,
TargetSettleKey = rcd.TargetSettleKey,
TargetSubIndex = rcd.TargetSubIndex,
}
end
---@param a TArray
---@param conversionfunc? function
local function TableFromTArray(a,conversionfunc)
local t = {}
a:ForEach(function(_,e)
if conversionfunc then
table.insert(t,conversionfunc(e:get()))
else
table.insert(t,e:get())
end
end)
end
---@param c FColor userdata
---@return FColor c table
local function TableFromFColor(c)
return {
B = c.B,
G = c.G,
R = c.R,
A = c.A,
}
end
---@param ei FEntityIndex userdata
---@return FEntityIndex ei table
local function TableFromFEntityIndex(ei)
return {
Type = ei.Type,
Version = ei.Version,
EntityIndex = ei.EntityIndex,
}
end
---@param csp FCloneSimplifyPackage userdate
---@return FCloneSimplifyPackage csp table
local function TableFromFCloneSimplifyPackage(csp)
local bp = TableFromFVector(csp.BuildPos)
print(string.format("BuildPos before %f,%f,%f",bp.X,bp.Y,bp.Z))
if bp.X == 687.5 then
bp.Z = bp.Z + 25
end
print(string.format("BuildPos after %f,%f,%f",bp.X,bp.Y,bp.Z))
return {
Secondary = csp.Secondary,
GridRotation = csp.GridRotation,
BaseActiveIndex = csp.BaseActiveIndex,
BuildingEntity = TableFromFEntityIndex(csp.BuildingEntity),
SettleKey = csp.SettleKey,
BaseArea = TableFromFIntPoint(csp.BaseArea),
}
end
---@param cbd FCloneBuildingData userdata
---@return FCloneBuildingData cbd table
local function TableFromFCloneBuildingData(cbd)
return {
IsDepend = cbd.IsDepend,
DependOthers = cbd.DependOthers,
RecipeName = cbd.RecipeName,
SupplyName = cbd.SupplyName,
ContractName = cbd.ContractName,
FilterName = cbd.FilterName,
SeedName = cbd.SeedName,
CoinName = cbd.CoinName,
NoticeString = cbd.NoticeString:ToString(),
CoinStack = cbd.CoinStack,
DependKeys = TableFromTArray(cbd.DependKeys),
CustomColor = TableFromFColor(cbd.CustomColor),
RelativeGridGroup = TableFromFGridGroup(cbd.RelativeGridGroup),
building = TableFromFCloneSimplifyPackage(cbd.building),
Extension = TableFromTArray(cbd.Extension, TableFromFCloneSimplifyPackage),
}
end
---@param cbs FCloneBuildingState userdata
---@return FCloneBuildingState cbs table
local function TableFromFCloneBuildingState(cbs)
return {
ParentGridGroup = TableFromFGridGroup(cbs.ParentGridGroup),
RelationCatapults = TableFromTArray(cbs.RelationCatapults,TableFromFRelationCatapultData),
Buildings = TableFromTArray(cbs.Buildings,TableFromFCloneBuildingData),
}
end
-- =========================
-- Hooks
-- =========================
---@param ud RemoteUnrealParam<FCloneBuildingState>
---@return FCloneBuildingState t table
function PostHook_BeltTD_SpatialCloneState_ReadBlueprintStatePack(_,ud)
-- this will crash the game, confirming the return value has some effect
-- return false
local table = TableFromFCloneBuildingState(ud:get())
-- this should move the first building up and change it to a candle
table.Buildings[1].building.BuildPos.Z = table.Buildings[1].building.BuildPos.Z + 25
table.Buildings[1].building.BuildingName = "Candle"
return table
end
function EmptyHook()
end
RegisterHook(
"/Script/BeltTD.SpatialCloneState:ReadBlueprintStatePack",
EmptyHook,
PostHook_BeltTD_SpatialCloneState_ReadBlueprintStatePack
)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment