Exemple #1
0
        /// <summary>
        /// Modify a chosen command in a code block
        /// <para>If the new command has more params than the old command (or the old command did not have params in the first place), the params location space may need to be expanded/relocated</para>
        /// </summary>
        /// <param name="commandLocation">The location of the command in the code block</param>
        /// <param name="oldPsaCommand">The old psa command (the one that is being modified)</param>
        /// <param name="newPsaCommand">The new psa command (the one that is replcaing the old psa command)</param>
        public void ModifyCommand(int commandLocation, PsaCommand oldPsaCommand, PsaCommand newPsaCommand)
        {
            if (PsaFile.DataSection[commandLocation + 1] >= 0 && PsaFile.DataSection[commandLocation + 1] < PsaFile.DataSectionSize)
            {
                // if there were no command params on the previous command
                if (oldPsaCommand.GetCommandParamsSize() == 0)
                {
                    // if there are no command params on new command, it's simply a swap out of command instructions with nothing else needed
                    if (newPsaCommand.GetCommandParamsSize() == 0)
                    {
                        PsaFile.DataSection[commandLocation] = newPsaCommand.Instruction;
                    }

                    // if there are command params on new command, create space for this new params location
                    else
                    {
                        CreateNewCommandParametersLocation(commandLocation, newPsaCommand);
                        PsaFileHelperMethods.ApplyHeaderUpdatesToAccountForPsaCommandChanges();
                    }
                }

                // if there are existing command params, they need to be overwritten, or the entire action may need to be relocated if not enough room for all the params
                else
                {
                    ModifyExistingCommandParametersLocation(commandLocation, oldPsaCommand, newPsaCommand);
                    PsaFileHelperMethods.ApplyHeaderUpdatesToAccountForPsaCommandChanges();
                }
            }
            else
            {
                throw new ApplicationException("Cannot modify command because it is not located within the data section");
            }
        }
Exemple #2
0
        /// <summary>
        /// This method is called when attempting to remove a param value that once pointed to another location (Pointer type) that MIGHT be an external subroutine call
        /// <para>If it is determined to be a call to an external subroutine, the external subroutine data table is updated to no longer pointer to it</para>
        /// </summary>
        /// <param name="removedPsaCommand">The psa command being removed</param>
        /// <param name="commandParamPointerValueLocation">The pointer to the param's value location</param>
        private void UpdateExternalPointerLogic(PsaCommand removedPsaCommand, int commandParamPointerValueLocation)
        {
            // iterate through each external subroutine in the external data table
            for (int externalSubRoutineIndex = 0; externalSubRoutineIndex < PsaFile.NumberOfExternalSubRoutines; externalSubRoutineIndex++)
            {
                // get a external subroutine's pointer
                int externalSubRoutineLocationIndex = (PsaFile.NumberOfDataTableEntries + externalSubRoutineIndex) * 2;
                int externalSubRoutineLocation      = PsaFile.DataTableSections[externalSubRoutineLocationIndex];
                if (externalSubRoutineLocation >= 8096 && externalSubRoutineLocation < PsaFile.DataSectionSize)
                {
                    // if the param being removed was pointing to an external subroutine
                    if (commandParamPointerValueLocation == externalSubRoutineLocation)
                    {
                        // get the location of the value of the param
                        int commandExternalSubroutineValueLocation = commandParamPointerValueLocation / 4;

                        // This stops the external data table from pointing to the command param pointer value location
                        if (PsaFile.DataSection[commandExternalSubroutineValueLocation] >= 8096 &&
                            PsaFile.DataSection[commandExternalSubroutineValueLocation] < PsaFile.DataSectionSize &&
                            PsaFile.DataSection[commandExternalSubroutineValueLocation] % 4 == 0)
                        {
                            PsaFile.DataTableSections[externalSubRoutineLocationIndex] = PsaFile.DataSection[commandExternalSubroutineValueLocation];
                        }
                        else
                        {
                            PsaFile.DataTableSections[externalSubRoutineLocationIndex] = -1;
                        }
                        break;
                    }

                    // same deal as above for the most part, but I am NOT sure what location "externalSubRoutineCodeBlockLocation" actually is (I don't think it's right currently)
                    // it's tough to test further because I also can't really figure out how to get this code to trigger at the moment, so I'm just going to leave this as is
                    int externalSubRoutineCodeBlockLocation = externalSubRoutineLocation / 4;

                    int externalSubRoutineCommandsPointerLocation = PsaFile.DataSection[externalSubRoutineCodeBlockLocation];
                    if (externalSubRoutineCommandsPointerLocation >= 8096 &&
                        externalSubRoutineCommandsPointerLocation < PsaFile.DataSectionSize &&
                        removedPsaCommand.CommandParametersLocation == externalSubRoutineCommandsPointerLocation)
                    {
                        int commandExternalDataPointerValue = removedPsaCommand.GetCommandParameterValueLocation(0);
                        if (PsaFile.DataSection[commandExternalDataPointerValue] >= 8096 &&
                            PsaFile.DataSection[commandExternalDataPointerValue] < PsaFile.DataSectionSize &&
                            PsaFile.DataSection[commandExternalDataPointerValue] % 4 == 0)
                        {
                            PsaFile.DataTableSections[externalSubRoutineCodeBlockLocation] = PsaFile.DataSection[commandExternalDataPointerValue];
                        }
                        else
                        {
                            PsaFile.DataTableSections[externalSubRoutineCodeBlockLocation] = -1;
                        }
                        break;
                    }
                }
            }
        }
