/* * This file is part of OpenTTD. * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . */ /** @file tracerestrict_sl.cpp Code handling saving and loading of trace restrict programs */ #include "../stdafx.h" #include "../tracerestrict.h" #include "../strings_func.h" #include "../string_func.h" #include "saveload.h" #include static const SaveLoad _trace_restrict_mapping_desc[] = { SLE_VAR(TraceRestrictMappingItem, program_id, SLE_UINT32), }; /** * Load mappings */ static void Load_TRRM() { int index; while ((index = SlIterateArray()) != -1) { TraceRestrictMappingItem &item = _tracerestrictprogram_mapping[index]; SlObject(&item, _trace_restrict_mapping_desc); } } /** * Save mappings */ static void Save_TRRM() { for (TraceRestrictMapping::iterator iter = _tracerestrictprogram_mapping.begin(); iter != _tracerestrictprogram_mapping.end(); ++iter) { SlSetArrayIndex(iter->first); SlObject(&(iter->second), _trace_restrict_mapping_desc); } } /** * Load program pool */ static void Load_TRRP() { int index; while ((index = SlIterateArray()) != -1) { TraceRestrictProgram *prog = new (index) TraceRestrictProgram(); uint32_t prog_length = SlReadUint32(); prog->items.resize(prog_length); if (prog_length > 0) SlArray(prog->items.data(), prog_length, SLE_UINT32); if (SlXvIsFeaturePresent(XSLFI_JOKERPP)) { for (size_t i = 0; i < prog->items.size(); i++) { TraceRestrictItem &item = prog->items[i]; // note this is a reference, if (GetTraceRestrictType(item) == 19 || GetTraceRestrictType(item) == 20) { SetTraceRestrictType(item, (TraceRestrictItemType)(GetTraceRestrictType(item) + 2)); } if (IsTraceRestrictDoubleItem(item)) i++; } } if (SlXvIsFeatureMissing(XSLFI_TRACE_RESTRICT, 17)) { /* TRIT_SLOT subtype moved from cond op to combined aux and cond op field in version 17. * Do this for all previous versions to avoid cases where it is unexpectedly present despite the version, * e.g. in JokerPP and non-SLXI tracerestrict saves. */ for (size_t i = 0; i < prog->items.size(); i++) { TraceRestrictItem &item = prog->items[i]; // note this is a reference if (GetTraceRestrictType(item) == TRIT_SLOT) { TraceRestrictSlotSubtypeField subtype = static_cast(GetTraceRestrictCondOp(item)); if (subtype == 7) { /* Was TRSCOF_ACQUIRE_TRY_ON_RESERVE */ subtype = TRSCOF_ACQUIRE_TRY; } SetTraceRestrictCombinedAuxCondOpField(item, subtype); } if (IsTraceRestrictDoubleItem(item)) i++; } } CommandCost validation_result = prog->Validate(); if (validation_result.Failed()) { char str[4096]; char *strend = str + seprintf(str, lastof(str), "Trace restrict program %d: %s\nProgram dump:", index, GetStringPtr(validation_result.GetErrorMessage())); uint fail_offset = validation_result.HasResultData() ? validation_result.GetResultData() : UINT32_MAX; for (uint i = 0; i < (uint)prog->items.size(); i++) { if ((i % 3) == 0) { strend += seprintf(strend, lastof(str), "\n%4u:", i); } strend += seprintf(strend, lastof(str), (i == fail_offset) ? " [%08X]" : " %08X", prog->items[i]); } SlErrorCorrupt(str); } } } /** * Save program pool */ static void Save_TRRP() { for (TraceRestrictProgram *prog : TraceRestrictProgram::Iterate()) { SlSetArrayIndex(prog->index); SlSetLength(4 + (prog->items.size() * 4)); SlWriteUint32((uint32_t)prog->items.size()); SlArray(prog->items.data(), prog->items.size(), SLE_UINT32); } } /** program length save header struct */ struct TraceRestrictSlotStub { uint32_t length; }; static const SaveLoad _trace_restrict_slot_stub_desc[] = { SLE_VAR(TraceRestrictSlotStub, length, SLE_UINT32), }; static const SaveLoad _trace_restrict_slot_desc[] = { SLE_VAR(TraceRestrictSlot, max_occupancy, SLE_UINT32), SLE_SSTR(TraceRestrictSlot, name, SLF_ALLOW_CONTROL), SLE_VAR(TraceRestrictSlot, owner, SLE_UINT8), SLE_CONDVAR_X(TraceRestrictSlot, vehicle_type, SLE_UINT8, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_TRACE_RESTRICT, 13)), }; /** * Load slot pool */ static void Load_TRRS() { int index; TraceRestrictSlotStub stub; while ((index = SlIterateArray()) != -1) { TraceRestrictSlot *slot = new (index) TraceRestrictSlot(); SlObject(slot, _trace_restrict_slot_desc); SlObject(&stub, _trace_restrict_slot_stub_desc); slot->occupants.resize(stub.length); if (stub.length) SlArray(slot->occupants.data(), stub.length, SLE_UINT32); } TraceRestrictSlot::RebuildVehicleIndex(); } /** * Save a slot, used by SlAutolength */ static void RealSave_TRRS(TraceRestrictSlot *slot) { SlObject(slot, _trace_restrict_slot_desc); TraceRestrictSlotStub stub; stub.length = (uint32_t)slot->occupants.size(); SlObject(&stub, _trace_restrict_slot_stub_desc); if (stub.length) SlArray(slot->occupants.data(), stub.length, SLE_UINT32); } /** * Save slot pool */ static void Save_TRRS() { for (TraceRestrictSlot *slot : TraceRestrictSlot::Iterate()) { SlSetArrayIndex(slot->index); SlAutolength((AutolengthProc*) RealSave_TRRS, slot); } } static const SaveLoad _trace_restrict_counter_desc[] = { SLE_VAR(TraceRestrictCounter, value, SLE_INT32), SLE_SSTR(TraceRestrictCounter, name, SLF_ALLOW_CONTROL), SLE_VAR(TraceRestrictCounter, owner, SLE_UINT8), }; /** * Load counter pool */ static void Load_TRRC() { int index; while ((index = SlIterateArray()) != -1) { TraceRestrictCounter *ctr = new (index) TraceRestrictCounter(); SlObject(ctr, _trace_restrict_counter_desc); } } /** * Save counter pool */ static void Save_TRRC() { for (TraceRestrictCounter *ctr : TraceRestrictCounter::Iterate()) { SlSetArrayIndex(ctr->index); SlObject(ctr, _trace_restrict_counter_desc); } } /** * Update program reference counts from just-loaded mapping */ void AfterLoadTraceRestrict() { for (TraceRestrictMapping::iterator iter = _tracerestrictprogram_mapping.begin(); iter != _tracerestrictprogram_mapping.end(); ++iter) { _tracerestrictprogram_pool.Get(iter->second.program_id)->IncrementRefCount(iter->first); } } extern const ChunkHandler trace_restrict_chunk_handlers[] = { { 'TRRM', Save_TRRM, Load_TRRM, nullptr, nullptr, CH_SPARSE_ARRAY }, // Trace Restrict Mapping chunk { 'TRRP', Save_TRRP, Load_TRRP, nullptr, nullptr, CH_ARRAY }, // Trace Restrict Mapping Program Pool chunk { 'TRRS', Save_TRRS, Load_TRRS, nullptr, nullptr, CH_ARRAY }, // Trace Restrict Slot Pool chunk { 'TRRC', Save_TRRC, Load_TRRC, nullptr, nullptr, CH_ARRAY }, // Trace Restrict Counter Pool chunk }; extern const ChunkHandlerTable _trace_restrict_chunk_handlers(trace_restrict_chunk_handlers);