progsig: Fix remove and clone program functions being completely broken.

Remove function only removed instructions from the local machine, and
was therefore not MP safe.
Clone function failed to work correctly for non-trivial cases,
and sometimes caused an array out of bounds assertion.

These are replaced by a new commandproc which does each operation
as a single action, which is therefore MP safe.

Remove an unused struct field.
This commit is contained in:
Jonathan G Rennison
2015-11-24 01:03:09 +00:00
parent 8760187899
commit 769b8ae096
5 changed files with 142 additions and 70 deletions

View File

@@ -256,8 +256,7 @@ public:
case PROGRAM_WIDGET_REMOVE: {
SignalInstruction *ins = GetSelected();
if (this->GetOwner() != _local_company || !ins)
return;
if (ins == NULL) return;
uint32 p1 = 0;
SB(p1, 0, 3, this->track);
@@ -336,15 +335,13 @@ public:
ScrollMainWindowToTile(this->tile);
// this->RaiseWidget(PROGRAM_WIDGET_GOTO_SIGNAL);
} break;
case PROGRAM_WIDGET_REMOVE_PROGRAM: {
if (this->GetOwner() != _local_company)
return;
program->first_instruction->Remove();
case PROGRAM_WIDGET_REMOVE_PROGRAM: {
DoCommandP(this->tile, this->track | (SPMC_REMOVE << 3), 0, CMD_SIGNAL_PROGRAM_MGMT | CMD_MSG(STR_ERROR_CAN_T_MODIFY_INSTRUCTION));
this->RebuildInstructionList();
} break;
case PROGRAM_WIDGET_COPY_PROGRAM: {
case PROGRAM_WIDGET_COPY_PROGRAM: {
this->ToggleWidgetLoweredState(PROGRAM_WIDGET_COPY_PROGRAM);
this->SetWidgetDirty(PROGRAM_WIDGET_COPY_PROGRAM);
if (this->IsWidgetLowered(PROGRAM_WIDGET_COPY_PROGRAM)) {
@@ -356,62 +353,6 @@ public:
}
}
void InsertInstruction(SignalInstruction *si, uint32 next)
{
uint64 p1 = 0;
while(true) {
if(si == NULL) break;
switch(si->Opcode()) {
case PSO_SET_SIGNAL: {
SB(p1, 0, 3, this->track);
SB(p1, 3, 16, next);
SB(p1, 19, 8, si->Opcode());
DoCommandP(this->tile, p1, 0, CMD_INSERT_SIGNAL_INSTRUCTION | CMD_MSG(STR_ERROR_CAN_T_INSERT_INSTRUCTION));
this->RebuildInstructionList();
si = ((SignalSet*)si)->next;
} break;
case PSO_IF: {
SB(p1, 0, 3, this->track);
SB(p1, 3, 16, next);
SB(p1, 19, 8, si->Opcode());
DoCommandP(this->tile, p1, 0, CMD_INSERT_SIGNAL_INSTRUCTION | CMD_MSG(STR_ERROR_CAN_T_INSERT_INSTRUCTION));
this->RebuildInstructionList();
SignalInstruction *s = ((SignalIf*)si)->if_true;
while(s->Opcode() != PSO_IF_ELSE) {
if(s->Opcode() == PSO_IF) s = ((SignalIf*)s)->after;
if(s->Opcode() == PSO_SET_SIGNAL) s = ((SignalSet*)s)->next;
else break;
}
InsertInstruction(((SignalIf*)si)->if_true, s->Id());
this->RebuildInstructionList();
s = ((SignalIf*)si)->if_false;
while(s->Opcode() != PSO_IF_ENDIF) {
if(s->Opcode() == PSO_IF) s = ((SignalIf*)s)->after;
if(s->Opcode() == PSO_SET_SIGNAL) s = ((SignalSet*)s)->next;
else break;
}
InsertInstruction(((SignalIf*)si)->if_false, s->Id());
this->RebuildInstructionList();
si = ((SignalIf*)si)->after;
} break;
case PSO_LAST:
case PSO_IF_ELSE:
case PSO_IF_ENDIF:
return;
default:
NOT_REACHED();
}
}
}
virtual void OnPlaceObject(Point pt, TileIndex tile1) OVERRIDE
{
if (this->IsWidgetLowered(PROGRAM_WIDGET_COPY_PROGRAM)) {
@@ -446,13 +387,10 @@ public:
ShowErrorMessage(STR_ERROR_INVALID_SIGNAL, STR_ERROR_NOT_AN_EXIT_SIGNAL, WL_INFO);
return;
}
program->first_instruction->Remove();
this->RebuildInstructionList();
SignalInstruction *si = ((SignalSpecial*)sp->first_instruction)->next;
InsertInstruction(si, program->last_instruction->Id());
DoCommandP(this->tile, this->track | (SPMC_CLONE << 3) | (track1 << 7), tile1, CMD_SIGNAL_PROGRAM_MGMT | CMD_MSG(STR_ERROR_CAN_T_INSERT_INSTRUCTION));
ResetObjectToPlace();
this->RaiseWidget(PROGRAM_WIDGET_COPY_PROGRAM);
this->RebuildInstructionList();
//OnPaint(); // this appears to cause visual artefacts
return;
}