Exemple #3
0
        /// <summary>
        /// Removes a command from a code block
        /// <para>If the removed command is the last command in the code block, the command space allocation is removed as well</para>
        /// </summary>
        /// <param name="codeBlock">The code block that contains the command to remove</param>
        /// <param name="commandLocation">The location of the command to remove in the code block</param>
        /// <param name="removedPsaCommand">The psa command that is going to be removed</param>
        public void RemoveCommand(CodeBlock codeBlock, int commandLocation, PsaCommand removedPsaCommand)
        {
            // if command to remove has params
            if (removedPsaCommand.NumberOfParams != 0)
            {
                // delete the command's parameters
                DeleteCommandParameters(removedPsaCommand, commandLocation);
            }

            // if code block will still have commands left in it after removing this command
            if (codeBlock.NumberOfCommands > 1)
            {
                // delete the command from the code
                DeleteCommandAndCloseGap(codeBlock, commandLocation);
            }

            // if removing this command will result in code block having no commands (essentially the last command in the block is being removed)
            else
            {
                // set removed command location to free space
                PsaFile.DataSection[commandLocation]     = Constants.FADEF00D;
                PsaFile.DataSection[commandLocation + 1] = Constants.FADEF00D;

                // set end of code block commands space to free space
                // this location is normally what marks the "end" of the commands in a code block (using 0s)
                // since it no longer represents a code block's commands space, it can be changed to free space
                int codeBlockCommandsEnd = codeBlock.GetCommandsEndLocation();
                PsaFile.DataSection[codeBlockCommandsEnd]     = Constants.FADEF00D;
                PsaFile.DataSection[codeBlockCommandsEnd + 1] = Constants.FADEF00D;

                // code block location is set to 0 since a code block with no commands is pointless anyway
                PsaFile.DataSection[codeBlock.Location] = 0;

                // remove any existing pointer references to the cdoe block
                int pointerToCodeBlockLocation = codeBlock.Location * 4;
                PsaFileHelperMethods.RemoveOffsetFromOffsetInterlockTracker(pointerToCodeBlockLocation);
            }

            // look through the rest of the PSA commands for something that points to a removed command or any of its params and remove that pointer
            int codeBlockCommandsEndLocation   = codeBlock.CommandsPointerLocation + codeBlock.NumberOfCommands * 8;
            int codeBlockCommandsStartLocation = codeBlockCommandsEndLocation - 8;

            for (int i = CodeBlockDataStartLocation; i < PsaFile.DataSectionSizeBytes; i++)
            {
                if (PsaFile.DataSection[i] >= codeBlockCommandsStartLocation && PsaFile.DataSection[i] <= codeBlockCommandsEndLocation)
                {
                    DeleteOffsetInterlockData(i);
                }
            }

            PsaFileHelperMethods.ApplyHeaderUpdatesToAccountForPsaCommandChanges();
        }
