Can I check pending events? Can I make on_tick function run last and not first?

Place to get help with not working mods / modding interface.
Rafiz
Inserter
Inserter
Posts: 32
Joined: Sun Jan 17, 2021 9:28 am
Contact:

Can I check pending events? Can I make on_tick function run last and not first?

Post by Rafiz »

I have two functions :

script.on_event({defines.events.on_train_changed_state},__train_changed_state)

script.on_event({defines.events.on_tick},__on_tick)

I must know if train changed state before on tick, because if it changed state, I stop train, but function __on_tick is always firing before __train_changed_state.
I already tried registering them in reverse order but it didn't helped.

Without looking for __train_changed_state game crashes, because I "try to change direction of automatic train", but I can't look it up before on_tick. (I know it is always firing after __on_tick, because I tried some game.prints() and those in __train_changed_state never fire up right before crash.

My on-tick code overwrites train physics, so it will indeed try to change direction of automatic train if it was moving in opposite direction. (it just sets speed, it doesn't look what speed is set by game)

I need to know in __on_tick if there's pending __train_changed state event, or I must get some post-tick function and I can move my __on_tick code here..

I also tried some weird methods like looking if train state was manual in last tick and isn't now, but it also won't cut it, because if it was automatic moving forward and I change it to automatic-backward it won't "flip" state and will crash..

Now that I think about it, I could check each frame for what station is next and if it changes, instantly stop train, but.... I want more elegant solution
User avatar
DaveMcW
Smart Inserter
Smart Inserter
Posts: 3716
Joined: Tue May 13, 2014 11:06 am
Contact:

Re: Can I check pending events? Can I make on_tick function run last and not first?

Post by DaveMcW »

I would simply stop using on_train_changed_state. It does not do much anyway. You can build your own function to track old_state if needed.
Rafiz wrote: Wed Aug 04, 2021 5:21 pmbut.... I want more elegant solution
If you are using on_tick, you have already failed at being elegant. Admit your defeat. :D
Last edited by DaveMcW on Wed Aug 04, 2021 5:44 pm, edited 1 time in total.
Rafiz
Inserter
Inserter
Posts: 32
Joined: Sun Jan 17, 2021 9:28 am
Contact:

Re: Can I check pending events? Can I make on_tick function run last and not first?

Post by Rafiz »

But when I try to use on_train_changed_state, somehow _on_tick gets fired first anyway. Maybe it's bug? Because specific event should always happen before timed events.

//edit : changed screenshot, previous wasnt showing enough code.
https://imgur.com/a/br4dVFk here's proof -> I mean proof that on_tick happens before on train changed state, error message doesn't matter, just wanted to stop execution right after showing what I wanted to show.

as for on_tick not being elegant, how am I going to overwrite physics, if not by using on_tick function? Game physics don't even work similarly to mine, I can't adjust parameters to work like I want it to work.

I could write my own tracker and not use on_train_changed_state, but ... events are here to use them, and they should fire in specific way (events that are triggered go instantly, and events that are timed(like on tick) go when it's their time).



//ok I finally stopped edditing :lol: sorry for my dislexion, at first I even didn't understood your message, cause I read it incorrectly, hence so many edits :oops:
User avatar
boskid
Factorio Staff
Factorio Staff
Posts: 3016
Joined: Thu Dec 14, 2017 6:56 pm
Contact:

Re: Can I check pending events? Can I make on_tick function run last and not first?

Post by boskid »

Changing sign of LuaTrain::speed for a train that is in automatic throws intentionally because otherwise the train would move backward on the path and there are no informations stored to decide onto which rails the back of the train should enter onto. A train in automatic has to always move in the direction of its path. Boolean which says if the path is a front-facing or back-facing is not exposed but if you have positive LuaTrain::speed, you should keep it positive (zero is also allowed). If it was negative (when a train is going backward), the speed will be negative and you are only allowed to write negative values here (zero is also allowed).

Train state changes are slightly deferred. They only happen after the update of a particular train but before update of other trains within the same tick. Those updates happen in the train manager. There is one special case where this event may be sent slightly earlier but this is related to the manual mode of a train.

on_tick events are dispatched slightly before map update, and the train manager updates during map update.

There are no good ways for you to control the train speed precisely in automatic because the train during its update is doing the acceleration logic and braking logic immediately followed by the move logic. If you would want to precisely control the train you would need to replace the train's fuel to something that gives no acceleration then you can kind of assume the speed will not increase due to built it logic, but at the same time the train speed would stay at 0 causing it to be not possible to query the train movement direction based on the LuaTrain::speed being positive or negative immediately after the train's state change event.
quyxkh
Smart Inserter
Smart Inserter
Posts: 1031
Joined: Sun May 08, 2016 9:01 am
Contact:

Re: Can I check pending events? Can I make on_tick function run last and not first?

Post by quyxkh »

Rafiz wrote: Wed Aug 04, 2021 5:21 pm I must know if train changed state before on tick, because if it changed state, I stop train, but function __on_tick is always firing before __train_changed_state.
Well, "must" if you don't stop the train in on_changed_state. My first-blush response would be that adapting to the actual event firing sequence is better than complicating the whole engine.
Rafiz
Inserter
Inserter
Posts: 32
Joined: Sun Jan 17, 2021 9:28 am
Contact:

Re: Can I check pending events? Can I make on_tick function run last and not first?

Post by Rafiz »

Thanks for detailed response.

As for controlling train speed precisely, it's really minor problem for me, *actual* speed is always wrong by very small amount, but acceleration and friction forces are way more convincing and that's what I only care about.

If I replaced fuel power modifiers with zero's I would have to overwrite car physics too, and do a lot more things, but it is interesting idea.
I think starting movement from stop wouldn't be problem, because when train is stopped, I use special case "simplePhysics" and it just *appends* sign equal to direction of acceleration, which is accesible from train riding_state.acceleration. It doesn't matter if acceleration is zero I believe - because my trains can start moving even if vanilla physics wouldn't let them start moving (like 20 wagons : 1 locomotive).

But now that I look at my code I actually already check for train moving direction. (looking at last 4 "meaningful" (not "end" only) lines..) I will look through my whole code again to find what fails. last "meaningful" line is the only place in whole code where I apply speed to factorio's LuaTrain, so it happens always just after check, and if check fails it sets my "train" speed to 0, right before applying it to factorio train.

Iii think I get it, if simple physics have some error, then it might propell full-stopped train (and it is fully stops in frame when I click auto-route) in opposite direction. My check checks only for opposite sign, it doesn't care if something was zero... So, train gets stopped by factorio, my simplePhysics propel it in wrong direction (to be found why), and last lines check don't apply, because it thinks - train was stopped, it has to start moving somehow, so both directions are allowed.

So I must look at error in simplePhysics... accelerate function should never return force value that is <0, but I will just give it a bit of math.abs(), to make sure... In this case acceleration direction MUST be ... actual acceleration direction, and I get it from factorio API, so it also have to be right.

Code: Select all

function simplePhysics(train,accel_direction) --starting from full stop.
	local force = acceleration_force(train);
	local acceleration = force*train.mass_reciprocal;
	velocity_mps = acceleration*framerate_multiplier;
	train.speed_mps = velocity_mps*accel_direction;
end

local discoveryInterval = 120;

function isStopped(train)
	return (train.factorioTrain.speed == 0) --I actually check for real-factorio train speed when deciding if train is *really* stopped.
end

function _on_tick(e)
	if (e.tick % discoveryInterval == 0) then
		registerTrains(); -- todo : throw away this discovery interval from on_tick. Use on_placed [placed.entity.type] instead.
	end
	for trainID, train in pairs(global.trainData) do
		if train.factorioTrain.valid then

			local accel_direction;
			if (train.factorioTrain.riding_state.acceleration == defines.riding.acceleration.accelerating) then
				accel_direction = 1;
			else
				if (train.factorioTrain.riding_state.acceleration == defines.riding.acceleration.reversing) then
					accel_direction = -1;
				else
					accel_direction = 0;
				end
			end


			if (isStopped(train)) then
				train.speed_mps=0; --if factorio train speed is 0, set our train speed to zero as-well.
				if(accel_direction~=0) then
					simplePhysics(train,accel_direction); --simpler case
				end
			else
				if(accel_direction~=0) then
					fullTrainPhysics(train,accel_direction); --it includes resistance physics. There could be separate call for resistancePhysics() right before/after, but I wanted all infomration accessible in 1 function for debugging.
				else
					resistancePhysics(train); --only resistance.
				end
			end
			if (math_sign(train.factorioTrain.speed)*math_sign(train.speed_mps)==-1) then
				train.speed_mps = 0;
			end
			train.factorioTrain.speed = mps_to_speed(train.speed_mps);
		end
	end
end 
Oook, I found out error. I changed isStopped(), during reviewing this responce, from checking my_train.speed, to checking factorio_train.speed. It don't crash anymore, tho now train if asked to switch auto-pilot direction just stays in place while going full-throttle and using fuel. It's another problem, which I probably can handle :)


Aah, and that another problem was easy to spot, while trying to repair *above described* error, I made this :

Code: Select all

function __train_changed_state(e)
	local factorioTrain = e.train;
	local train = global.trainData[factorioTrain.id];
	train.speed_mps = 0;
	factorioTrain.speed = 0;
end
And train just changes states continously when I stop him and he tries to start moving.

Oh, and now it changes to "breaking before station" too early, because it don't really know how long it will really break, but it's all smaller problems. I think biggest problem is solved, and that's what matters, thanks for responces.
Post Reply

Return to “Modding help”