<?xml version="1.0" encoding="utf-8"?>
<CheatTable CheatEngineTableVersion="46">
  <CheatEntries>
    <CheatEntry>
      <ID>13</ID>
      <Description>"God Mode"</Description>
      <VariableType>Auto Assembler Script</VariableType>
      <AssemblerScript>[ENABLE]

{$lua}
if syntaxcheck then return end

if LaunchMonoDataCollector() == 0 then
  error("Could not activate Mono. Make sure Valheim is fully loaded.")
end

{$asm}

define(ISPLAYER,Player:IsPlayer)
define(SETHEALTH,Character:SetHealth)

assert(ISPLAYER,48 83 EC 08 B8 01 00 00 00 48 83 C4 08 C3)
assert(SETHEALTH,55 48 8B EC 48 83 EC 40 48 89 75 F0 48 89 7D F8)

alloc(godmem,$1000)

label(playerHook)
label(healthHook)
label(normalHealth)
label(blockDamage)
label(playerPtr)

godmem:

playerPtr:
  dq 0

// Capture the Player object whenever Player:IsPlayer runs.
// Then reproduce the original function exactly.
playerHook:
  mov [playerPtr],rcx
  sub rsp,08
  mov eax,00000001
  add rsp,08
  ret

// Character:SetHealth entry:
// RCX  = Character object
// XMM1 = requested new health
healthHook:
  cmp rcx,[playerPtr]
  jne normalHealth

  // Current health is Character+524
  comiss xmm1,[rcx+524]

  // Proposed health is lower - block damage
  jb blockDamage

normalHealth:
  // Replay the 16 bytes replaced at Character:SetHealth
  push rbp
  mov rbp,rsp
  sub rsp,40
  mov [rbp-10],rsi
  mov [rbp-08],rdi

  jmp far SETHEALTH+10

blockDamage:
  ret

// Player:IsPlayer is exactly 14 bytes long
ISPLAYER:
  jmp far playerHook

// We overwrite the first 16 bytes of SetHealth
SETHEALTH:
  jmp far healthHook
  nop 2

registersymbol(playerPtr)

[DISABLE]

ISPLAYER:
  db 48 83 EC 08 B8 01 00 00 00 48 83 C4 08 C3

SETHEALTH:
  db 55 48 8B EC 48 83 EC 40 48 89 75 F0 48 89 7D F8

unregistersymbol(playerPtr)
dealloc(godmem)
</AssemblerScript>
    </CheatEntry>
    <CheatEntry>
      <ID>27</ID>
      <Description>"Max Health (125)"</Description>
      <VariableType>Auto Assembler Script</VariableType>
      <AssemblerScript>[ENABLE]

{$lua}
if syntaxcheck then return end

if LaunchMonoDataCollector() == 0 then
  error("Could not activate Mono. Make sure Valheim is fully loaded.")
end

{$asm}

define(MAXHEALTH,Player:SetMaxHealth)

assert(MAXHEALTH+F,F3 0F 11 4D F0)

alloc(maxhealthmem,$1000,MAXHEALTH+F)

label(return)
label(original)
label(minHealth)

maxhealthmem:

  // XMM1 = requested new max health
  // If Valheim wants less than 125, replace it with 125
  comiss xmm1,[minHealth]
  jae original

  movss xmm1,[minHealth]

original:
  // Original instruction
  movss [rbp-10],xmm1
  jmp return

minHealth:
  dd (float)125

MAXHEALTH+F:
  jmp maxhealthmem

return:


[DISABLE]

define(MAXHEALTH,Player:SetMaxHealth)

MAXHEALTH+F:
  db F3 0F 11 4D F0

dealloc(maxhealthmem)
</AssemblerScript>
    </CheatEntry>
    <CheatEntry>
      <ID>14</ID>
      <Description>"Infinite Stamina"</Description>
      <VariableType>Auto Assembler Script</VariableType>
      <AssemblerScript>[ENABLE]

{$lua}
if syntaxcheck then return end

if LaunchMonoDataCollector() == 0 then
  error("Could not activate Mono. Make sure Valheim is fully loaded.")
end

{$asm}

define(USESTAMINA,Player:RPC_UseStamina)

// Updated Valheim stamina field offset:
// Old: +988
// New: +990

assert(USESTAMINA+4C,F3 0F 11 AE 90 09 00 00)

// Original:
// movss [rsi+00000990],xmm5
//
// Prevent reduced stamina from being stored.

USESTAMINA+4C:
  db 90 90 90 90 90 90 90 90


[DISABLE]

define(USESTAMINA,Player:RPC_UseStamina)

// Restore original stamina instruction.

USESTAMINA+4C:
  db F3 0F 11 AE 90 09 00 00
</AssemblerScript>
    </CheatEntry>
    <CheatEntry>
      <ID>42</ID>
      <Description>"CarryWeight 1000"</Description>
      <VariableType>Auto Assembler Script</VariableType>
      <AssemblerScript>[ENABLE]

{$lua}
if syntaxcheck then return end

------------------------------------------------------------
-- Valheim GetMaxCarryWeight
-- Forces returned carry weight to 1000.0
------------------------------------------------------------

if LaunchMonoDataCollector() == 0 then
  error("Could not activate Mono. Make sure Valheim is fully loaded.")
end

------------------------------------------------------------
-- Locate Mono method
------------------------------------------------------------

local method = mono_findMethod("", "Player", "GetMaxCarryWeight")

if not method or method == 0 then
  error("Could not find Player:GetMaxCarryWeight")
end

------------------------------------------------------------
-- Compile/get native method
------------------------------------------------------------

local p = mono_compile_method(method)

if not p or p == 0 then
  error("Could not compile Player:GetMaxCarryWeight")
end

------------------------------------------------------------
-- Get actual JIT code information
------------------------------------------------------------

local ji = mono_getJitInfo(p)

if not ji then
  error("Could not get JIT information for GetMaxCarryWeight")
end

local methodBody = ji.code_start
local methodSize = ji.code_size

print(string.format(
  "[Carry Weight] JIT body: %X size=%X",
  methodBody,
  methodSize
))