Exemple #4
0
        /// <summary>
        /// Moves a command upwards
        /// <para>swaps command with the command above it</para>
        /// </summary>
        /// <param name="codeBlock">The code block the command to move is in</param>
        /// <param name="psaCommandToMove">The psa command to move</param>
        /// <param name="commandLocation">The location of the psa command to move</param>
        private void MoveCommandUp(CodeBlock codeBlock, PsaCommand psaCommandToMove, int commandLocation)
        {
            int        commandIndex    = codeBlock.GetPsaCommandIndexByLocation(commandLocation);
            PsaCommand psaCommandAbove = codeBlock.PsaCommands[commandIndex - 1];

            // if moving a command with no params
            if (psaCommandToMove.NumberOfParams == 0)
            {
                // if the command above has params
                if (psaCommandAbove.NumberOfParams != 0)
                {
                    // since command is being moved upwards, the command above will switch with it and as a result moves downwards
                    // this will increase the offset table's pointer to the command above's param location by 8 to adjust for the command moving downwards
                    int commandAboveParamsPointerLocation = codeBlock.GetPsaCommandParamsLocation(commandIndex - 1) * 4;
                    for (int i = 0; i < PsaFile.OffsetSection.Count; i++)
                    {
                        if (PsaFile.OffsetSection[i] == commandAboveParamsPointerLocation)
                        {
                            // Update actual offset pointer in both offset tracker and file content (since the apply header updates method is never called for moving commands)
                            PsaFile.OffsetSection[i] += 8;
                            break;
                        }
                    }
                }
            }

            // if the command above has no parameters
            else if (psaCommandAbove.NumberOfParams == 0)
            {
                // since command is being moved upwards, anything pointing to its params pointer will need to move upwards by 8
                int commandParamsPointerLocation = codeBlock.GetPsaCommandParametersPointerLocation(commandIndex);
                for (int i = 0; i < PsaFile.OffsetSection.Count; i++)
                {
                    if (PsaFile.OffsetSection[i] == commandParamsPointerLocation)
                    {
                        // Update actual offset pointer in both offset tracker and file content (since the apply header updates method is never called for moving commands)
                        PsaFile.OffsetSection[i] -= 8;
                        break;
                    }
                }
            }

            // replace the command to move with the command above
            PsaFile.DataSection[commandLocation]     = psaCommandAbove.Instruction;
            PsaFile.DataSection[commandLocation + 1] = psaCommandAbove.CommandParametersLocation;

            // replace the command above with the command to move
            PsaFile.DataSection[commandLocation - 2] = psaCommandToMove.Instruction;
            PsaFile.DataSection[commandLocation - 1] = psaCommandToMove.CommandParametersLocation;
        }
