Initial implementation of tracerestrict counter mechanism

This commit is contained in:
Jonathan G Rennison
2020-08-31 19:08:35 +01:00
parent dea2be5d3f
commit 817bc44a3e
17 changed files with 887 additions and 13 deletions

View File

@@ -69,6 +69,9 @@ INSTANTIATE_POOL_METHODS(TraceRestrictProgram)
TraceRestrictSlotPool _tracerestrictslot_pool("TraceRestrictSlot");
INSTANTIATE_POOL_METHODS(TraceRestrictSlot)
TraceRestrictCounterPool _tracerestrictcounter_pool("TraceRestrictCounter");
INSTANTIATE_POOL_METHODS(TraceRestrictCounter)
/**
* TraceRestrictRefId --> TraceRestrictProgramID (Pool ID) mapping
* The indirection is mainly to enable shared programs
@@ -499,6 +502,15 @@ void TraceRestrictProgram::Execute(const Train* v, const TraceRestrictProgramInp
break;
}
case TRIT_COND_COUNTER_VALUE: {
// TRVT_COUNTER_INDEX_INT value type uses the next slot
i++;
uint32_t value = this->items[i];
const TraceRestrictCounter *ctr = TraceRestrictCounter::GetIfValid(GetTraceRestrictValue(item));
result = TestCondition(ctr != nullptr ? ctr->value : 0, condop, value);
break;
}
default:
NOT_REACHED();
}
@@ -657,6 +669,33 @@ void TraceRestrictProgram::Execute(const Train* v, const TraceRestrictProgramInp
}
break;
case TRIT_COUNTER: {
// TRVT_COUNTER_INDEX_INT value type uses the next slot
i++;
uint32_t value = this->items[i];
if (!(input.permitted_slot_operations & TRPISP_CHANGE_COUNTER)) break;
TraceRestrictCounter *ctr = TraceRestrictCounter::GetIfValid(GetTraceRestrictValue(item));
if (ctr == nullptr) break;
switch (static_cast<TraceRestrictCounterCondOpField>(GetTraceRestrictCondOp(item))) {
case TRCCOF_INCREASE:
ctr->UpdateValue(ctr->value + value);
break;
case TRCCOF_DECREASE:
ctr->UpdateValue(ctr->value - value);
break;
case TRCCOF_SET:
ctr->UpdateValue(value);
break;
default:
NOT_REACHED();
break;
}
break;
}
default:
NOT_REACHED();
}
@@ -751,6 +790,7 @@ CommandCost TraceRestrictProgram::Validate(const std::vector<TraceRestrictItem>
case TRIT_COND_TRAIN_OWNER:
case TRIT_COND_TRAIN_STATUS:
case TRIT_COND_LOAD_PERCENT:
case TRIT_COND_COUNTER_VALUE:
break;
default:
@@ -834,6 +874,10 @@ CommandCost TraceRestrictProgram::Validate(const std::vector<TraceRestrictItem>
actions_used_flags |= TRPAUF_TRAIN_NOT_STUCK;
break;
case TRIT_COUNTER:
actions_used_flags |= TRPAUF_CHANGE_COUNTER;
break;
default:
return_cmd_error(STR_TRACE_RESTRICT_ERROR_VALIDATE_UNKNOWN_INSTRUCTION);
}
@@ -943,6 +987,10 @@ void SetTraceRestrictValueDefault(TraceRestrictItem &item, TraceRestrictValueTyp
SetTraceRestrictValue(item, INVALID_TRACE_RESTRICT_SLOT_ID);
break;
case TRVT_COUNTER_INDEX_INT:
SetTraceRestrictValue(item, INVALID_TRACE_RESTRICT_COUNTER_ID);
break;
default:
NOT_REACHED();
break;
@@ -1147,8 +1195,12 @@ static uint32 GetDualInstructionInitialValue(TraceRestrictItem item)
return INVALID_TILE;
case TRIT_COND_SLOT_OCCUPANCY:
case TRIT_COND_COUNTER_VALUE:
return 0;
case TRIT_COUNTER:
return 1;
default:
NOT_REACHED();
}
@@ -1636,9 +1688,20 @@ void TraceRestrictUpdateCompanyID(CompanyID old_company, CompanyID new_company)
}
}
for (TraceRestrictCounter *ctr : TraceRestrictCounter::Iterate()) {
if (ctr->owner != old_company) continue;
if (new_company == INVALID_OWNER) {
TraceRestrictRemoveCounterID(ctr->index);
delete ctr;
} else {
ctr->owner = new_company;
}
}
// update windows
InvalidateWindowClassesData(WC_TRACE_RESTRICT);
InvalidateWindowClassesData(WC_TRACE_RESTRICT_SLOTS);
InvalidateWindowClassesData(WC_TRACE_RESTRICT_COUNTERS);
}
static std::unordered_multimap<VehicleID, TraceRestrictSlotID> slot_vehicle_index;
@@ -1922,7 +1985,7 @@ CommandCost CmdDeleteTraceRestrictSlot(TileIndex tile, DoCommandFlag flags, uint
* @param flags type of operation
* @param p1 index of array group
* - p1 bit 0-15 : GroupID
* - p1 bit 16: 0 - Rename grouop
* - p1 bit 16: 0 - Rename group
* 1 - Change max occupancy
* @param p2 new max occupancy
* @param text the new name
@@ -2012,3 +2075,148 @@ CommandCost CmdRemoveVehicleTraceRestrictSlot(TileIndex tile, DoCommandFlag flag
return CommandCost();
}
void TraceRestrictCounter::UpdateValue(int32 new_value)
{
new_value = max<int32>(0, new_value);
if (new_value != this->value) {
this->value = new_value;
InvalidateWindowClassesData(WC_TRACE_RESTRICT_COUNTERS);
}
}
static bool IsUniqueCounterName(const char *name)
{
for (const TraceRestrictCounter *ctr : TraceRestrictCounter::Iterate()) {
if (ctr->name == name) return false;
}
return true;
}
/**
* This is called when a counter is about to be deleted
* Scan program pool and change any references to it to the invalid counter ID, to avoid dangling references
*/
void TraceRestrictRemoveCounterID(TraceRestrictCounterID index)
{
for (TraceRestrictProgram *prog : TraceRestrictProgram::Iterate()) {
for (size_t i = 0; i < prog->items.size(); i++) {
TraceRestrictItem &item = prog->items[i]; // note this is a reference,
if ((GetTraceRestrictType(item) == TRIT_COUNTER || GetTraceRestrictType(item) == TRIT_COND_COUNTER_VALUE) && GetTraceRestrictValue(item) == index) {
SetTraceRestrictValueDefault(item, TRVT_COUNTER_INDEX_INT); // this updates the instruction in-place
}
if (IsTraceRestrictDoubleItem(item)) i++;
}
}
// update windows
InvalidateWindowClassesData(WC_TRACE_RESTRICT);
}
/**
* Create a new counter.
* @param tile unused
* @param flags type of operation
* @param p1 unused
* @param p2 unused
* @param text new counter name
* @return the cost of this operation or an error
*/
CommandCost CmdCreateTraceRestrictCounter(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
{
if (!TraceRestrictCounter::CanAllocateItem()) return CMD_ERROR;
if (StrEmpty(text)) return CMD_ERROR;
size_t length = Utf8StringLength(text);
if (length <= 0) return CMD_ERROR;
if (length >= MAX_LENGTH_TRACE_RESTRICT_SLOT_NAME_CHARS) return CMD_ERROR;
if (!IsUniqueCounterName(text)) return_cmd_error(STR_ERROR_NAME_MUST_BE_UNIQUE);
if (flags & DC_EXEC) {
TraceRestrictCounter *ctr = new TraceRestrictCounter(_current_company);
ctr->name = text;
// update windows
InvalidateWindowClassesData(WC_TRACE_RESTRICT);
InvalidateWindowClassesData(WC_TRACE_RESTRICT_COUNTERS);
}
return CommandCost();
}
/**
* Deletes a counter.
* @param tile unused
* @param flags type of operation
* @param p1 index of array group
* - p1 bit 0-15 : Counter ID
* @param p2 unused
* @param text unused
* @return the cost of this operation or an error
*/
CommandCost CmdDeleteTraceRestrictCounter(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
{
TraceRestrictCounter *ctr = TraceRestrictCounter::GetIfValid(p1);
if (ctr == nullptr || ctr->owner != _current_company) return CMD_ERROR;
if (flags & DC_EXEC) {
/* notify tracerestrict that counter is about to be deleted */
TraceRestrictRemoveCounterID(ctr->index);
delete ctr;
InvalidateWindowClassesData(WC_TRACE_RESTRICT);
InvalidateWindowClassesData(WC_TRACE_RESTRICT_COUNTERS);
InvalidateWindowClassesData(WC_VEHICLE_ORDERS);
}
return CommandCost();
}
/**
* Alter a counter
* @param tile unused
* @param flags type of operation
* @param p1 index of array counter
* - p1 bit 0-15 : Counter ID
* - p1 bit 16: 0 - Rename counter
* 1 - Change value
* @param p2 new value
* @param text the new name
* @return the cost of this operation or an error
*/
CommandCost CmdAlterTraceRestrictCounter(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
{
TraceRestrictCounter *ctr = TraceRestrictCounter::GetIfValid(GB(p1, 0, 16));
if (ctr == nullptr || ctr->owner != _current_company) return CMD_ERROR;
if (!HasBit(p1, 16)) {
/* Rename counter */
if (StrEmpty(text)) return CMD_ERROR;
size_t length = Utf8StringLength(text);
if (length <= 0) return CMD_ERROR;
if (length >= MAX_LENGTH_TRACE_RESTRICT_SLOT_NAME_CHARS) return CMD_ERROR;
if (!IsUniqueCounterName(text)) return_cmd_error(STR_ERROR_NAME_MUST_BE_UNIQUE);
if (flags & DC_EXEC) {
ctr->name = text;
}
} else {
/* Change value */
if (flags & DC_EXEC) {
ctr->UpdateValue(p2);
}
}
if (flags & DC_EXEC) {
// update windows
InvalidateWindowClassesData(WC_TRACE_RESTRICT);
InvalidateWindowClassesData(WC_TRACE_RESTRICT_COUNTERS);
InvalidateWindowClassesData(WC_VEHICLE_ORDERS);
}
return CommandCost();
}