------------------------------------------------------------
-- Current Valheim return sequence:
--
-- F3 0F 10 45 F4
-- F3 0F 5A C0
-- F2 0F 5A C0
--
-- movss xmm0,[rbp-0C]
-- cvtss2sd xmm0,xmm0
-- cvtsd2ss xmm0,xmm0
------------------------------------------------------------

local pattern = {
  0xF3,0x0F,0x10,0x45,0xF4,
  0xF3,0x0F,0x5A,0xC0,
  0xF2,0x0F,0x5A,0xC0
}

------------------------------------------------------------
-- Pattern scanner
------------------------------------------------------------

local function findPattern(startAddr, searchSize, bytes)

  if searchSize &lt; #bytes then
    return nil
  end

  local data = readBytes(startAddr, searchSize, true)

  if not data then
    return nil
  end

  for offset = 0, searchSize - #bytes do

    local match = true

    for i = 1, #bytes do
      if data[offset + i] ~= bytes[i] then
        match = false
        break
      end
    end

    if match then
      return startAddr + offset
    end

  end

  return nil
end

------------------------------------------------------------
-- Locate return sequence
------------------------------------------------------------

local addr = findPattern(
  methodBody,
  methodSize,
  pattern
)

if not addr then
  error("Carry Weight: final return sequence was not found")
end

print(string.format(
  "[Carry Weight] Return sequence found at %X (+%X)",
  addr,
  addr - methodBody
))

------------------------------------------------------------
-- Save original code
------------------------------------------------------------

local original = readBytes(addr, 13, true)

if not original then
  error("Could not save original carry-weight instructions")
end

_G.ValheimCarryWeightPatch = addr
_G.ValheimCarryWeightOriginal = original

------------------------------------------------------------
-- Patch
--
-- 1000.0f = 447A0000
--
-- B8 00007A44        mov eax,447A0000
-- 66 0F 6E C0        movd xmm0,eax
-- 90 90 90 90        nop
------------------------------------------------------------

writeBytes(
  addr,

  0xB8,0x00,0x00,0x7A,0x44,
  0x66,0x0F,0x6E,0xC0,
  0x90,0x90,0x90,0x90
)

print("[Carry Weight] SUCCESS - Carry weight set to 1000")

{$asm}


[DISABLE]

{$lua}
if syntaxcheck then return end

local addr = _G.ValheimCarryWeightPatch
local original = _G.ValheimCarryWeightOriginal

if addr and original then

  writeBytes(addr, table.unpack(original))

  print(string.format(
    "[Carry Weight] Original code restored at %X",
    addr
  ))

end

_G.ValheimCarryWeightPatch = nil
_G.ValheimCarryWeightOriginal = nil

{$asm}
</AssemblerScript>
    </CheatEntry>
    <CheatEntry>
      <ID>52</ID>
      <Description>"Run Speed"</Description>
      <Options moHideChildren="1"/>
      <GroupHeader>1</GroupHeader>
      <CheatEntries>
        <CheatEntry>
          <ID>48</ID>
          <Description>"1.5x Run Speed"</Description>
          <VariableType>Auto Assembler Script</VariableType>
          <AssemblerScript>[ENABLE]

{$lua}
if syntaxcheck then return end

if LaunchMonoDataCollector() == 0 then
  error("Could not activate Mono. Make sure Valheim is fully loaded.")
end

--------------------------------------------------
-- Find local Player
--------------------------------------------------

local playerClass = mono_findClass("", "Player")

if not playerClass or playerClass == 0 then
  error("Could not find Player class")
end

local playerFields = mono_class_enumFields(playerClass)
local localPlayerField = nil

for i = 1, #playerFields do
  if playerFields[i].name == "m_localPlayer"
     and playerFields[i].isStatic then
    localPlayerField = playerFields[i]
    break
  end
end

if not localPlayerField then
  error("Could not find Player.m_localPlayer")
end

local domains = mono_enumDomains()
local staticBase =
  mono_class_getStaticFieldAddress(domains[1], playerClass)

if not staticBase or staticBase == 0 then
  error("Could not resolve Player static fields")
end

local player =
  readPointer(staticBase + localPlayerField.offset)

if not player or player == 0 then
  error("Local player not found. Load into your world first.")
end

--------------------------------------------------
-- Find Character movement fields
--------------------------------------------------

local characterClass = mono_findClass("", "Character")

if not characterClass or characterClass == 0 then
  error("Could not find Character class")
end

local characterFields =
  mono_class_enumFields(characterClass)

local runOffset = nil
local swimOffset = nil

for i = 1, #characterFields do
  if characterFields[i].name == "m_runSpeed" then
    runOffset = characterFields[i].offset

  elseif characterFields[i].name == "m_swimSpeed" then
    swimOffset = characterFields[i].offset
  end
end

if not runOffset then
  error("Could not find Character.m_runSpeed")
end

if not swimOffset then
  error("Could not find Character.m_swimSpeed")
end

--------------------------------------------------
-- Save original speeds only once
--------------------------------------------------

local state = _G.ValheimMovementSpeedState

if not state
   or state.player ~= player
   or state.runOffset ~= runOffset
   or state.swimOffset ~= swimOffset then

  local baseRun = readFloat(player + runOffset)
  local baseSwim = readFloat(player + swimOffset)

  if baseRun == nil then
    error("Could not read original run speed")
  end

  if baseSwim == nil then
    error("Could not read original swim speed")
  end

  state = {
    player = player,
    runOffset = runOffset,
    swimOffset = swimOffset,
    baseRun = baseRun,
    baseSwim = baseSwim
  }

  _G.ValheimMovementSpeedState = state
end

--------------------------------------------------
-- Turn off other Movement Speed options
--------------------------------------------------

_G.ValheimMovementSpeedSwitching = true

local parent = memrec.Parent

if parent then
  for i = 0, parent.Count - 1 do
    local mr = parent.Child[i]

    if mr ~= memrec and mr.Active then
      mr.Active = false
    end
  end
end

--------------------------------------------------
-- Apply 1.5x
--------------------------------------------------

writeFloat(
  state.player + state.runOffset,
  state.baseRun * 1.5
)

writeFloat(
  state.player + state.swimOffset,
  state.baseSwim * 1.5
)

_G.ValheimMovementSpeedSwitching = false

{$asm}


[DISABLE]

{$lua}
if syntaxcheck then return end

if _G.ValheimMovementSpeedSwitching then
  return
end