Exemple #5
0
        /// <summary>
        /// This will expand (usually includes relocating) the command's parameters location if the new psa command has more parameters than the old psa command
        /// <para>If possible, it will not relocate the params section if enough free space can be found</para>
        /// <para>If it can't find enough free space in the data section, it resorts to expanding the data section</para>
        /// </summary>
        /// <param name="oldPsaCommand">The psa command being modified</param>
        /// <param name="newPsaCommand">The psa command replacing the old psa command</param>
        /// <returns>The new location of the command parameters section (if section does not end up getting relocated, it will return the original param section location of the old psa command)</returns>
        private int ExpandCommandParametersSection(PsaCommand oldPsaCommand, PsaCommand newPsaCommand)
        {
            int oldCommandParamsSize = oldPsaCommand.GetCommandParamsSize();
            int newCommandParamsSize = newPsaCommand.GetCommandParamsSize();

            // determine how much space is currently available for params
            // to start, there is the original amount of space that the old psa command had
            int currentCommandParamSize = oldCommandParamsSize;

            // if adding one command to the current parameters location would cause it to go over the data section limit, expand the data section by the amount needed
            if (oldPsaCommand.CommandParametersValuesLocation + oldCommandParamsSize + 5 > PsaFile.DataSection.Count)
            {
                if (oldPsaCommand.CommandParametersValuesLocation + oldCommandParamsSize + 3 > PsaFile.DataSection.Count)
                {
                    // difference between the new size needed and the old size
                    currentCommandParamSize = newCommandParamsSize;
                }
            }

            // add 1 additional block of space for each free space (FADEF00D) that comes afterwards
            while (currentCommandParamSize < newCommandParamsSize &&
                   PsaFile.DataSection[oldPsaCommand.CommandParametersValuesLocation + currentCommandParamSize] == Constants.FADEF00D)
            {
                currentCommandParamSize++;
            }

            // if expanding the data section was applicable or enough free space was found from the above loop
            // the original location of the old psa command now has enough room to hold all necessary parameters for the new command
            if (currentCommandParamSize >= newCommandParamsSize)
            {
                return(oldPsaCommand.CommandParametersValuesLocation);
            }

            // if the amount of space available at the current moment is STILL not enough for all of the new params
            // the parameter location is going to need to be relocated to a place in the file with enough free space
            else
            {
                // find a location in the file with enough free space
                int newCommandParametersValuesLocation = PsaFileHelperMethods.FindLocationWithAmountOfFreeSpace(CodeBlockDataStartLocation, newCommandParamsSize);

                // if new location goes over data section limit, expand data sectoin
                if (newCommandParametersValuesLocation >= PsaFile.DataSection.Count)
                {
                    newCommandParametersValuesLocation = PsaFile.DataSection.Count;
                }
                return(newCommandParametersValuesLocation);
            }
        }
Exemple #6
0
        /// <summary>
        /// Deletes a command from a code block
        /// <para>all other commands in the code block after the removed command are shifted backwards by one to close the gap</para>
        /// <para>think of it like a list data structure where removing an item causes the list to adjust by shifting indexes</para>
        /// </summary>
        /// <param name="codeBlock">The code block of the command being removed</param>
        /// <param name="commandLocation">The location in the code block of the command being removed</param>
        private void DeleteCommandAndCloseGap(CodeBlock codeBlock, int commandLocation)
        {
            // get the command to be removed's index in the code block (i.e. first command is index 0, second command is index 1, etc)
            int removedCommandIndex = codeBlock.GetPsaCommandIndexByLocation(commandLocation);

            // starting from the removed command, iterate through each command in the code block
            // this loop will shift the commands all over by 1, closing the gap where the removed command used to exist
            for (int commandIndex = removedCommandIndex; commandIndex < codeBlock.PsaCommands.Count - 1; commandIndex++)
            {
                // get the next psa command that comes after the current one
                PsaCommand nextPsaCommand = codeBlock.PsaCommands[commandIndex + 1];

                // get the command location of the current command
                int currentCommandLocation = codeBlock.GetPsaCommandLocation(commandIndex);

                // if next command that comes after the current one has params
                if (nextPsaCommand.NumberOfParams > 0)
                {
                    // adjust pointer location for next command to point to the command before it (since all commands are shifted over now)
                    int nextCommandPointerLocation = currentCommandLocation * 4 + 12;

                    for (int j = 0; j < PsaFile.OffsetSection.Count; j++)
                    {
                        if (PsaFile.OffsetSection[j] == nextCommandPointerLocation)
                        {
                            PsaFile.OffsetSection[j] -= 8;
                            break;
                        }
                    }
                }

                // this is what actually shifts the command - the instruction and param pointer is shifted to the previous command location
                PsaFile.DataSection[currentCommandLocation]     = PsaFile.DataSection[currentCommandLocation + 2];
                PsaFile.DataSection[currentCommandLocation + 1] = PsaFile.DataSection[currentCommandLocation + 3];
            }

            // mark the old last command location (that was shifted up in the the loop above) as the end of the code block
            int lastCommandLocation = codeBlock.GetPsaCommandLocation(codeBlock.NumberOfCommands - 1);

            PsaFile.DataSection[lastCommandLocation]     = 0;
            PsaFile.DataSection[lastCommandLocation + 1] = 0;

            // this space is left over from all of the commands shifting -- it is now unused so it can be set to free space
            PsaFile.DataSection[lastCommandLocation + 2] = Constants.FADEF00D;
            PsaFile.DataSection[lastCommandLocation + 3] = Constants.FADEF00D;
        }
