package speedytools.serverside.ingametester; import net.minecraft.util.BlockPos; import net.minecraft.util.ChatComponentText; import net.minecraft.util.IChatComponent; import net.minecraftforge.fml.relauncher.Side; import net.minecraft.entity.player.EntityPlayerMP; import net.minecraft.item.ItemStack; //import org.objenesis.Objenesis; //import org.objenesis.ObjenesisStd; import speedytools.common.items.RegistryForItems; import speedytools.common.network.ServerStatus; import speedytools.common.utilities.QuadOrientation; import speedytools.common.utilities.ResultWithReason; import speedytools.serverside.network.SpeedyToolsNetworkServer; /** * Created by TheGreyGhost on 26/06/14. * used for in-game testing of the client user interface to simulate different server conditions * Test mode is selected by putting the test ItemSpeedyTester item into the leftmost inventory slot and changing the stack size * * test condition: * (1) server state forced to PERFORMING_BACKUP * (2) server state forced to PERFORMING_YOUR_ACTION, playerBeingServiced = the client * (3) server state forced to UNDOING_YOUR_ACTION, playerBeingServiced = the client * (4) server state forced to PERFORMING_YOUR_ACTION, playerBeingServiced = null * (5) server state forced to PERFORMING_YOUR_ACTION, playerBeingServiced = someone else. * (6) - (10) = same as (1 - 5) except server returns to IDLE after a while, and sends the status to client * For states 1 - 5, the status stays on the server only, client side forced to IDLE. * For states 1 - 5, the percent complete slowly increases over 10 seconds from 0 to 100, stays there for 5 seconds, * then starts from 0 in an endless cycle * For states 6 - 10, the percent complete slowly increases over 10 seconds from 0 to 100, then goes to IDLE for 5 seconds. * Repeats in an endless cycle. * (11) = backups, placements, and undo are simulated. Will succeed unless cancelled. Will take 10 seconds. * (12) = backups, placements, and undo are simulated but will fail immediately. * (20 - 27) = combinations of (11) and (12): +1 = backup succeed, +2 = placement succeed, +4 = undo succeed * * Test plan: messages to test are * Server-side failures: * - selection not transmitted yet (not tested) * 26 - backup failed * 1 - world backup in progress * 2 - own action already in progress * 3 - own undo already in progress * 4, 5 - someone else is busy * Client-side failures: * 6 - server backup in progress * - selection not transmitted yet * 9, 10 - someone else is busy */ public class InGameStatusSimulator { public InGameStatusSimulator() { // Objenesis objenesis = new ObjenesisStd(); //todo - reinstate Objenesis for entityPlayerMPDummy // // entityPlayerMPDummy = (EntityPlayerMPDummy) objenesis.newInstance(EntityPlayerMPDummy.class); testMode = 0; } public void setTestMode(EntityPlayerMP entityPlayerMP) { testMode = 0; if (entityPlayerMP == null || entityPlayerMP.inventory == null) return; ItemStack firstSlotItem = entityPlayerMP.inventory.getStackInSlot(0); if (firstSlotItem == null) return; if (firstSlotItem.getItem() != RegistryForItems.itemSpeedyTester) return; testMode = firstSlotItem.stackSize; } public boolean isTestModeActivated() { return testMode != 0; } public ServerStatus getForcedStatus(ServerStatus unforcedStatus, Side forWhichSide) { int status = testMode; if (testMode >= 6 && testMode <= 10) { status = testMode - 5; forWhichSide = Side.SERVER; long nanoseconds = System.nanoTime(); long CYCLE_TIME_NS = 15 * 1000 * 1000L * 1000; long IDLE_TIME_NS = 5 * 1000 * 1000L * 1000; long cyclePosition = nanoseconds % CYCLE_TIME_NS; if (cyclePosition <= IDLE_TIME_NS) return ServerStatus.IDLE; } switch (status) { case 1: return forWhichSide == Side.SERVER ? ServerStatus.PERFORMING_BACKUP : ServerStatus.IDLE; case 2: return forWhichSide == Side.SERVER ? ServerStatus.PERFORMING_YOUR_ACTION : ServerStatus.IDLE; case 3: return forWhichSide == Side.SERVER ? ServerStatus.UNDOING_YOUR_ACTION : ServerStatus.IDLE; case 4: return forWhichSide == Side.SERVER ? ServerStatus.PERFORMING_YOUR_ACTION : ServerStatus.IDLE; case 5: return forWhichSide == Side.SERVER ? ServerStatus.PERFORMING_YOUR_ACTION : ServerStatus.IDLE; } return unforcedStatus; } public EntityPlayerMP getForcedPlayerBeingServiced(EntityPlayerMP unforcedEntityPlayerMP, EntityPlayerMP thePlayer, Side forWhichSide) { int status = testMode; if (testMode >= 6 && testMode <= 10) { status = testMode - 5; long nanoseconds = System.nanoTime(); long CYCLE_TIME_NS = 15 * 1000 * 1000L * 1000; long IDLE_TIME_NS = 5 * 1000 * 1000L * 1000; long cyclePosition = nanoseconds % CYCLE_TIME_NS; if (cyclePosition <= IDLE_TIME_NS) return unforcedEntityPlayerMP; } switch (status) { case 2: return thePlayer; case 3: return thePlayer; case 4: return null; case 5: return entityPlayerMPDummy; } return unforcedEntityPlayerMP; } public byte getForcedPercentComplete(byte unforcedPercentComplete, Side forWhichSide) { if (testMode >= 6 && testMode <= 10) { long nanoseconds = System.nanoTime(); long CYCLE_TIME_NS = 15 * 1000 * 1000L * 1000; long IDLE_TIME_NS = 5 * 1000 * 1000L * 1000; long cyclePosition = nanoseconds % CYCLE_TIME_NS; if (cyclePosition <= IDLE_TIME_NS) return 0; long percentage = (cyclePosition - IDLE_TIME_NS) / ( CYCLE_TIME_NS / 100); if (percentage > 100) percentage = 100; return (byte)percentage; } if (testMode >= 1 && testMode <= 5) { long nanoseconds = System.nanoTime(); long CYCLE_TIME_NS = 15 * 1000 * 1000L * 1000; long HOLD_AT_MAX_PERCENT = 50; long percentage = (nanoseconds % CYCLE_TIME_NS) / (CYCLE_TIME_NS / (100 + HOLD_AT_MAX_PERCENT)); if (percentage > 100) percentage = 100; return (byte)percentage; } return unforcedPercentComplete; } /** simulate this method * @return null if not simulated (-> progress to real code) */ public ResultWithReason prepareForToolAction(SpeedyToolsNetworkServer speedyToolsNetworkServer, EntityPlayerMP player) { final int TEST_BACKUP_FLAG = 1; if (testMode >= 20 && testMode <= 27) { if (((testMode - 20) & TEST_BACKUP_FLAG) == 0) { return ResultWithReason.failure("Simulated Backup Failure"); } } else { if (testMode == 12) { return ResultWithReason.failure("Simulated Backup Failure"); } if (testMode != 11) return null; } testInProgress = TestInProgress.PREPARE_FOR_TOOL_ACTION; testStartTime = System.nanoTime(); testPlayer = player; speedyToolsNetworkServer.changeServerStatus(ServerStatus.PERFORMING_BACKUP, player, (byte)0); return ResultWithReason.success(); } /** simulate this method * @return null if not simulated (-> progress to real code) */ public ResultWithReason performUndoOfCurrentAction(SpeedyToolsNetworkServer speedyToolsNetworkServer, EntityPlayerMP player, int undoSequenceNumber, int actionSequenceNumber) { final int TEST_UNDO_FLAG = 4; if (testMode >= 20 && testMode <= 27) { if (((testMode - 20) & TEST_UNDO_FLAG) == 0) { return ResultWithReason.failure("Simulated Undo Current Failure"); } } else { if (testMode == 12) { return ResultWithReason.failure("Simulated Undo Current Failure"); } if (testMode != 11) return null; } testInProgress = TestInProgress.PERFORM_UNDO_OF_CURRENT_ACTION; testStartTime = System.nanoTime(); testPlayer = player; testUndoSequenceNumber = undoSequenceNumber; speedyToolsNetworkServer.changeServerStatus(ServerStatus.UNDOING_YOUR_ACTION, player, (byte)0); speedyToolsNetworkServer.actionCompleted(player, actionSequenceNumber); return ResultWithReason.success(); } /** simulate this method * @return null if not simulated (-> progress to real code) */ public ResultWithReason performUndoOfLastAction(SpeedyToolsNetworkServer speedyToolsNetworkServer, EntityPlayerMP player, int undoSequenceNumber) { final int TEST_UNDO_FLAG = 4; if (testMode >= 20 && testMode <= 27) { if (((testMode - 20) & TEST_UNDO_FLAG) == 0) { return ResultWithReason.failure("Simulated Undo Last Failure"); } } else { if (testMode == 12) { return ResultWithReason.failure("Simulated Undo Last Failure"); } if (testMode != 11) return null; } testInProgress = TestInProgress.PERFORM_UNDO_OF_LAST_ACTION; testStartTime = System.nanoTime(); testPlayer = player; testUndoSequenceNumber = undoSequenceNumber; speedyToolsNetworkServer.changeServerStatus(ServerStatus.UNDOING_YOUR_ACTION, player, (byte)0); return ResultWithReason.success(); } /** simulate this method * @return null if not simulated (-> progress to real code) */ public ResultWithReason performToolAction(SpeedyToolsNetworkServer speedyToolsNetworkServer, EntityPlayerMP player, int sequenceNumber, int toolID, int xpos, int ypos, int zpos, QuadOrientation quadOrientation, BlockPos initalSelectionOrigin) { final int TEST_ACTION_FLAG = 2; if (testMode >= 20 && testMode <= 27) { if (((testMode - 20) & TEST_ACTION_FLAG) == 0) { return ResultWithReason.failure("Simulated Action Failure"); } } else { if (testMode == 12) { return ResultWithReason.failure("Simulated Action Failure"); } if (testMode != 11) return null; } testInProgress = TestInProgress.PERFORM_TOOL_ACTION; testStartTime = System.nanoTime(); testPlayer = player; testActionSequenceNumber = sequenceNumber; speedyToolsNetworkServer.changeServerStatus(ServerStatus.PERFORMING_YOUR_ACTION, player, (byte)0); return ResultWithReason.success(); } /** * Update the server status according to current test (use proper code, don't force) * @param speedyToolsNetworkServer */ public void updateServerStatus(SpeedyToolsNetworkServer speedyToolsNetworkServer) { final long NANOSECONDS_PER_SECOND = 1000 * 1000 * 1000L; if (testInProgress == TestInProgress.NONE) return; final int TICKS_PER_STATUS_UPDATE = 20; if (++tickCount % TICKS_PER_STATUS_UPDATE != 0) return; long elapsedTime = System.nanoTime() - testStartTime; switch (testInProgress) { case PREPARE_FOR_TOOL_ACTION: { final long TEST_DURATION_SECONDS = 10; if (elapsedTime > TEST_DURATION_SECONDS * NANOSECONDS_PER_SECOND) { speedyToolsNetworkServer.changeServerStatus(ServerStatus.IDLE, null, (byte)0); testInProgress = TestInProgress.NONE; // System.out.println("Server: backup completed"); } else { long completion = 100 * elapsedTime / (TEST_DURATION_SECONDS * NANOSECONDS_PER_SECOND); speedyToolsNetworkServer.changeServerStatus(ServerStatus.PERFORMING_BACKUP, testPlayer, (byte)completion); } break; } case PERFORM_TOOL_ACTION: { final long TEST_DURATION_SECONDS = 10; if (elapsedTime > TEST_DURATION_SECONDS * NANOSECONDS_PER_SECOND) { speedyToolsNetworkServer.changeServerStatus(ServerStatus.IDLE, null, (byte)0); speedyToolsNetworkServer.actionCompleted(testPlayer, testActionSequenceNumber); // System.out.println("Server: actionCompleted # " + testActionSequenceNumber); testInProgress = TestInProgress.NONE; } else { long completion = 100 * elapsedTime / (TEST_DURATION_SECONDS * NANOSECONDS_PER_SECOND); speedyToolsNetworkServer.changeServerStatus(ServerStatus.PERFORMING_YOUR_ACTION, testPlayer, (byte)completion); } break; } case PERFORM_UNDO_OF_LAST_ACTION: case PERFORM_UNDO_OF_CURRENT_ACTION: { final long TEST_DURATION_SECONDS = 10; if (elapsedTime > TEST_DURATION_SECONDS * NANOSECONDS_PER_SECOND) { speedyToolsNetworkServer.changeServerStatus(ServerStatus.IDLE, null, (byte)0); speedyToolsNetworkServer.undoCompleted(testPlayer, testUndoSequenceNumber); // System.out.println("Server: undoCompleted # " + testUndoSequenceNumber); testInProgress = TestInProgress.NONE; } else { long completion = 100 * elapsedTime / (TEST_DURATION_SECONDS * NANOSECONDS_PER_SECOND); speedyToolsNetworkServer.changeServerStatus(ServerStatus.UNDOING_YOUR_ACTION, testPlayer, (byte)completion); } break; } } } private int testMode = 0; // 0 = none private EntityPlayerMPDummy entityPlayerMPDummy; enum TestInProgress {NONE, PREPARE_FOR_TOOL_ACTION, PERFORM_TOOL_ACTION, PERFORM_UNDO_OF_CURRENT_ACTION, PERFORM_UNDO_OF_LAST_ACTION}; TestInProgress testInProgress = TestInProgress.NONE; long testStartTime = 0; int tickCount = 0; EntityPlayerMP testPlayer = null; int testActionSequenceNumber; int testUndoSequenceNumber; class EntityPlayerMPDummy extends EntityPlayerMP { public EntityPlayerMPDummy() { super(null, null, null, null); } @Override public IChatComponent getDisplayName() { return new ChatComponentText("Dummy"); } } }