local state = _G.ValheimMovementSpeedState

if state and state.player and state.player ~= 0 then
  writeFloat(
    state.player + state.runOffset,
    state.baseRun
  )

  writeFloat(
    state.player + state.swimOffset,
    state.baseSwim
  )
end

_G.ValheimMovementSpeedState = nil

{$asm}
</AssemblerScript>
        </CheatEntry>
        <CheatEntry>
          <ID>49</ID>
          <Description>"2x Run Speed"</Description>
          <VariableType>Auto Assembler Script</VariableType>
          <AssemblerScript>[ENABLE]

{$lua}
if syntaxcheck then return end

if LaunchMonoDataCollector() == 0 then
  error("Could not activate Mono. Make sure Valheim is fully loaded.")
end

--------------------------------------------------
-- Find local Player
--------------------------------------------------

local playerClass = mono_findClass("", "Player")

if not playerClass or playerClass == 0 then
  error("Could not find Player class")
end

local playerFields = mono_class_enumFields(playerClass)
local localPlayerField = nil

for i = 1, #playerFields do
  if playerFields[i].name == "m_localPlayer"
     and playerFields[i].isStatic then
    localPlayerField = playerFields[i]
    break
  end
end

if not localPlayerField then
  error("Could not find Player.m_localPlayer")
end

local domains = mono_enumDomains()
local staticBase =
  mono_class_getStaticFieldAddress(domains[1], playerClass)

if not staticBase or staticBase == 0 then
  error("Could not resolve Player static fields")
end

local player =
  readPointer(staticBase + localPlayerField.offset)

if not player or player == 0 then
  error("Local player not found. Load into your world first.")
end

--------------------------------------------------
-- Find Character movement fields
--------------------------------------------------

local characterClass = mono_findClass("", "Character")

if not characterClass or characterClass == 0 then
  error("Could not find Character class")
end

local characterFields =
  mono_class_enumFields(characterClass)

local runOffset = nil
local swimOffset = nil

for i = 1, #characterFields do
  if characterFields[i].name == "m_runSpeed" then
    runOffset = characterFields[i].offset

  elseif characterFields[i].name == "m_swimSpeed" then
    swimOffset = characterFields[i].offset
  end
end

if not runOffset then
  error("Could not find Character.m_runSpeed")
end

if not swimOffset then
  error("Could not find Character.m_swimSpeed")
end

--------------------------------------------------
-- Save original speeds only once
--------------------------------------------------

local state = _G.ValheimMovementSpeedState

if not state
   or state.player ~= player
   or state.runOffset ~= runOffset
   or state.swimOffset ~= swimOffset then

  local baseRun = readFloat(player + runOffset)
  local baseSwim = readFloat(player + swimOffset)

  if baseRun == nil then
    error("Could not read original run speed")
  end

  if baseSwim == nil then
    error("Could not read original swim speed")
  end

  state = {
    player = player,
    runOffset = runOffset,
    swimOffset = swimOffset,
    baseRun = baseRun,
    baseSwim = baseSwim
  }

  _G.ValheimMovementSpeedState = state
end

--------------------------------------------------
-- Turn off other Movement Speed options
--------------------------------------------------

_G.ValheimMovementSpeedSwitching = true

local parent = memrec.Parent

if parent then
  for i = 0, parent.Count - 1 do
    local mr = parent.Child[i]

    if mr ~= memrec and mr.Active then
      mr.Active = false
    end
  end
end

--------------------------------------------------
-- Apply 2x
--------------------------------------------------

writeFloat(
  state.player + state.runOffset,
  state.baseRun * 2.0
)

writeFloat(
  state.player + state.swimOffset,
  state.baseSwim * 2.0
)

_G.ValheimMovementSpeedSwitching = false

{$asm}


[DISABLE]

{$lua}
if syntaxcheck then return end

if _G.ValheimMovementSpeedSwitching then
  return
end

local state = _G.ValheimMovementSpeedState

if state and state.player and state.player ~= 0 then
  writeFloat(
    state.player + state.runOffset,
    state.baseRun
  )

  writeFloat(
    state.player + state.swimOffset,
    state.baseSwim
  )
end

_G.ValheimMovementSpeedState = nil

{$asm}
</AssemblerScript>
        </CheatEntry>
        <CheatEntry>
          <ID>50</ID>
          <Description>"3x Run Speed"</Description>
          <VariableType>Auto Assembler Script</VariableType>
          <AssemblerScript>[ENABLE]

{$lua}
if syntaxcheck then return end

if LaunchMonoDataCollector() == 0 then
  error("Could not activate Mono. Make sure Valheim is fully loaded.")
end

--------------------------------------------------
-- Find local Player
--------------------------------------------------

local playerClass = mono_findClass("", "Player")

if not playerClass or playerClass == 0 then
  error("Could not find Player class")
end

local playerFields = mono_class_enumFields(playerClass)
local localPlayerField = nil

for i = 1, #playerFields do
  if playerFields[i].name == "m_localPlayer"
     and playerFields[i].isStatic then
    localPlayerField = playerFields[i]
    break
  end
end

if not localPlayerField then
  error("Could not find Player.m_localPlayer")
end

local domains = mono_enumDomains()
local staticBase =
  mono_class_getStaticFieldAddress(domains[1], playerClass)

if not staticBase or staticBase == 0 then
  error("Could not resolve Player static fields")
end

local player =
  readPointer(staticBase + localPlayerField.offset)

if not player or player == 0 then
  error("Local player not found. Load into your world first.")
end

--------------------------------------------------
-- Find Character movement fields
--------------------------------------------------

local characterClass = mono_findClass("", "Character")

if not characterClass or characterClass == 0 then
  error("Could not find Character class")
end

local characterFields =
  mono_class_enumFields(characterClass)

local runOffset = nil
local swimOffset = nil

for i = 1, #characterFields do
  if characterFields[i].name == "m_runSpeed" then
    runOffset = characterFields[i].offset

  elseif characterFields[i].name == "m_swimSpeed" then
    swimOffset = characterFields[i].offset
  end
end

if not runOffset then
  error("Could not find Character.m_runSpeed")
end

if not swimOffset then
  error("Could not find Character.m_swimSpeed")
end

--------------------------------------------------
-- Save original speeds only once
--------------------------------------------------