Exemple #7
0
        /// <summary>
        /// Moves a command either upwards or downwards
        /// </summary>
        /// <param name="codeBlock">The code block the command to move is in</param>
        /// <param name="psaCommandToMove">The psa command to move</param>
        /// <param name="commandLocation">The location of the psa command to move</param>
        /// <param name="moveDirection">The direction to move the command in (MoveDirection enum -- UP or DOWN)</param>
        public void MoveCommand(CodeBlock codeBlock, PsaCommand psaCommandToMove, int commandLocation, MoveDirection moveDirection)
        {
            switch (moveDirection)
            {
            // move command upwards by one index (swap command with command above it)
            case MoveDirection.UP:
                MoveCommandUp(codeBlock, psaCommandToMove, commandLocation);
                break;

            // move command downwards by one index (swap command with command below it)
            case MoveDirection.DOWN:
                MoveCommandDown(codeBlock, psaCommandToMove, commandLocation);
                break;

            default:
                throw new InvalidEnumArgumentException("Direction type does not exist");
            }
        }
Exemple #8
0
        /// <summary>
        /// Creates a new parameters section for a command
        /// <para>This is called if the old psa command does not have any parameters, but the new command does -- that means a parameters section for the command needs to be created and pointed to</para>
        /// </summary>
        /// <param name="commandLocation"></param>
        /// <param name="newPsaCommand"></param>
        private void CreateNewCommandParametersLocation(int commandLocation, PsaCommand newPsaCommand)
        {
            int newCommandParamsValuesSize = newPsaCommand.GetCommandParamsSize();

            // determine where the new parameters values location will be by finding enough free space to fit it
            int newCommandParametersValuesLocation = PsaFileHelperMethods.FindLocationWithAmountOfFreeSpace(CodeBlockDataStartLocation, newCommandParamsValuesSize);

            // if the only place with free space found is after the limits of the data section, expand the data section to make room
            if (newCommandParametersValuesLocation >= PsaFile.DataSection.Count)
            {
                newCommandParametersValuesLocation = PsaFile.DataSection.Count;
            }

            // go through each parameter in the new command one at a time and place it in the newly created parameters values location (type, value)
            for (int paramIndex = 0; paramIndex < newPsaCommand.NumberOfParams; paramIndex++)
            {
                int paramTypeLocation  = paramIndex * 2;
                int paramValueLocation = paramIndex * 2 + 1;

                // if command param type is "Pointer" and the param value is greater than 0 (meaning it points to something)
                if (newPsaCommand.Parameters[paramIndex].Type == 2 && newPsaCommand.Parameters[paramIndex].Value > 0)
                {
                    int commandParameterPointerLocation = (newCommandParametersValuesLocation + paramTypeLocation) * 4 + 4;
                    PsaFile.OffsetSection.Add(commandParameterPointerLocation);
                }
                PsaFileHelperMethods.SetDataSectionValue(newCommandParametersValuesLocation + paramTypeLocation, newPsaCommand.Parameters[paramIndex].Type);
                PsaFileHelperMethods.SetDataSectionValue(newCommandParametersValuesLocation + paramValueLocation, newPsaCommand.Parameters[paramIndex].Value);
            }

            // place new command instruction at command location
            PsaFile.DataSection[commandLocation] = newPsaCommand.Instruction;

            // set pointer to command parameters location
            int newCommandParametersLocation = newCommandParametersValuesLocation * 4;

            PsaFile.DataSection[commandLocation + 1] = newCommandParametersLocation;

            // set pointer to command parameters pointer location in the offset interlock tracker
            int newCommandParametersPointerLocation = commandLocation * 4 + 4;

            PsaFile.OffsetSection.Add(newCommandParametersPointerLocation);
        }
