BeamMP-Server icon indicating copy to clipboard operation
BeamMP-Server copied to clipboard

[Bug] Reloading plugin creates duplicate event timers

Open Dreae opened this issue 1 year ago • 1 comments

OS (windows, linux, ...): windows BeamMP-Server Version: master

Describe the bug Plugin auto-reloading on file changes does not clear timers created with CreateEventTimer causing duplicate timers to be created every time the plugin reloads. This also causes a crash if the event handler function changes name when the plugin reloads.

To Reproduce Steps to reproduce the behavior:

  1. Create a timer using CreateEventTimer
  2. Trigger a plugin reload by saving a file
  3. The event function will be called twice per-period due to duplicate event timers

Expected behavior Reloading plugins clears existing event timers so they will be recreated cleanly when the plugin restarts

Logs

[26/11/23 12:30:51] main.cpp:196 [INFO] ALL SYSTEMS STARTED SUCCESSFULLY, EVERYTHING IS OKAY
[26/11/23 12:30:52] LuaAPI.cpp:105 [LUA] Hello there	
[26/11/23 12:30:54] LuaAPI.cpp:105 [LUA] Hello there	
> status
BeamMP-Server Status:
	Total Players:             0
	Syncing Players:           0
	Synced Players:            0
	Connected Players:         0
	Guests:                    0
	Cars:                      0
	Uptime:                    10201ms (~0h) 
	Lua:
		Queued results to check:     0
		States:                      2
		Event timers:                1
		Event handlers:              1
	Subsystems:
		Good/Starting/Bad:           11/0/0
		Shutting down/Shut down:     0/0
		Good:                        [ Main, Server, Heartbeat, LuaEngine, Config, PPSMonitor, ResourceManager, UpdateCheck, PluginMonitor, TCPNetwork, UDPNetwork ]
		Starting:                    [  ]
		Bad:                         [  ]
		Shutting down:               [  ]
		Shut down:                   [  ]

[26/11/23 12:30:56] LuaAPI.cpp:105 [LUA] Hello there	
[26/11/23 12:30:58] LuaAPI.cpp:105 [LUA] Hello there	
[26/11/23 12:31:00] LuaAPI.cpp:105 [LUA] Hello there	
[26/11/23 12:31:01] TPluginMonitor.cpp:41 [INFO] File "Resources\Server\TimerTest\main.lua" changed, reloading
[26/11/23 12:31:02] LuaAPI.cpp:105 [LUA] Hello there	
[26/11/23 12:31:03] LuaAPI.cpp:105 [LUA] Hello there	
[26/11/23 12:31:04] LuaAPI.cpp:105 [LUA] Hello there	
[26/11/23 12:31:05] LuaAPI.cpp:105 [LUA] Hello there	
[26/11/23 12:31:06] LuaAPI.cpp:105 [LUA] Hello there	
[26/11/23 12:31:07] LuaAPI.cpp:105 [LUA] Hello there	
[26/11/23 12:31:07] TPluginMonitor.cpp:41 [INFO] File "Resources\Server\TimerTest\main.lua" changed, reloading
[26/11/23 12:31:08] LuaAPI.cpp:105 [LUA] Hello there	
[26/11/23 12:31:09] LuaAPI.cpp:105 [LUA] Hello there	
[26/11/23 12:31:09] LuaAPI.cpp:105 [LUA] Hello there	
[26/11/23 12:31:10] LuaAPI.cpp:105 [LUA] Hello there	
[26/11/23 12:31:11] LuaAPI.cpp:105 [LUA] Hello there	
[26/11/23 12:31:11] LuaAPI.cpp:105 [LUA] Hello there	
[26/11/23 12:31:12] LuaAPI.cpp:105 [LUA] Hello there	
> status
BeamMP-Server Status:
	Total Players:             0
	Syncing Players:           0
	Synced Players:            0
	Connected Players:         0
	Guests:                    0
	Cars:                      0
	Uptime:                    27491ms (~0h) 
	Lua:
		Queued results to check:     0
		States:                      2
		Event timers:                3
		Event handlers:              1
	Subsystems:
		Good/Starting/Bad:           11/0/0
		Shutting down/Shut down:     0/0
		Good:                        [ Main, Server, Heartbeat, LuaEngine, Config, PPSMonitor, ResourceManager, UpdateCheck, PluginMonitor, TCPNetwork, UDPNetwork ]
		Starting:                    [  ]
		Bad:                         [  ]
		Shutting down:               [  ]
		Shut down:                   [  ]

Additional Context Lua file used to reproduce the issue:

function SayHello()
    print("Hello there")
end

MP.RegisterEvent("TestTimer", "SayHello")
MP.CreateEventTimer("TestTimer", 2000)

Dreae avatar Nov 26 '23 19:11 Dreae

The way this currently is worked around is by always cancelling your event timers before starting them, much like unsubscribing event handlers in other languages before subscribing. Cancelling a nonexistent event timer is a no-op.

So, dirty fix:

  function SayHello()
      print("Hello there")
  end

  MP.RegisterEvent("TestTimer", "SayHello")
+ MP.CancelEventTimer("TestTimer")
  MP.CreateEventTimer("TestTimer", 2000)

Fixing this would require the following changes to be made to the lua/plugin engine:

  • [ ] Keep track of which event handler and event timer comes from which file (currently they're just lua chunks I'm pretty sure)
  • [ ] Cancel event timers that are started by a specific file when that file is reloaded

You could also potentially add an event for onBeforeReload or something, but nobody would end up using that IMO.

lionkor avatar Nov 27 '23 10:11 lionkor