local state = _G.ValheimMovementSpeedState

if not state
   or state.player ~= player
   or state.runOffset ~= runOffset
   or state.swimOffset ~= swimOffset then

  local baseRun = readFloat(player + runOffset)
  local baseSwim = readFloat(player + swimOffset)

  if baseRun == nil then
    error("Could not read original run speed")
  end

  if baseSwim == nil then
    error("Could not read original swim speed")
  end

  state = {
    player = player,
    runOffset = runOffset,
    swimOffset = swimOffset,
    baseRun = baseRun,
    baseSwim = baseSwim
  }

  _G.ValheimMovementSpeedState = state
end

--------------------------------------------------
-- Turn off other Movement Speed options
--------------------------------------------------

_G.ValheimMovementSpeedSwitching = true

local parent = memrec.Parent

if parent then
  for i = 0, parent.Count - 1 do
    local mr = parent.Child[i]

    if mr ~= memrec and mr.Active then
      mr.Active = false
    end
  end
end

--------------------------------------------------
-- Apply 3x
--------------------------------------------------

writeFloat(
  state.player + state.runOffset,
  state.baseRun * 3.0
)

writeFloat(
  state.player + state.swimOffset,
  state.baseSwim * 3.0
)

_G.ValheimMovementSpeedSwitching = false

{$asm}


[DISABLE]

{$lua}
if syntaxcheck then return end

if _G.ValheimMovementSpeedSwitching then
  return
end

local state = _G.ValheimMovementSpeedState

if state and state.player and state.player ~= 0 then
  writeFloat(
    state.player + state.runOffset,
    state.baseRun
  )

  writeFloat(
    state.player + state.swimOffset,
    state.baseSwim
  )
end

_G.ValheimMovementSpeedState = nil

{$asm}
</AssemblerScript>
        </CheatEntry>
        <CheatEntry>
          <ID>51</ID>
          <Description>"5x Runs Speed"</Description>
          <VariableType>Auto Assembler Script</VariableType>
          <AssemblerScript>[ENABLE]

{$lua}
if syntaxcheck then return end

if LaunchMonoDataCollector() == 0 then
  error("Could not activate Mono. Make sure Valheim is fully loaded.")
end

--------------------------------------------------
-- Find local Player
--------------------------------------------------

local playerClass = mono_findClass("", "Player")

if not playerClass or playerClass == 0 then
  error("Could not find Player class")
end

local playerFields = mono_class_enumFields(playerClass)
local localPlayerField = nil

for i = 1, #playerFields do
  if playerFields[i].name == "m_localPlayer"
     and playerFields[i].isStatic then
    localPlayerField = playerFields[i]
    break
  end
end

if not localPlayerField then
  error("Could not find Player.m_localPlayer")
end

local domains = mono_enumDomains()
local staticBase =
  mono_class_getStaticFieldAddress(domains[1], playerClass)

if not staticBase or staticBase == 0 then
  error("Could not resolve Player static fields")
end

local player =
  readPointer(staticBase + localPlayerField.offset)

if not player or player == 0 then
  error("Local player not found. Load into your world first.")
end

--------------------------------------------------
-- Find Character movement fields
--------------------------------------------------

local characterClass = mono_findClass("", "Character")

if not characterClass or characterClass == 0 then
  error("Could not find Character class")
end

local characterFields =
  mono_class_enumFields(characterClass)

local runOffset = nil
local swimOffset = nil

for i = 1, #characterFields do
  if characterFields[i].name == "m_runSpeed" then
    runOffset = characterFields[i].offset

  elseif characterFields[i].name == "m_swimSpeed" then
    swimOffset = characterFields[i].offset
  end
end

if not runOffset then
  error("Could not find Character.m_runSpeed")
end

if not swimOffset then
  error("Could not find Character.m_swimSpeed")
end

--------------------------------------------------
-- Save original speeds only once
--------------------------------------------------

local state = _G.ValheimMovementSpeedState

if not state
   or state.player ~= player
   or state.runOffset ~= runOffset
   or state.swimOffset ~= swimOffset then

  local baseRun = readFloat(player + runOffset)
  local baseSwim = readFloat(player + swimOffset)

  if baseRun == nil then
    error("Could not read original run speed")
  end

  if baseSwim == nil then
    error("Could not read original swim speed")
  end

  state = {
    player = player,
    runOffset = runOffset,
    swimOffset = swimOffset,
    baseRun = baseRun,
    baseSwim = baseSwim
  }

  _G.ValheimMovementSpeedState = state
end

--------------------------------------------------
-- Turn off other Movement Speed options
--------------------------------------------------

_G.ValheimMovementSpeedSwitching = true

local parent = memrec.Parent

if parent then
  for i = 0, parent.Count - 1 do
    local mr = parent.Child[i]

    if mr ~= memrec and mr.Active then
      mr.Active = false
    end
  end
end

--------------------------------------------------
-- Apply 5x
--------------------------------------------------

writeFloat(
  state.player + state.runOffset,
  state.baseRun * 40.0
)

writeFloat(
  state.player + state.swimOffset,
  state.baseSwim * 40.0
)

_G.ValheimMovementSpeedSwitching = false

{$asm}


[DISABLE]

{$lua}
if syntaxcheck then return end

if _G.ValheimMovementSpeedSwitching then
  return
end

local state = _G.ValheimMovementSpeedState

if state and state.player and state.player ~= 0 then
  writeFloat(
    state.player + state.runOffset,
    state.baseRun
  )

  writeFloat(
    state.player + state.swimOffset,
    state.baseSwim
  )
end

_G.ValheimMovementSpeedState = nil

{$asm}
</AssemblerScript>
        </CheatEntry>
      </CheatEntries>
    </CheatEntry>
    <CheatEntry>
      <ID>40</ID>
      <Description>"Extra Damage"</Description>
      <VariableType>Auto Assembler Script</VariableType>
      <AssemblerScript>[ENABLE]

{$lua}
if syntaxcheck then return end

if LaunchMonoDataCollector() == 0 then
  error("Could not activate Mono. Make sure Valheim is fully loaded.")
end
{$asm}

define(MODDAMAGE,Attack:ModifyDamage)

// Original instructions from +16 through +26
assert(MODDAMAGE+16,F3 0F 11 55 E0 F3 0F 10 87 24 01 00 00 F3 0F 5A C0)