Exemple #9
0
        /// <summary>
        /// Deletes all of a command's parameters
        /// </summary>
        /// <param name="removedPsaCommand">command being removed (which will have its params deleted)</param>
        /// <param name="commandLocation">location of the command being removed in the code block</param>
        private void DeleteCommandParameters(PsaCommand removedPsaCommand, int commandLocation)
        {
            // if command parameters location is within the valid space for code block commands
            if (removedPsaCommand.CommandParametersValuesLocation >= CodeBlockDataStartLocation && removedPsaCommand.CommandParametersValuesLocation < PsaFile.DataSectionSizeBytes)
            {
                // remove any pointers to the parameters location (since it won't exist anymore)
                int commandParametersPointerLocation = commandLocation * 4 + 4;
                PsaFileHelperMethods.RemoveOffsetFromOffsetInterlockTracker(commandParametersPointerLocation);

                // iterates through each param the command had
                for (int i = 0; i < removedPsaCommand.NumberOfParams * 2; i += 2)
                {
                    int parameterType  = removedPsaCommand.Parameters[i / 2].Type;
                    int parameterValue = removedPsaCommand.Parameters[i / 2].Value;

                    // If the pointer param was an external subroutine (from the external data table) (such as Mario's Up B, the item ones like the home run bat, etc),
                    // some additional work needs to be done to remove references to it from the external data table
                    if (parameterType == 2)
                    {
                        // Get the pointer location of the param value that is currently pointing to another location
                        int commandParamPointerValueLocation = removedPsaCommand.CommandParametersLocation + 4;


                        // Attempt to remove the above offset from the offset interlock tracker
                        bool wasOffsetRemoved = PsaFileHelperMethods.RemoveOffsetFromOffsetInterlockTracker(commandParamPointerValueLocation);

                        // If offset was not successfully removed, it means it either doesn't exist or is an external subroutine
                        // The below method call UpdateExternalPointerLogic will do some necessary work if the offset turns out to be an external subroutine call
                        if (!wasOffsetRemoved)
                        {
                            UpdateExternalPointerLogic(removedPsaCommand, commandParamPointerValueLocation);
                        }
                    }

                    // replace removed param values with free space (FADEF00D)
                    // first replaces the param type, second replaces the param value
                    PsaFile.DataSection[removedPsaCommand.CommandParametersValuesLocation + i]     = Constants.FADEF00D;
                    PsaFile.DataSection[removedPsaCommand.CommandParametersValuesLocation + i + 1] = Constants.FADEF00D;
                }
            }
        }
