Emberveil sourcetests/BasicSkillsCheck.java
import com.rs2.Constants;
import com.rs2.event.CycleEventHandler;
import com.rs2.game.content.skills.SkillHandler;
import com.rs2.game.content.skills.core.Fishing;
import com.rs2.game.content.skills.cooking.Cooking;
import com.rs2.game.content.skills.woodcutting.Woodcutting;
import com.rs2.game.items.ItemDefinitions;
import com.rs2.game.players.Client;
import org.apollo.cache.IndexedFileSystem;
import org.apollo.cache.decoder.ItemDefinitionDecoder;
import java.nio.file.Paths;
import java.lang.reflect.Field;
import java.util.Arrays;
/** Disposable players only: no save files, sockets or live world. */
public final class BasicSkillsCheck {
static int checks,failures;
static void check(boolean ok,String label){checks++;if(!ok){failures++;System.out.println("FAIL "+label);}}
static class Fixture extends Client {
Fixture()throws Exception{super(null,1);playerName="skillqa";tutorialProgress=36;isActive=true;randomEventsEnabled=false;absX=3222;absY=3218;objectX=3223;objectY=3218;respawnTimer=-6;
Arrays.fill(playerLevel,99);Arrays.fill(playerXP,13034431);Arrays.fill(playerEquipment,-1);
getOutStream().packetEncryption=new org.apollo.util.security.IsaacRandom(new int[]{1,2,3,4});
Field instance=CycleEventHandler.class.getDeclaredField("instance");instance.setAccessible(true);instance.set(null,new CycleEventHandler());}
public void flushOutStream(){getOutStream().currentOffset=0;}
void item(int slot,int id,int amount){playerItems[slot]=id+1;playerItemsN[slot]=amount;}
}
static void tick(int count){for(int i=0;i<count;i++)CycleEventHandler.getSingleton().process();}
static Fixture fishing(int bait)throws Exception{Fixture p=new Fixture();p.item(0,309,1);p.item(1,314,bait);Fishing.fishingNPC(p,1,309);return p;}
static void fishingChecks()throws Exception {
for(int i=0;i<24;i++){
Fixture p=fishing(1);int xp=p.playerXP[Constants.FISHING];tick(10);
int trout=p.getItemAssistant().getItemAmount(335),salmon=p.getItemAssistant().getItemAmount(331);
check(trout+salmon==1,"one bait produces one fish");
check(p.playerXP[Constants.FISHING]-xp==4*(trout*50+salmon*70),"fishing XP matches caught fish");
check(!p.getItemAssistant().playerHasItem(314),"bait consumed exactly once");
tick(30);check(p.getItemAssistant().getItemAmount(335)+p.getItemAssistant().getItemAmount(331)==1,"empty bait stops future catches");
}
Fixture p=fishing(5);int xp=p.playerXP[10];tick(5);p.playerItems[0]=p.playerItemsN[0]=0;tick(3);
check(p.playerXP[10]==xp,"removed rod cannot award XP before next validation tick");
p=fishing(5);xp=p.playerXP[10];p.disconnected=true;tick(10);check(p.playerXP[10]==xp,"disconnected player cannot catch fish");
}
static void cookingChecks()throws Exception {
Fixture p=new Fixture();p.item(0,317,1);int xp=p.playerXP[7];Cooking.cookItem(p,317,1,2732);tick(4);
check(p.getItemAssistant().playerHasItem(315)&&!p.getItemAssistant().playerHasItem(317),"shrimp converts once");check(p.playerXP[7]-xp==120,"cooking uses server 4x XP");tick(12);check(!p.playerIsCooking,"completed cooking clears action");
p=new Fixture();p.item(0,317,1);xp=p.playerXP[7];Cooking.cookItem(p,317,0,2732);tick(4);check(p.playerXP[7]==xp&&p.getItemAssistant().playerHasItem(317),"zero quantity cannot cook a free extra item");
p=new Fixture();p.item(0,317,1);xp=p.playerXP[7];Cooking.cookItem(p,317,1,2732);p.absX+=10;tick(4);check(p.playerXP[7]==xp&&p.getItemAssistant().playerHasItem(317),"out of reach cooking preserves raw food");check(!p.playerIsCooking,"out of reach cooking releases action");
p=new Fixture();p.item(0,317,1);xp=p.playerXP[7];Cooking.cookItem(p,317,1,2732);p.disconnected=true;tick(4);check(p.playerXP[7]==xp,"disconnected cooking grants no XP");
java.lang.Object shark=Cooking.forId(383);Field threshold=shark.getClass().getDeclaredField("stopBurnGloves");threshold.setAccessible(true);check(threshold.getInt(shark)==94,"gauntlets retain shark no-burn level 94");
p=new Fixture();p.item(0,317,2);xp=p.playerXP[7];Cooking.cookItem(p,317,99,2732);tick(16);check(p.getItemAssistant().getItemAmount(315)==2&&p.playerXP[7]-xp==240,"cook-all clamps to owned food");
p=new Fixture();p.item(0,383,1);p.playerLevel[7]=1;Cooking.cookItem(p,383,1,2732);tick(8);check(p.getItemAssistant().playerHasItem(383)&&!p.playerIsCooking,"low-level shark cooking cannot bypass requirement");
}
static void gatheringChecks()throws Exception {
Fixture p=new Fixture();p.item(0,1265,1);int xp=p.playerXP[14];p.getMining().startMining(p,2491,3223,3218,0);tick(2);check(p.playerXP[14]>xp,"essence mining rewards XP");check(p.getItemAssistant().playerHasItem(7936),"high-level essence yields pure essence");SkillHandler.resetSkills(p);xp=p.playerXP[14];tick(15);check(p.playerXP[14]==xp,"cancelled mining stops rewards");
p=new Fixture();p.item(0,1265,1);xp=p.playerXP[14];p.getMining().startMining(p,2491,3223,3218,0);p.playerItems[0]=p.playerItemsN[0]=0;tick(2);check(p.playerXP[14]==xp,"removed pickaxe stops reward");
p=new Fixture();p.item(0,1265,1);xp=p.playerXP[14];p.getMining().startMining(p,2491,3223,3218,0);p.disconnected=true;tick(2);check(p.playerXP[14]==xp,"disconnected mining stops reward");
p=new Fixture();p.item(0,1351,1);xp=p.playerXP[8];Woodcutting.startWoodcutting(p,1276,3223,3218,0);p.playerItems[0]=p.playerItemsN[0]=0;tick(3);check(p.playerXP[8]==xp,"removed axe stops reward");
p=new Fixture();p.item(0,1351,1);xp=p.playerXP[8];Woodcutting.startWoodcutting(p,1276,3223,3218,0);p.absX+=10;tick(3);check(p.playerXP[8]==xp,"out of reach woodcutting stops reward");
p=new Fixture();p.item(0,1351,1);xp=p.playerXP[8];Woodcutting.startWoodcutting(p,1276,3223,3218,0);tick(3);check(p.getItemAssistant().playerHasItem(1511)&&p.playerXP[8]-xp==100,"ordinary tree produces one log and 4x XP");
p=new Fixture();p.item(0,1265,1);xp=p.playerXP[14];p.getMining().startMining(p,2491,3223,3218,0);for(int i=1;i<28;i++)p.item(i,995,1);tick(2);check(p.playerXP[14]==xp,"inventory filled during mining grants no XP without ore");
p=new Fixture();p.item(0,1265,1);p.getMining().startMining(p,2491,3223,3218,0);tick(30);
check(p.getItemAssistant().getItemAmount(7936)>=10,"continuous essence mining continues until inventory fills");
check(CycleEventHandler.getSingleton().getEventsCount()<=4,"long essence mining keeps background timers bounded");
p=new Fixture();p.item(0,1351,1);for(int i=0;i<50;i++)Woodcutting.startWoodcutting(p,1281,3223,3218,0);tick(1);
check(CycleEventHandler.getSingleton().getEventsCount()<=2,"repeated tree clicks do not accumulate animation timers");
}
public static void main(String[] args)throws Exception{
Constants.XP_RATE=4;new ItemDefinitionDecoder(new IndexedFileSystem(Paths.get("data/cache"),true)).run();ItemDefinitions.load();
fishingChecks();cookingChecks();gatheringChecks();
System.out.println("Basic skill checks="+checks+" failures="+failures);if(failures>0)System.exit(1);
}
}