Jump to content

Invisible Gingerbread Houses, with fix


CarlZalph
  • Pending

I believe there's a race condition between when a client sets the AnimState's bank/build and when the server sets it such that there's a chance one of the settings gets overridden or ignored.

Specifically in the case of the gingerbread houses the client and server both set these on entity creation, and then if the load pass happens the server tries to set it again the same frame.

 

In any case, I've changed around the prefab file to follow how the flower prefab sets and saves its animations so all clients see the same flower (now the same gingerbread house is seen for all) but also saves the animation as an integer index instead of string values for both the build and bank lowering save file sizes.

 

Here is a diff generated to reflect my changes:

  require "prefabutil"
  
  local assets =
  {
      Asset("ANIM", "anim/gingerbread_house1.zip"),
      Asset("ANIM", "anim/gingerbread_house2.zip"),
      Asset("ANIM", "anim/gingerbread_house3.zip"),
      Asset("ANIM", "anim/gingerbread_house4.zip"),
  }
  
  local prefabs =
  {
      "wintersfeastfuel",
      "gingerdeadpig",
      "crumbs",
  }
  
  SetSharedLootTable( 'gingerbreadhouse',
  {
      {'wintersfeastfuel',  1.00},
      {'crumbs',            1.00},
      {'crumbs',            1.00},
      {'crumbs',            1.00},
      {'crumbs',            1.00},
      {'crumbs',            1.00},
  })
  
  
  local animdata = 
  {
      { build = "gingerbread_house1", bank = "gingerbread_house1" },
-     { build = "gingerbread_house3", bank = "gingerbread_house2" },
      { build = "gingerbread_house2", bank = "gingerbread_house2" },
+     { build = "gingerbread_house3", bank = "gingerbread_house2" },
      { build = "gingerbread_house4", bank = "gingerbread_house1" },
  }
+ 
+ local function setanims(inst)
+     inst.AnimState:SetBank(animdata[inst.animindex].bank)
+     inst.AnimState:SetBuild(animdata[inst.animindex].build)
+     inst.AnimState:PlayAnimation("idle", true)
+ end
  
  local function onhammered(inst, worker)
      if inst.components.burnable ~= nil and inst.components.burnable:IsBurning() then
          inst.components.burnable:Extinguish()
      end
  
      local x, y, z = inst.Transform:GetWorldPosition()
      local fx = SpawnPrefab("collapse_small")
      fx.Transform:SetPosition(x, y, z)
      fx:SetMaterial("wood")
  
      if not inst:HasTag("burnt") then
          inst.components.lootdropper:DropLoot()
          if math.random() < 0.3 then
              local gingerdeadman = SpawnPrefab("gingerdeadpig")
              gingerdeadman.Transform:SetPosition(x, y, z)
              inst.components.lootdropper:SpawnLootPrefab("wintersfeastfuel", Point(x,y,z))
          end
      end
  
      inst:Remove()
  end
  
  local function onhit(inst, worker)
      if not inst:HasTag("burnt") then 
          inst.AnimState:PlayAnimation("hit")
          inst.AnimState:PushAnimation("idle")
      end
  end
  
  local function OnSave(inst, data)
-     data.build = inst.build
-     data.bank = inst.bank
+     data.animindex = inst.animindex
  end
  
  local function OnLoad(inst, data)
      if data ~= nil then
-         inst.build = data.build or animdata[1].build
-         inst.bank = data.bank or animdata[1].bank
- 
-         inst.AnimState:SetBuild(inst.build)
-         inst.AnimState:SetBank(inst.bank)
+         if data.animindex ~= nil and data.animindex > 0 and data.animindex <= #animdata
+         then
+             inst.animindex = data.animindex
+             setanims(inst)
+         end
      end
  end
  
  local function fn()
      local inst = CreateEntity()
  
      inst.entity:AddTransform()
      inst.entity:AddAnimState()
      inst.entity:AddSoundEmitter()
      inst.entity:AddNetwork()
  
      MakeObstaclePhysics(inst, 1)
- 
-     local index = math.random(#animdata)
-     inst.build = animdata[index].build
-     inst.bank  = animdata[index].bank
- 
-     inst.AnimState:SetBank (inst.bank)
-     inst.AnimState:SetBuild(inst.build)
-     inst.AnimState:PlayAnimation("idle", true)
  
      inst:AddTag("structure")
  
      MakeSnowCoveredPristine(inst)
  
      inst.entity:SetPristine()
  
      if not TheWorld.ismastersim then
          return inst
      end
+ 
+     inst.animindex = math.random(#animdata)
+     setanims(inst)
  
      inst:AddComponent("lootdropper")
      inst.components.lootdropper:SetChanceLootTable('gingerbreadhouse')
      
      inst:AddComponent("workable")
      inst.components.workable:SetWorkAction(ACTIONS.HAMMER)
      inst.components.workable:SetWorkLeft(4)
      inst.components.workable:SetOnFinishCallback(onhammered)
      inst.components.workable:SetOnWorkCallback(onhit)
  
      inst:AddComponent("inspectable")
  
      MakeSnowCovered(inst)
  
      MakeSmallBurnable(inst, nil, nil, true)
      MakeMediumPropagator(inst)
  
      inst.OnSave = OnSave
      inst.OnLoad = OnLoad
  
      return inst
  end
  
  return Prefab("gingerbreadhouse", fn, assets, prefabs)

 


Steps to Reproduce
Spawn a field of gingerbread houses, leave server and start it back up. A percentage of them at random will be invisible. Example code for generating a field of them: for i=0,100,2 do for j=0,100,2 do local it = SpawnPrefab("gingerbreadhouse") it.Transform:SetPosition(i,0,j) end end ThePlayer.Transform:SetPosition(50,0,50)
  • Thanks 1



User Feedback


There are no comments to display.



Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×
  • Create New...