Exemple #10
0
        /// <summary>
        /// Modify a command with existing parameters
        /// <para>Case 1: both old and new command have same number of parameters, which is an easy params replace 1 by 1</para>
        /// <para>Case 2: new command has less params than old command, which is the same as case 1, but the unused param space needs to be converted to free space (FADEF00D)</para>
        /// <para>Case 3: new command has more params than old command, which will result in finding a new location for the parameters that has enough space</para>
        /// </summary>
        /// <param name="commandLocation">The location of the command in the code block</param>
        /// <param name="oldPsaCommand">The old psa command (the one that is being modified)</param>
        /// <param name="newPsaCommand">The new psa command (the one that is replcaing the old psa command)</param>
        private void ModifyExistingCommandParametersLocation(int commandLocation, PsaCommand oldPsaCommand, PsaCommand newPsaCommand)
        {
            // If modifying a command that pointed to another location (the "Pointer" param type), the pointer location needs to be removed from the offset interlock tracker
            // If the pointer param was an external subroutine (from the external data table) (such as Mario's Up B, the item ones like the home run bat, etc),
            // some additional work needs to be done to remove references to it from the external data table
            // This if statement checks if the first parameter is of type Pointer or the second, which matches commands like "goto", "subroutine", and "concurrent subroutine"
            if (PsaFile.DataSection[oldPsaCommand.CommandParametersValuesLocation] == 2 ||
                (PsaFile.DataSection[oldPsaCommand.CommandParametersValuesLocation + 2] == 2 && oldPsaCommand.NumberOfParams == 2))
            {
                // Get the pointer location of the param value that is currently pointing to another location
                int commandParamPointerValueLocation = PsaFile.DataSection[oldPsaCommand.CommandParametersValuesLocation] == 2
                    ? oldPsaCommand.CommandParametersLocation + 4
                    : oldPsaCommand.CommandParametersLocation + 12;

                // Attempt to remove the above offset from the offset interlock tracker
                bool wasOffsetRemoved = PsaFileHelperMethods.RemoveOffsetFromOffsetInterlockTracker(commandParamPointerValueLocation);

                // If offset was not successfully removed, it means it either doesn't exist or is an external subroutine
                // The below method call UpdateExternalPointerLogic will do some necessary work if the offset turns out to be an external subroutine call
                if (!wasOffsetRemoved)
                {
                    UpdateExternalPointerLogic(oldPsaCommand, commandParamPointerValueLocation);
                }
            }

            // Replace old param values with free space (FADEF00D)
            for (int paramIndex = 0; paramIndex < oldPsaCommand.NumberOfParams; paramIndex++)
            {
                int commandParameterTypeLocation  = oldPsaCommand.GetCommandParameterTypeLocation(paramIndex);
                int commandParameterValueLocation = oldPsaCommand.GetCommandParameterValueLocation(paramIndex);
                PsaFile.DataSection[commandParameterTypeLocation]  = Constants.FADEF00D;
                PsaFile.DataSection[commandParameterValueLocation] = Constants.FADEF00D;
            }

            // set new command instruction
            PsaFile.DataSection[commandLocation] = newPsaCommand.Instruction;

            // if new command has no parameters, set pointer to parameters to nothing (which is 0) and remove the pointer to the parameters from the offset interlock
            if (newPsaCommand.NumberOfParams == 0)
            {
                // remove pointer to params since this command has no params
                PsaFile.DataSection[commandLocation + 1] = 0;

                // remove offset from interlock tracker since it no longer exists
                int commandParametersPointerLocation = commandLocation * 4 + 4;
                PsaFileHelperMethods.RemoveOffsetFromOffsetInterlockTracker(commandParametersPointerLocation);
            }

            // if new command has parameters
            else
            {
                // if new command has a less or equal parameter count to the old command, the parameter values location does not need to be relocated
                // if the new command has a higher parameter count than the old command, the paramter values location will need to be expanded/relocated to have enough room for all the parameters
                int newCommandParametersValuesLocation = oldPsaCommand.NumberOfParams >= newPsaCommand.NumberOfParams
                    ? oldPsaCommand.CommandParametersValuesLocation
                    : ExpandCommandParametersSection(oldPsaCommand, newPsaCommand);

                PsaFile.DataSection[commandLocation + 1] = newCommandParametersValuesLocation * 4;


                // put param values in new param values location one by one
                for (int paramIndex = 0; paramIndex < newPsaCommand.NumberOfParams; paramIndex++)
                {
                    int paramTypeLocation  = paramIndex * 2;
                    int paramValueLocation = paramIndex * 2 + 1;

                    // if command param type is Pointer and it actually points to something
                    if (newPsaCommand.Parameters[paramIndex].Type == 2 && newPsaCommand.Parameters[paramIndex].Value > 0)
                    {
                        // I believe this points to the location of the param value (if the param is a pointer)
                        int commandParameterPointerValueLocation = (newCommandParametersValuesLocation + paramTypeLocation) * 4 + 4;
                        PsaFile.OffsetSection.Add(commandParameterPointerValueLocation);
                    }

                    // place parameter type in value in proper place
                    PsaFileHelperMethods.SetDataSectionValue(newCommandParametersValuesLocation + paramTypeLocation, newPsaCommand.Parameters[paramIndex].Type);
                    PsaFileHelperMethods.SetDataSectionValue(newCommandParametersValuesLocation + paramValueLocation, newPsaCommand.Parameters[paramIndex].Value);
                }
            }
        }