00001
00002
00003
00004
00005
00006
00007
00008
00009
00012 #include "../stdafx.h"
00013 #include "../programmable_signals.h"
00014 #include "../core/alloc_type.hpp"
00015 #include "../core/bitmath_func.hpp"
00016 #include <vector>
00017 #include "saveload.h"
00018
00019 typedef std::vector<byte> Buffer;
00020
00021
00022
00023
00024 static void WriteVLI(Buffer &b, uint i)
00025 {
00026 uint lsmask = 0x7F;
00027 uint msmask = ~0x7F;
00028 while(i & msmask) {
00029 byte part = (i & lsmask) | 0x80;
00030 b.push_back(part);
00031 i >>= 7;
00032 }
00033 b.push_back((byte) i);
00034 }
00035
00036 static uint ReadVLI()
00037 {
00038 uint shift = 0;
00039 uint val = 0;
00040 byte b;
00041
00042 b = SlReadByte();
00043 while(b & 0x80) {
00044 val |= uint(b & 0x7F) << shift;
00045 shift += 7;
00046 b = SlReadByte();
00047 }
00048 val |= uint(b) << shift;
00049 return val;
00050 }
00051
00052 static void WriteCondition(Buffer &b, SignalCondition *c)
00053 {
00054 WriteVLI(b, c->ConditionCode());
00055 switch(c->ConditionCode()) {
00056 case PSC_NUM_GREEN:
00057 case PSC_NUM_RED: {
00058 SignalVariableCondition *vc = static_cast<SignalVariableCondition*>(c);
00059 WriteVLI(b, vc->comparator);
00060 WriteVLI(b, vc->value);
00061 } break;
00062
00063 case PSC_SIGNAL_STATE: {
00064 SignalStateCondition *sc = static_cast<SignalStateCondition*>(c);
00065 WriteVLI(b, sc->sig_tile);
00066 WriteVLI(b, sc->sig_track);
00067 } break;
00068
00069 default:
00070 break;
00071 }
00072 }
00073
00074 static SignalCondition *ReadCondition(SignalReference this_sig)
00075 {
00076 SignalConditionCode code = (SignalConditionCode) ReadVLI();
00077 switch(code) {
00078 case PSC_NUM_GREEN:
00079 case PSC_NUM_RED: {
00080 SignalVariableCondition *c = new SignalVariableCondition(code);
00081 c->comparator = (SignalComparator) ReadVLI();
00082 if(c->comparator > SGC_LAST) NOT_REACHED();
00083 c->value = ReadVLI();
00084 return c;
00085 }
00086
00087 case PSC_SIGNAL_STATE: {
00088 TileIndex ti = (TileIndex) ReadVLI();
00089 Trackdir td = (Trackdir) ReadVLI();
00090 return new SignalStateCondition(this_sig, ti, td);
00091 }
00092
00093 default:
00094 return new SignalSimpleCondition(code);
00095 }
00096 }
00097
00098 static void Save_SPRG()
00099 {
00100
00101
00102
00103 for(ProgramList::iterator i = _signal_programs.begin(), e = _signal_programs.end();
00104 i != e; ++i) {
00105 SignalReference ref = i->first;
00106 if(!HasProgrammableSignals(ref)) {
00107 DEBUG(sl, 0, "Programmable signal information for (%x, %d) has been leaked!",
00108 ref.tile, ref.track);
00109 ++i;
00110 FreeSignalProgram(ref);
00111 if(i == e) break;
00112 }
00113 }
00114
00115
00116 Buffer b;
00117 WriteVLI(b, _signal_programs.size());
00118 for(ProgramList::iterator i = _signal_programs.begin(), e = _signal_programs.end();
00119 i != e; ++i) {
00120 SignalReference ref = i->first;
00121 SignalProgram *prog = i->second;
00122
00123 prog->DebugPrintProgram();
00124
00125 WriteVLI(b, prog->tile);
00126 WriteVLI(b, prog->track);
00127 WriteVLI(b, prog->instructions.Length());
00128 for(SignalInstruction **j = prog->instructions.Begin(), **je = prog->instructions.End();
00129 j != je; ++j) {
00130 SignalInstruction *insn = *j;
00131 WriteVLI(b, insn->Opcode());
00132 if(insn->Opcode() != PSO_FIRST)
00133 WriteVLI(b, insn->Previous()->Id());
00134 switch(insn->Opcode()) {
00135 case PSO_FIRST: {
00136 SignalSpecial *s = static_cast<SignalSpecial*>(insn);
00137 WriteVLI(b, s->next->Id());
00138 break;
00139 }
00140
00141 case PSO_LAST: break;
00142
00143 case PSO_IF: {
00144 SignalIf *i = static_cast<SignalIf*>(insn);
00145 WriteCondition(b, i->condition);
00146 WriteVLI(b, i->if_true->Id());
00147 WriteVLI(b, i->if_false->Id());
00148 WriteVLI(b, i->after->Id());
00149 break;
00150 }
00151
00152 case PSO_IF_ELSE:
00153 case PSO_IF_ENDIF: {
00154 SignalIf::PseudoInstruction *p = static_cast<SignalIf::PseudoInstruction*>(insn);
00155 WriteVLI(b, p->block->Id());
00156 break;
00157 }
00158
00159 case PSO_SET_SIGNAL: {
00160 SignalSet *s = static_cast<SignalSet*>(insn);
00161 WriteVLI(b, s->next->Id());
00162 WriteVLI(b, s->to_state ? 1 : 0);
00163 break;
00164 }
00165
00166 default: NOT_REACHED();
00167 }
00168 }
00169 }
00170
00171 uint size = b.size();
00172 SlSetLength(size);
00173 for(uint i = 0; i < size; i++)
00174 SlWriteByte(b[i]);
00175 }
00176
00177 static void Load_SSIG()
00178 {
00179 _speedlimits.clear();
00180
00181 uint count = ReadVLI();
00182 for(uint i = 0; i < count; i++) {
00183 TileIndex tile = ReadVLI();
00184 Track track = (Track) ReadVLI();
00185 uint16 speed = ReadVLI();
00186 SignalReference ref(tile, track);
00187
00188 _speedlimits[ref] = speed;
00189 }
00190 }
00191
00192 static void Save_SSIG()
00193 {
00194
00195
00196
00197 for(SpeedLimits::iterator i = _speedlimits.begin(), e = _speedlimits.end();
00198 i != e; ++i) {
00199 SignalReference ref = i->first;
00200 if(!HasSpeedSignals(ref)) {
00201 DEBUG(sl, 0, "Speed signal information for (%x, %d) has been leaked!",
00202 ref.tile, ref.track);
00203 ++i;
00204 FreeSignalSpeed(ref);
00205 if(i == e) break;
00206 }
00207 }
00208
00209
00210 Buffer b;
00211 WriteVLI(b, _speedlimits.size());
00212 for(SpeedLimits::iterator i = _speedlimits.begin(), e = _speedlimits.end();
00213 i != e; ++i) {
00214 SignalReference ref = i->first;
00215 uint16 speed = i->second;
00216
00217 WriteVLI(b, ref.tile);
00218 WriteVLI(b, ref.track);
00219 WriteVLI(b, speed);
00220 }
00221
00222 uint size = b.size();
00223 SlSetLength(size);
00224 for(uint i = 0; i < size; i++)
00225 SlWriteByte(b[i]);
00226 }
00227
00228
00229
00230
00231
00232
00233
00234
00235 struct Fixup {
00236 Fixup(SignalInstruction **p, SignalOpcode type)
00237 : type(type), ptr(p)
00238 {}
00239
00240 SignalOpcode type;
00241 SignalInstruction **ptr;
00242 };
00243
00244 typedef SmallVector<Fixup, 4> FixupList;
00245
00246 template<typename T>
00247 static void MakeFixup(FixupList &l, T *&ir, uint id, SignalOpcode op = PSO_INVALID)
00248 {
00249 ir = reinterpret_cast<T*>(id);
00250 new(l.Append()) Fixup(reinterpret_cast<SignalInstruction**>(&ir), op);
00251 }
00252
00253 static void DoFixups(FixupList &l, InstructionList &il)
00254 {
00255 for(Fixup *i = l.Begin(), *e = l.End(); i != e; ++i) {
00256 uint id = reinterpret_cast<size_t>(*i->ptr);
00257 if(id >= il.Length())
00258 NOT_REACHED();
00259
00260 *i->ptr = il[id];
00261
00262 if(i->type != PSO_INVALID && (*i->ptr)->Opcode() != i->type) {
00263 DEBUG(sl, 0, "Expected Id %d to be %d, but was in fact %d", id, i->type, (*i->ptr)->Opcode());
00264 NOT_REACHED();
00265 }
00266 }
00267 }
00268
00269 static void Load_SPRG()
00270 {
00271 uint count = ReadVLI();
00272 for(uint i = 0; i < count; i++) {
00273 FixupList l;
00274 TileIndex tile = ReadVLI();
00275 Track track = (Track) ReadVLI();
00276 uint instructions = ReadVLI();
00277 SignalReference ref(tile, track);
00278
00279 SignalProgram *sp = new SignalProgram(tile, track, true);
00280 _signal_programs[ref] = sp;
00281
00282 for(uint j = 0; j < instructions; j++) {
00283 SignalOpcode op = (SignalOpcode) ReadVLI();
00284 switch(op) {
00285 case PSO_FIRST: {
00286 sp->first_instruction = new SignalSpecial(sp, PSO_FIRST);
00287 sp->first_instruction->GetPrevHandle() = NULL;
00288 MakeFixup(l, sp->first_instruction->next, ReadVLI());
00289 break;
00290 }
00291
00292 case PSO_LAST: {
00293 sp->last_instruction = new SignalSpecial(sp, PSO_LAST);
00294 sp->last_instruction->next = NULL;
00295 MakeFixup(l, sp->last_instruction->GetPrevHandle(), ReadVLI());
00296 break;
00297 }
00298
00299 case PSO_IF: {
00300 SignalIf *i = new SignalIf(sp, true);
00301 MakeFixup(l, i->GetPrevHandle(), ReadVLI());
00302 i->condition = ReadCondition(ref);
00303 MakeFixup(l, i->if_true, ReadVLI());
00304 MakeFixup(l, i->if_false, ReadVLI());
00305 MakeFixup(l, i->after, ReadVLI());
00306 break;
00307 }
00308
00309 case PSO_IF_ELSE:
00310 case PSO_IF_ENDIF: {
00311 SignalIf::PseudoInstruction *p = new SignalIf::PseudoInstruction(sp, op);
00312 MakeFixup(l, p->GetPrevHandle(), ReadVLI());
00313 MakeFixup(l, p->block, ReadVLI(), PSO_IF);
00314 break;
00315 }
00316
00317 case PSO_SET_SIGNAL: {
00318 SignalSet *s = new SignalSet(sp);
00319 MakeFixup(l, s->GetPrevHandle(), ReadVLI());
00320 MakeFixup(l, s->next, ReadVLI());
00321 s->to_state = (SignalState) ReadVLI();
00322 if(s->to_state > SIGNAL_STATE_MAX) NOT_REACHED();
00323 break;
00324 }
00325
00326 default: NOT_REACHED();
00327 }
00328 }
00329
00330 DoFixups(l, sp->instructions);
00331 sp->DebugPrintProgram();
00332 }
00333 }
00334
00335 extern const ChunkHandler _signal_chunk_handlers[] = {
00336 { 'SPRG', Save_SPRG, Load_SPRG, NULL, NULL, CH_RIFF | CH_LAST},
00337 };
00338
00339 extern const ChunkHandler _speed_signal_chunk_handlers[] = {
00340 { 'SSIG', Save_SSIG, Load_SSIG, NULL, NULL, CH_RIFF | CH_LAST},
00341 };