// Allocate anywhere - no nearby allocation required
alloc(damagemem,$1000)

label(normalDamage)
label(damageMultiplier)

damagemem:

  // Attack+90 = m_baseAI
  // AI attack -&gt; leave damage unchanged
  cmp qword ptr [rdi+90],00
  jne normalDamage

  // Player attack:
  // XMM2 contains damageFactor
  mulss xmm2,[damageMultiplier]

normalDamage:

  // Replay all instructions we replaced
  movss [rbp-20],xmm2
  movss xmm0,[rdi+00000124]
  cvtss2sd xmm0,xmm0

  // Continue original function
  jmp far MODDAMAGE+27


damageMultiplier:
  dd (float)10.0


MODDAMAGE+16:
  jmp far damagemem
  nop 3


[DISABLE]

define(MODDAMAGE,Attack:ModifyDamage)

MODDAMAGE+16:
  db F3 0F 11 55 E0
  db F3 0F 10 87 24 01 00 00
  db F3 0F 5A C0

dealloc(damagemem)
</AssemblerScript>
    </CheatEntry>
    <CheatEntry>
      <ID>23</ID>
      <Description>"Infinite Ammo"</Description>
      <VariableType>Auto Assembler Script</VariableType>
      <AssemblerScript>[ENABLE]

{$lua}
if syntaxcheck then return end

if LaunchMonoDataCollector() == 0 then
  error("Could not activate Mono. Make sure Valheim is fully loaded.")
end

{$asm}

define(USEAMMO,Attack:UseAmmo)

// Original:
// call r11
//
// r11 = Inventory:RemoveItem
assert(USEAMMO+298,41 FF D3)

// Prevent the ammo-removal call
USEAMMO+298:
  db 90 90 90


[DISABLE]

define(USEAMMO,Attack:UseAmmo)

USEAMMO+298:
  db 41 FF D3

</AssemblerScript>
    </CheatEntry>
    <CheatEntry>
      <ID>41</ID>
      <Description>"Durability"</Description>
      <Options moAlwaysHideChildren="1" moActivateChildrenAsWell="1" moDeactivateChildrenAsWell="1"/>
      <GroupHeader>1</GroupHeader>
      <CheatEntries>
        <CheatEntry>
          <ID>17</ID>
          <Description>"Melee Durability"</Description>
          <VariableType>Auto Assembler Script</VariableType>
          <AssemblerScript>[ENABLE]

{$lua}
if syntaxcheck then return end

if LaunchMonoDataCollector() == 0 then
  error("Could not activate Mono. Make sure Valheim is fully loaded.")
end

{$asm}

define(MELEEDURABILITY,Attack:DoMeleeAttack)

assert(MELEEDURABILITY+5B32,F3 0F 11 68 3C)

// Original:
// movss [rax+3C],xmm5
//
// Prevent melee weapon/tool durability loss
MELEEDURABILITY+5B32:
  db 90 90 90 90 90


[DISABLE]

define(MELEEDURABILITY,Attack:DoMeleeAttack)

MELEEDURABILITY+5B32:
  db F3 0F 11 68 3C

</AssemblerScript>
        </CheatEntry>
        <CheatEntry>
          <ID>20</ID>
          <Description>"Ranged Durability"</Description>
          <VariableType>Auto Assembler Script</VariableType>
          <AssemblerScript>[ENABLE]

{$lua}
if syntaxcheck then return end

if LaunchMonoDataCollector() == 0 then
  error("Could not activate Mono. Make sure Valheim is fully loaded.")
end

{$asm}

define(PROJECTILEDURABILITY,Attack:ProjectileAttackTriggered)

assert(PROJECTILEDURABILITY+418,F3 0F 11 68 3C)

// Original:
// movss [rax+3C],xmm5
//
// Prevent bow / projectile weapon durability loss
PROJECTILEDURABILITY+418:
  db 90 90 90 90 90


[DISABLE]

define(PROJECTILEDURABILITY,Attack:ProjectileAttackTriggered)

PROJECTILEDURABILITY+418:
  db F3 0F 11 68 3C
</AssemblerScript>
        </CheatEntry>
        <CheatEntry>
          <ID>29</ID>
          <Description>"Armour Durability"</Description>
          <VariableType>Auto Assembler Script</VariableType>
          <AssemblerScript>[ENABLE]

{$lua}
if syntaxcheck then return end

if LaunchMonoDataCollector() == 0 then
  error("Could not activate Mono. Make sure Valheim is fully loaded.")
end

{$asm}

define(ARMORDURABILITY,Player:DamageArmorDurability)

assert(ARMORDURABILITY+3B4,F3 41 0F 11 6F 3C)

// Original:
// movss [r15+3C],xmm5
//
// Prevent armour durability loss
ARMORDURABILITY+3B4:
  db 90 90 90 90 90 90


[DISABLE]

define(ARMORDURABILITY,Player:DamageArmorDurability)

ARMORDURABILITY+3B4:
  db F3 41 0F 11 6F 3C

</AssemblerScript>
        </CheatEntry>
        <CheatEntry>
          <ID>46</ID>
          <Description>"Hammer Durability"</Description>
          <VariableType>Auto Assembler Script</VariableType>
          <AssemblerScript>[ENABLE]

{$lua}
if syntaxcheck then return end

if LaunchMonoDataCollector() == 0 then
  error("Could not activate Mono. Make sure Valheim is fully loaded.")
end

local p = getAddressSafe("Player:UpdatePlacement")

if not p then
  error("Could not find Player:UpdatePlacement")
end

-- Follow the DMD jump
local firstByte = readBytes(p,1,false)

if firstByte ~= 0xE9 then
  error("Player:UpdatePlacement is not using the expected DMD jump")
end

local rel = readInteger(p+1)

if rel &gt;= 0x80000000 then
  rel = rel - 0x100000000
end

local dmd = p + 5 + rel
local addr = dmd + 0xF55

-- Original:
-- F3 41 0F 11 6F 3C
-- movss [r15+3C],xmm5

local original = {
  0xF3,0x41,0x0F,0x11,0x6F,0x3C
}

local current = readBytes(addr,6,true)

if not current then
  error("Could not read hammer durability instruction")
end

