Couple of ways, you didn't specify which game so I'll write this for RS3:
Easiest way is only useful if the trees you're chopping give you one item per harvest (i.e. normal trees -> normal logs). In this case, you can use tabBackpack.waitForShift(), which can actually double as a timeout failsafe were you to set the function's parameter to something unreasonable.
So an example, say you just clicked a tree and you want to wait until a log has appeared in your inventory. You also recognize that other players might steal your tree before you successfully harvest the resource, so you want to create a failsafe as well. Using .waitForShift(), you'd do:
Simba Code:
tabBackpack.waitForShift(30000);
This will wait up to 30 seconds (30 thousand milliseconds) for the backpack count to change. If it does change at any point, the function will exit and the script will move on. If the backpack's count happens to not change, (and might never change) because someone stole your tree - no worries, the function will automatically time out after 30 seconds and the script will move on as normal.
***
Second way would be tracking the backpack shift, but in a slightly different way. .waitForShift() will exit instantly right when your backpack count changes by any amount (in both directions, gaining items or losing them) which might not be what we want.
Take a look at this function that I wrote for iOak:
Simba Code:
function isStillChopping():boolean;
var
startCount, i:integer;
begin
if (not isLoggedIn()) then
exit;
if tabBackpack.isFull() then
exit(false);
startCount := tabBackpack.count();
for i := 0 to (randomRange(minWait, maxWait)) do
begin
if tabBackpack.isFull() then
exit(false);
wait(randomRange(800, 1200));
end;
result := (tabBackpack.count() <> startCount);
writeDebug('Still chopping? ' + lowercase(toStr(result)));
end;
(this has been edited a tad for simplicity, and I haven't tested the function - it's only meant to show proof of concept)
minWait and maxWait are constants that the user would be asking to input when setting up the script.
Essentially, this function checks the backpack count several times, but waits in between singular checks. In this manner, the function can be used to accurately determine the status of our character when gathering a resource that provides several items per instance (say, oak trees).
If, at any point, the backpack count has changed, the function will return true and continue looping. If the backpack count hasn't changed, the function will return false and exit. The maxWait constant functions in a similar manner to .waitForShift()'s paremeter - preventing infinite loops.
***
The third way would be to use pixel shift. mainScreen.isPlayerAnimating() is a nice example of this, a function that uses pixel shift to return true if your player is animating (i.e. moving).
When woodcutting, this could be a problem because trees in RuneScape are big and green and leafy and sometimes cover your character, preventing Simba from detecting any movement. A pixel shift function would then return false, and move on to the next tree even though it hasn't finished chopping.
The solution to such a problem is to of course adjust the camera angle so your player is in full view ... but that gets into some (relatively) complicated stuff that I'm not going to cover in this post, but will if you wish me to.
Here's the same function from iOak as above, but edited to use pixel shift instead of inventory count:
Simba Code:
function isStillChopping():boolean;
var
pxShift:integer;
begin
if (not (isLoggedIn())) then
exit;
if tabBackpack.isFull() then
exit(false);
smartImage.drawBox(mainScreen.playerBox, false, clRed);
pxShift := getPixelShiftAverage(mainScreen.playerBox, 50, 500);
result := (pxShift > 150);
writeDebug('Still chopping? ' + lowercase(toStr(result)) + ', with an average pixel shift of ' + toStr(pxShift));
end;
This function will grab the pixel shift inside the mainScreen.playerBox for 500 milliseconds in 50 millisecond loops. After it's done that, it will then compare the average of those pixel shifts to the value we have set (150). Return true or false based on the outcome or the comparison. Loop again, or move on.
***
That about covers what I have to say on the matter - let me know if you need clarification on anything