for i=1,6 do
  if current[i] ~= original[i] then
    error("Hammer Durability: expected original bytes were not found")
  end
end

_G.ValheimHammerDurabilityPatch = addr

-- Prevent durability from being written
writeBytes(addr,
  0x90,0x90,0x90,0x90,0x90,0x90
)

{$asm}


[DISABLE]

{$lua}
if syntaxcheck then return end

local addr = _G.ValheimHammerDurabilityPatch

if addr then
  writeBytes(addr,
    0xF3,0x41,0x0F,0x11,0x6F,0x3C
  )
end

_G.ValheimHammerDurabilityPatch = nil

{$asm}

</AssemblerScript>
        </CheatEntry>
        <CheatEntry>
          <ID>55</ID>
          <Description>"Shield"</Description>
          <VariableType>Auto Assembler Script</VariableType>
          <AssemblerScript>[ENABLE]

{$lua}
if syntaxcheck then return end

if LaunchMonoDataCollector() == 0 then
  error("Could not activate Mono. Make sure Valheim is fully loaded.")
end

{$asm}

define(SHIELDDURABILITY,Humanoid:BlockAttack)

assert(SHIELDDURABILITY+CE6,F3 41 0F 11 6E 3C)

// Original:
// movss [r14+3C],xmm5
//
// Prevent shield durability loss when blocking

SHIELDDURABILITY+CE6:
  db 90 90 90 90 90 90


[DISABLE]

define(SHIELDDURABILITY,Humanoid:BlockAttack)

SHIELDDURABILITY+CE6:
  db F3 41 0F 11 6E 3C

</AssemblerScript>
        </CheatEntry>
      </CheatEntries>
    </CheatEntry>
    <CheatEntry>
      <ID>31</ID>
      <Description>"Skill Multiplier"</Description>
      <Options moHideChildren="1"/>
      <GroupHeader>1</GroupHeader>
      <CheatEntries>
        <CheatEntry>
          <ID>30</ID>
          <Description>"Skill Multiplier x5"</Description>
          <VariableType>Auto Assembler Script</VariableType>
          <AssemblerScript>[ENABLE]

{$lua}
if syntaxcheck then return end

-- Only allow one Skill Multiplier child to be active
local parent = memrec.Parent

if parent then
  for i = 0, parent.Count - 1 do
    local mr = parent.Child[i]

    if mr ~= memrec and mr.Active then
      mr.Active = false
    end
  end
end

if LaunchMonoDataCollector() == 0 then
  error("Could not activate Mono. Make sure Valheim is fully loaded.")
end
{$asm}

define(RAISESKILL,Skills:RaiseSkill)

assert(RAISESKILL+1D,F3 0F 11 55 C8)

alloc(skillmem,$1000,RAISESKILL+1D)

label(return)
label(xpMultiplier)

skillmem:

  // XMM2 = normal skill XP factor
  mulss xmm2,[xpMultiplier]

  // Original instruction
  movss [rbp-38],xmm2

  jmp return

xpMultiplier:
  dd (float)5.0


RAISESKILL+1D:
  jmp skillmem

return:


[DISABLE]

define(RAISESKILL,Skills:RaiseSkill)

RAISESKILL+1D:
  db F3 0F 11 55 C8

dealloc(skillmem)

</AssemblerScript>
        </CheatEntry>
        <CheatEntry>
          <ID>32</ID>
          <Description>"Skill Multiplier x10"</Description>
          <VariableType>Auto Assembler Script</VariableType>
          <AssemblerScript>[ENABLE]

{$lua}
if syntaxcheck then return end

-- Only allow one Skill Multiplier child to be active
local parent = memrec.Parent

if parent then
  for i = 0, parent.Count - 1 do
    local mr = parent.Child[i]

    if mr ~= memrec and mr.Active then
      mr.Active = false
    end
  end
end

if LaunchMonoDataCollector() == 0 then
  error("Could not activate Mono. Make sure Valheim is fully loaded.")
end
{$asm}

define(RAISESKILL,Skills:RaiseSkill)

assert(RAISESKILL+1D,F3 0F 11 55 C8)

alloc(skillmem,$1000,RAISESKILL+1D)

label(return)
label(xpMultiplier)

skillmem:

  // XMM2 = normal skill XP factor
  mulss xmm2,[xpMultiplier]

  // Original instruction
  movss [rbp-38],xmm2

  jmp return

xpMultiplier:
  dd (float)10.0


RAISESKILL+1D:
  jmp skillmem

return:


[DISABLE]

define(RAISESKILL,Skills:RaiseSkill)

RAISESKILL+1D:
  db F3 0F 11 55 C8

dealloc(skillmem)

</AssemblerScript>
        </CheatEntry>
        <CheatEntry>
          <ID>33</ID>
          <Description>"Skill Multiplier x25"</Description>
          <VariableType>Auto Assembler Script</VariableType>
          <AssemblerScript>[ENABLE]

{$lua}
if syntaxcheck then return end

-- Only allow one Skill Multiplier child to be active
local parent = memrec.Parent

if parent then
  for i = 0, parent.Count - 1 do
    local mr = parent.Child[i]

    if mr ~= memrec and mr.Active then
      mr.Active = false
    end
  end
end

if LaunchMonoDataCollector() == 0 then
  error("Could not activate Mono. Make sure Valheim is fully loaded.")
end
{$asm}

define(RAISESKILL,Skills:RaiseSkill)

assert(RAISESKILL+1D,F3 0F 11 55 C8)

alloc(skillmem,$1000,RAISESKILL+1D)

label(return)
label(xpMultiplier)

skillmem:

  // XMM2 = normal skill XP factor
  mulss xmm2,[xpMultiplier]

  // Original instruction
  movss [rbp-38],xmm2

  jmp return

xpMultiplier:
  dd (float)25.0


RAISESKILL+1D:
  jmp skillmem

return:


[DISABLE]

define(RAISESKILL,Skills:RaiseSkill)

RAISESKILL+1D:
  db F3 0F 11 55 C8

dealloc(skillmem)

</AssemblerScript>
        </CheatEntry>
        <CheatEntry>
          <ID>34</ID>
          <Description>"Skill Multiplier x50"</Description>
          <VariableType>Auto Assembler Script</VariableType>
          <AssemblerScript>[ENABLE]

{$lua}
if syntaxcheck then return end

-- Only allow one Skill Multiplier child to be active
local parent = memrec.Parent

if parent then
  for i = 0, parent.Count - 1 do
    local mr = parent.Child[i]

    if mr ~= memrec and mr.Active then
      mr.Active = false
    end
  end
end

if LaunchMonoDataCollector() == 0 then
  error("Could not activate Mono. Make sure Valheim is fully loaded.")
end
{$asm}

define(RAISESKILL,Skills:RaiseSkill)

assert(RAISESKILL+1D,F3 0F 11 55 C8)

alloc(skillmem,$1000,RAISESKILL+1D)

label(return)
label(xpMultiplier)

skillmem:

  // XMM2 = normal skill XP factor
  mulss xmm2,[xpMultiplier]

  // Original instruction
  movss [rbp-38],xmm2

  jmp return

xpMultiplier:
  dd (float)50.0


RAISESKILL+1D:
  jmp skillmem

return:


[DISABLE]

define(RAISESKILL,Skills:RaiseSkill)

RAISESKILL+1D:
  db F3 0F 11 55 C8

dealloc(skillmem)

</AssemblerScript>
        </CheatEntry>
        <CheatEntry>
          <ID>35</ID>
          <Description>"Skill Multiplier x100"</Description>
          <VariableType>Auto Assembler Script</VariableType>
          <AssemblerScript>[ENABLE]

{$lua}
if syntaxcheck then return end

-- Only allow one Skill Multiplier child to be active
local parent = memrec.Parent

if parent then
  for i = 0, parent.Count - 1 do
    local mr = parent.Child[i]

    if mr ~= memrec and mr.Active then
      mr.Active = false
    end
  end
end

if LaunchMonoDataCollector() == 0 then
  error("Could not activate Mono. Make sure Valheim is fully loaded.")
end
{$asm}

define(RAISESKILL,Skills:RaiseSkill)

assert(RAISESKILL+1D,F3 0F 11 55 C8)

alloc(skillmem,$1000,RAISESKILL+1D)

label(return)
label(xpMultiplier)

skillmem:

  // XMM2 = normal skill XP factor
  mulss xmm2,[xpMultiplier]

  // Original instruction
  movss [rbp-38],xmm2

  jmp return

xpMultiplier:
  dd (float)1000.0


RAISESKILL+1D:
  jmp skillmem

return:


[DISABLE]

define(RAISESKILL,Skills:RaiseSkill)

RAISESKILL+1D:
  db F3 0F 11 55 C8

dealloc(skillmem)

</AssemblerScript>
        </CheatEntry>
      </CheatEntries>
    </CheatEntry>
    <CheatEntry>
      <ID>39</ID>
      <Description>"Free Build (No Resources)"</Description>
      <VariableType>Auto Assembler Script</VariableType>
      <AssemblerScript>[ENABLE]

{$lua}
if syntaxcheck then return end

------------------------------------------------------------
-- VALHEIM FREE BUILDING
--
-- Patches:
--
--   ALL Player:HaveRequirements overloads -&gt; TRUE
--   Player:HaveRequirementItems           -&gt; TRUE
--   Player:ConsumeResources               -&gt; RETURN
--
------------------------------------------------------------

if LaunchMonoDataCollector() == 0 then
  error(
    "Could not activate Mono. Make sure Valheim is fully loaded."
  )
end

------------------------------------------------------------
-- Don't allow accidental double-enable
------------------------------------------------------------

if _G.ValheimFreeBuild then
  error(
    "Free Building patch is already active"
  )
end

------------------------------------------------------------
-- Find Player class
------------------------------------------------------------

local playerClass =
  mono_findClass("", "Player")

if not playerClass or playerClass == 0 then
  error("Could not find Player class")
end

------------------------------------------------------------
-- Enumerate Player methods
------------------------------------------------------------

local methods =
  mono_class_enumMethods(playerClass)

if not methods then
  error("Could not enumerate Player methods")
end

------------------------------------------------------------
-- Patch storage
------------------------------------------------------------

local patches = {}

------------------------------------------------------------
-- Resolve exact Mono method
------------------------------------------------------------

local function getJitAddress(method)

  local compiled =
    mono_compile_method(method)

  if not compiled or compiled == 0 then
    return nil,nil
  end

  local ji =
    mono_getJitInfo(compiled)

  if not ji then
    return nil,nil
  end

  return ji.code_start,ji.code_size

end

------------------------------------------------------------
-- Save a patch
------------------------------------------------------------

local function savePatch(
  name,
  method,
  address,
  size,
  patchBytes
)

  local original =
    readBytes(
      address,
      #patchBytes,
      true
    )

  if not original then
    error(
      "Could not save original bytes for "..name
    )
  end

  ----------------------------------------------------------
  -- Safety:
  --
  -- Current methods should start:
  --
  -- 55
  -- 48 8B EC
  --
  -- push rbp
  -- mov rbp,rsp
  ----------------------------------------------------------

  if original[1] ~= 0x55 then
    error(
      name..
      ": unexpected method entry byte"
    )
  end

  table.insert(
    patches,
    {
      name = name,
      method = method,
      address = address,
      size = size,
      original = original,
      patch = patchBytes
    }
  )

end

------------------------------------------------------------
-- Find every relevant method
------------------------------------------------------------

local requirementCount = 0
local requirementItemsCount = 0
local consumeCount = 0

for _,m in ipairs(methods) do

  local name =
    m.name or ""

  local method =
    m.method

  if method and method ~= 0 then

    --------------------------------------------------------
    -- ALL HaveRequirements overloads
    --------------------------------------------------------

    if name == "HaveRequirements" then

      local addr,size =
        getJitAddress(method)

      if addr then

        requirementCount =
          requirementCount + 1

        print(string.format(
          "[Free Building] HaveRequirements #%d: %X size=%X",
          requirementCount,
          addr,
          size
        ))

        ----------------------------------------------------
        -- mov eax,1
        -- ret
        ----------------------------------------------------

        savePatch(
          "HaveRequirements #"..
          requirementCount,
          method,
          addr,
          size,
          {
            0xB8,
            0x01,0x00,0x00,0x00,
            0xC3
          }
        )

      end

    --------------------------------------------------------
    -- HaveRequirementItems
    --------------------------------------------------------

    elseif name == "HaveRequirementItems" then

      local addr,size =
        getJitAddress(method)

      if addr then

        requirementItemsCount =
          requirementItemsCount + 1

        print(string.format(
          "[Free Building] HaveRequirementItems #%d: %X size=%X",
          requirementItemsCount,
          addr,
          size
        ))

        savePatch(
          "HaveRequirementItems #"..
          requirementItemsCount,
          method,
          addr,
          size,
          {
            0xB8,
            0x01,0x00,0x00,0x00,
            0xC3
          }
        )

      end

    --------------------------------------------------------
    -- ConsumeResources
    --------------------------------------------------------

    elseif name == "ConsumeResources" then

      local addr,size =
        getJitAddress(method)

      if addr then

        consumeCount =
          consumeCount + 1

        print(string.format(
          "[Free Building] ConsumeResources #%d: %X size=%X",
          consumeCount,
          addr,
          size
        ))

        ----------------------------------------------------
        -- ret
        ----------------------------------------------------

        savePatch(
          "ConsumeResources #"..
          consumeCount,
          method,
          addr,
          size,
          {
            0xC3
          }
        )

      end

    end

  end

end

------------------------------------------------------------
-- Sanity checks BEFORE changing anything
------------------------------------------------------------

if requirementCount == 0 then
  error(
    "No HaveRequirements methods found"
  )
end

if requirementItemsCount == 0 then
  error(
    "No HaveRequirementItems methods found"
  )
end

if consumeCount == 0 then
  error(
    "No ConsumeResources methods found"
  )
end

print("")
print(string.format(
  "[Free Building] Found %d HaveRequirements overload(s)",
  requirementCount
))

print(string.format(
  "[Free Building] Found %d HaveRequirementItems method(s)",
  requirementItemsCount
))

print(string.format(
  "[Free Building] Found %d ConsumeResources method(s)",
  consumeCount
))

------------------------------------------------------------
-- Apply patches
------------------------------------------------------------

for _,p in ipairs(patches) do

  writeBytes(
    p.address,
    table.unpack(p.patch)
  )

  print(string.format(
    "[Free Building] Patched %s at %X",
    p.name,
    p.address
  ))

end

------------------------------------------------------------
-- Store everything for DISABLE
------------------------------------------------------------

_G.ValheimFreeBuild =
  patches

print("")
print(
  "[Free Building] SUCCESS"
)

print(
  "[Free Building] All requirement checks forced TRUE"
)

print(
  "[Free Building] Resource consumption disabled"
)

{$asm}


[DISABLE]

{$lua}
if syntaxcheck then return end

local patches =
  _G.ValheimFreeBuild

if patches then

  ----------------------------------------------------------
  -- Restore every patched method
  ----------------------------------------------------------

  for _,p in ipairs(patches) do

    if p.address and
       p.original then

      writeBytes(
        p.address,
        table.unpack(p.original)
      )

      print(string.format(
        "[Free Building] Restored %s at %X",
        p.name,
        p.address
      ))

    end

  end

end

_G.ValheimFreeBuild = nil

print(
  "[Free Building] Original methods restored"
)

{$asm}
</AssemblerScript>
    </CheatEntry>
    <CheatEntry>
      <ID>56</ID>
      <Description>"Guaranteed Forge of Potential"</Description>
      <VariableType>Auto Assembler Script</VariableType>
      <AssemblerScript>[ENABLE]

{$lua}
if syntaxcheck then return end

if LaunchMonoDataCollector() == 0 then
  error("Could not activate Mono")
end

if _G.ForgeRollPatch then
  error("Forge roll patch is already active")
end

local method = mono_findMethod("", "InventoryGui", "DoCrafting")
if not method or method == 0 then
  error("InventoryGui:DoCrafting not found")
end

local compiled = mono_compile_method(method)
local ji = mono_getJitInfo(compiled)
if not ji then error("JIT information unavailable") end

local pattern = {
  0xF3,0x0F,0x11,0xAD,0x2C,0xFD,0xFF,0xFF
}

local data = readBytes(ji.code_start,ji.code_size,true)
if not data then error("Could not read method") end

local matches = {}

for i=1,#data-#pattern+1 do
  local ok=true
  for j=1,#pattern do
    if data[i+j-1]~=pattern[j] then
      ok=false
      break
    end
  end
  if ok then
    table.insert(matches,ji.code_start+i-1)
  end
end

if #matches ~= 1 then
  error("Expected one roll-storage instruction; found "..#matches)
end

local addr = matches[1]

-- xorps xmm5,xmm5
-- movss [rbp-000002D4],xmm5
-- Requires 11 bytes, so patch the preceding conversion
-- and the store as one contiguous block.

local start = addr-5

local original = readBytes(start,13,true)
if not original then error("Could not save original bytes") end

local expected = {
  0xF2,0x0F,0x5A,0xE8,
  0xF3,0x0F,0x11,0xAD,0x2C,0xFD,0xFF,0xFF
}

-- Verify the exact conversion/store sequence.
-- The conversion starts 4 bytes before the store.
start = addr-4
original = readBytes(start,12,true)

for i=1,#expected do
  if original[i]~=expected[i] then
    error("Unexpected conversion/store bytes; no patch applied")
  end
end

local replacement = {
  0x0F,0x57,0xED, -- xorps xmm5,xmm5
  0x90,           -- nop
  0xF3,0x0F,0x11,0xAD,0x2C,0xFD,0xFF,0xFF
}

local unpackBytes=table.unpack or unpack

if not writeBytes(start,unpackBytes(replacement)) then
  error("Failed to patch roll")
end

_G.ForgeRollPatch={
  address=start,
  original=original
}

print(string.format(
  "[Forge] Roll forced to zero at %X",
  start
))

{$asm}

[DISABLE]

{$lua}
if syntaxcheck then return end

local patch=_G.ForgeRollPatch

if patch then
  local unpackBytes=table.unpack or unpack
  writeBytes(patch.address,unpackBytes(patch.original))
  _G.ForgeRollPatch=nil
  print("[Forge] Original roll restored")
end

{$asm}
</AssemblerScript>
    </CheatEntry>
  </CheatEntries>
  <UserdefinedSymbols/>
</CheatTable>
