~widelands-dev/widelands/trunk

« back to all changes in this revision

Viewing changes to src/logic/playercommand.cc

  • Committer: sigra
  • Date: 2010-01-04 03:32:50 UTC
  • Revision ID: git-v1:82d9f24adcbde7d19f90434aac5f96c7df58aa10
Fix bug #2924988 (crash when initialization removed between game preload and game start) reported by qcs - Qcumber-some.

Before the game is set up, the tribes are preloaded, which means that it is checked which tribes exist and which initializations each tribe has, so that each player can select a tribe and an initialization. The selected initialization is saved as an index. When the game is finally started, the tribes are fully read. Then a player is initialized with the initialization with the stored index.

But if for example a player has selected the initialization with index 1, then the tribe is edited so that there is no initialization with that index (such as only the initialization with index 0 remains), then the game i started, the tribe fully read, the player initialized with initialization 1, an assertion will fail in debug builds (and an out-of-range access will be done in release builds.

Now throw game_data_error when this happens. Of course it may still behave a bit unexpected if a player selects initialization a with index 0 and then initializaion a is removed and initialization b has index 0, but at least a crash is fixed.

Also make donkey breeding less broken.

git-svn-id: https://widelands.svn.sourceforge.net/svnroot/widelands/trunk@4870 37b2a8de-5219-0410-9f54-a31bc463ab9c

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/*
2
 
 * Copyright (C) 2004, 2007-2009 by the Widelands Development Team
 
2
 * Copyright (C) 2004, 2007-2010 by the Widelands Development Team
3
3
 *
4
4
 * This program is free software; you can redistribute it and/or
5
5
 * modify it under the terms of the GNU General Public License
52
52
        PLCMD_CHANGESOLDIERCAPACITY,
53
53
        PLCMD_ENEMYFLAGACTION,
54
54
        PLCMD_SETWAREPRIORITY,
55
 
        PLCMD_SETTARGETQUANTITY,
56
 
        PLCMD_RESETTARGETQUANTITY
 
55
        PLCMD_SETWARETARGETQUANTITY,
 
56
        PLCMD_RESETWARETARGETQUANTITY,
 
57
        PLCMD_SETWORKERTARGETQUANTITY,
 
58
        PLCMD_RESETWORKERTARGETQUANTITY
57
59
};
58
60
 
59
61
/*** class PlayerCommand ***/
73
75
        case PLCMD_STARTSTOPBUILDING:     return new Cmd_StartStopBuilding    (des);
74
76
        case PLCMD_ENHANCEBUILDING:       return new Cmd_EnhanceBuilding      (des);
75
77
        case PLCMD_SETWAREPRIORITY:       return new Cmd_SetWarePriority      (des);
76
 
        case PLCMD_SETTARGETQUANTITY:     return new Cmd_SetTargetQuantity    (des);
77
 
        case PLCMD_RESETTARGETQUANTITY:   return new Cmd_ResetTargetQuantity  (des);
 
78
        case PLCMD_SETWARETARGETQUANTITY:
 
79
                return new Cmd_SetWareTargetQuantity    (des);
 
80
        case PLCMD_RESETWARETARGETQUANTITY:
 
81
                return new Cmd_ResetWareTargetQuantity  (des);
 
82
        case PLCMD_SETWORKERTARGETQUANTITY:
 
83
                return new Cmd_SetWareTargetQuantity    (des);
 
84
        case PLCMD_RESETWORKERTARGETQUANTITY:
 
85
                return new Cmd_ResetWareTargetQuantity  (des);
78
86
        case PLCMD_CHANGETRAININGOPTIONS: return new Cmd_ChangeTrainingOptions(des);
79
87
        case PLCMD_DROPSOLDIER:           return new Cmd_DropSoldier          (des);
80
88
        case PLCMD_CHANGESOLDIERCAPACITY: return new Cmd_ChangeSoldierCapacity(des);
677
685
}
678
686
 
679
687
 
680
 
Cmd_SetTargetQuantity::Cmd_SetTargetQuantity
 
688
Cmd_SetWareTargetQuantity::Cmd_SetWareTargetQuantity
681
689
        (int32_t const _duetime, Player_Number const _sender,
682
690
         uint32_t const _economy,
683
691
         Ware_Index const _ware_type,
687
695
        m_permanent(_permanent), m_temporary(_temporary)
688
696
{}
689
697
 
690
 
void Cmd_SetTargetQuantity::execute(Game & game)
 
698
void Cmd_SetWareTargetQuantity::execute(Game & game)
691
699
{
692
700
        Player & player = game.player(sender());
693
701
        if
694
702
                (economy  () < player.get_nr_economies() and
695
703
                 ware_type() < player.tribe().get_nrwares())
696
 
        {
697
 
                player.get_economy_by_number(economy())->set_target_quantity
 
704
                player.get_economy_by_number(economy())->set_ware_target_quantity
698
705
                        (ware_type(),  m_permanent, m_temporary, duetime());
699
 
        }
700
706
}
701
707
 
702
 
#define PLAYER_CMD_SETTARGETQUANTITY_VERSION 1
 
708
#define PLAYER_CMD_SETWARETARGETQUANTITY_VERSION 1
703
709
 
704
 
void Cmd_SetTargetQuantity::Write
 
710
void Cmd_SetWareTargetQuantity::Write
705
711
        (FileWrite & fw, Editor_Game_Base & egbase, Map_Map_Object_Saver & mos)
706
712
{
707
 
        fw.Unsigned16(PLAYER_CMD_SETTARGETQUANTITY_VERSION);
 
713
        fw.Unsigned16(PLAYER_CMD_SETWARETARGETQUANTITY_VERSION);
708
714
        Cmd_ChangeTargetQuantity::Write(fw, egbase, mos);
709
715
        fw.Unsigned32(m_permanent);
710
716
        fw.Unsigned32(m_temporary);
711
717
}
712
718
 
713
 
void Cmd_SetTargetQuantity::Read
 
719
void Cmd_SetWareTargetQuantity::Read
714
720
        (FileRead & fr, Editor_Game_Base & egbase, Map_Map_Object_Loader & mol)
715
721
{
716
722
        try {
717
723
                uint16_t const packet_version = fr.Unsigned16();
718
 
                if (packet_version == PLAYER_CMD_SETTARGETQUANTITY_VERSION) {
 
724
                if (packet_version == PLAYER_CMD_SETWARETARGETQUANTITY_VERSION) {
719
725
                        Cmd_ChangeTargetQuantity::Read(fr, egbase, mol);
720
726
                        m_permanent = fr.Unsigned32();
721
727
                        m_temporary = fr.Unsigned32();
723
729
                        throw game_data_error
724
730
                                (_("unknown/unhandled version %u"), packet_version);
725
731
        } catch (_wexception const & e) {
726
 
                throw game_data_error(_("set target quantity: %s"), e.what());
 
732
                throw game_data_error(_("set ware target quantity: %s"), e.what());
727
733
        }
728
734
}
729
735
 
730
 
Cmd_SetTargetQuantity::Cmd_SetTargetQuantity(StreamRead & des)
 
736
Cmd_SetWareTargetQuantity::Cmd_SetWareTargetQuantity(StreamRead & des)
731
737
        :
732
738
        Cmd_ChangeTargetQuantity(des),
733
739
        m_permanent             (des.Unsigned32()),
734
740
        m_temporary             (des.Unsigned32())
735
741
{}
736
742
 
737
 
void Cmd_SetTargetQuantity::serialize(StreamWrite & ser)
 
743
void Cmd_SetWareTargetQuantity::serialize(StreamWrite & ser)
738
744
{
739
 
        ser.Unsigned8 (PLCMD_SETTARGETQUANTITY);
 
745
        ser.Unsigned8 (PLCMD_SETWARETARGETQUANTITY);
740
746
        Cmd_ChangeTargetQuantity::serialize(ser);
741
747
        ser.Unsigned32(m_permanent);
742
748
        ser.Unsigned32(m_temporary);
743
749
}
744
750
 
745
751
 
746
 
Cmd_ResetTargetQuantity::Cmd_ResetTargetQuantity
 
752
Cmd_ResetWareTargetQuantity::Cmd_ResetWareTargetQuantity
747
753
        (int32_t const _duetime, Player_Number const _sender,
748
754
         uint32_t const _economy,
749
755
         Ware_Index const _ware_type)
751
757
        Cmd_ChangeTargetQuantity(_duetime, _sender, _economy, _ware_type)
752
758
{}
753
759
 
754
 
void Cmd_ResetTargetQuantity::execute(Game & game)
 
760
void Cmd_ResetWareTargetQuantity::execute(Game & game)
755
761
{
756
762
        Player & player = game.player(sender());
757
763
        Tribe_Descr const & tribe = player.tribe();
761
767
        {
762
768
                int32_t const count =
763
769
                        tribe.get_ware_descr(ware_type())->default_target_quantity();
764
 
                player.get_economy_by_number(economy())->set_target_quantity
 
770
                player.get_economy_by_number(economy())->set_ware_target_quantity
765
771
                        (ware_type(),  count, count, 0);
766
772
        }
767
773
}
768
774
 
769
 
#define PLAYER_CMD_RESETTARGETQUANTITY_VERSION 1
 
775
#define PLAYER_CMD_RESETWARETARGETQUANTITY_VERSION 1
770
776
 
771
 
void Cmd_ResetTargetQuantity::Write
 
777
void Cmd_ResetWareTargetQuantity::Write
772
778
        (FileWrite & fw, Editor_Game_Base & egbase, Map_Map_Object_Saver & mos)
773
779
{
774
 
        fw.Unsigned16(PLAYER_CMD_SETTARGETQUANTITY_VERSION);
 
780
        fw.Unsigned16(PLAYER_CMD_RESETWARETARGETQUANTITY_VERSION);
775
781
        Cmd_ChangeTargetQuantity::Write(fw, egbase, mos);
776
782
}
777
783
 
778
 
void Cmd_ResetTargetQuantity::Read
 
784
void Cmd_ResetWareTargetQuantity::Read
779
785
        (FileRead & fr, Editor_Game_Base & egbase, Map_Map_Object_Loader & mol)
780
786
{
781
787
        try {
782
788
                uint16_t const packet_version = fr.Unsigned16();
783
 
                if (packet_version == PLAYER_CMD_RESETTARGETQUANTITY_VERSION) {
 
789
                if (packet_version == PLAYER_CMD_RESETWARETARGETQUANTITY_VERSION)
784
790
                        Cmd_ChangeTargetQuantity::Read(fr, egbase, mol);
785
 
                } else
 
791
                else
786
792
                        throw game_data_error
787
793
                                (_("unknown/unhandled version %u"), packet_version);
788
794
        } catch (_wexception const & e) {
790
796
        }
791
797
}
792
798
 
793
 
Cmd_ResetTargetQuantity::Cmd_ResetTargetQuantity(StreamRead & des)
794
 
        : Cmd_ChangeTargetQuantity(des)
795
 
{}
796
 
 
797
 
void Cmd_ResetTargetQuantity::serialize(StreamWrite & ser)
798
 
{
799
 
        ser.Unsigned8 (PLCMD_RESETTARGETQUANTITY);
 
799
Cmd_ResetWareTargetQuantity::Cmd_ResetWareTargetQuantity(StreamRead & des)
 
800
        : Cmd_ChangeTargetQuantity(des)
 
801
{}
 
802
 
 
803
void Cmd_ResetWareTargetQuantity::serialize(StreamWrite & ser)
 
804
{
 
805
        ser.Unsigned8 (PLCMD_RESETWARETARGETQUANTITY);
 
806
        Cmd_ChangeTargetQuantity::serialize(ser);
 
807
}
 
808
 
 
809
 
 
810
Cmd_SetWorkerTargetQuantity::Cmd_SetWorkerTargetQuantity
 
811
        (int32_t const _duetime, Player_Number const _sender,
 
812
         uint32_t const _economy,
 
813
         Ware_Index const _ware_type,
 
814
         uint32_t const _permanent, uint32_t const _temporary)
 
815
        :
 
816
        Cmd_ChangeTargetQuantity(_duetime, _sender, _economy, _ware_type),
 
817
        m_permanent(_permanent), m_temporary(_temporary)
 
818
{}
 
819
 
 
820
void Cmd_SetWorkerTargetQuantity::execute(Game & game)
 
821
{
 
822
        Player & player = game.player(sender());
 
823
        if
 
824
                (economy  () < player.get_nr_economies() and
 
825
                 ware_type() < player.tribe().get_nrwares())
 
826
                player.get_economy_by_number(economy())->set_worker_target_quantity
 
827
                        (ware_type(),  m_permanent, m_temporary, duetime());
 
828
}
 
829
 
 
830
#define PLAYER_CMD_SETWORKERTARGETQUANTITY_VERSION 1
 
831
 
 
832
void Cmd_SetWorkerTargetQuantity::Write
 
833
        (FileWrite & fw, Editor_Game_Base & egbase, Map_Map_Object_Saver & mos)
 
834
{
 
835
        fw.Unsigned16(PLAYER_CMD_SETWORKERTARGETQUANTITY_VERSION);
 
836
        Cmd_ChangeTargetQuantity::Write(fw, egbase, mos);
 
837
        fw.Unsigned32(m_permanent);
 
838
        fw.Unsigned32(m_temporary);
 
839
}
 
840
 
 
841
void Cmd_SetWorkerTargetQuantity::Read
 
842
        (FileRead & fr, Editor_Game_Base & egbase, Map_Map_Object_Loader & mol)
 
843
{
 
844
        try {
 
845
                uint16_t const packet_version = fr.Unsigned16();
 
846
                if (packet_version == PLAYER_CMD_SETWORKERTARGETQUANTITY_VERSION) {
 
847
                        Cmd_ChangeTargetQuantity::Read(fr, egbase, mol);
 
848
                        m_permanent = fr.Unsigned32();
 
849
                        m_temporary = fr.Unsigned32();
 
850
                } else
 
851
                        throw game_data_error
 
852
                                (_("unknown/unhandled version %u"), packet_version);
 
853
        } catch (_wexception const & e) {
 
854
                throw game_data_error(_("set worker target quantity: %s"), e.what());
 
855
        }
 
856
}
 
857
 
 
858
Cmd_SetWorkerTargetQuantity::Cmd_SetWorkerTargetQuantity(StreamRead & des)
 
859
        :
 
860
        Cmd_ChangeTargetQuantity(des),
 
861
        m_permanent             (des.Unsigned32()),
 
862
        m_temporary             (des.Unsigned32())
 
863
{}
 
864
 
 
865
void Cmd_SetWorkerTargetQuantity::serialize(StreamWrite & ser)
 
866
{
 
867
        ser.Unsigned8 (PLCMD_SETWORKERTARGETQUANTITY);
 
868
        Cmd_ChangeTargetQuantity::serialize(ser);
 
869
        ser.Unsigned32(m_permanent);
 
870
        ser.Unsigned32(m_temporary);
 
871
}
 
872
 
 
873
 
 
874
Cmd_ResetWorkerTargetQuantity::Cmd_ResetWorkerTargetQuantity
 
875
        (int32_t const _duetime, Player_Number const _sender,
 
876
         uint32_t const _economy,
 
877
         Ware_Index const _ware_type)
 
878
        :
 
879
        Cmd_ChangeTargetQuantity(_duetime, _sender, _economy, _ware_type)
 
880
{}
 
881
 
 
882
void Cmd_ResetWorkerTargetQuantity::execute(Game & game)
 
883
{
 
884
        Player & player = game.player(sender());
 
885
        Tribe_Descr const & tribe = player.tribe();
 
886
        if
 
887
                (economy  () < player.get_nr_economies() and
 
888
                 ware_type() < tribe.get_nrwares())
 
889
        {
 
890
                int32_t const count =
 
891
                        tribe.get_ware_descr(ware_type())->default_target_quantity();
 
892
                player.get_economy_by_number(economy())->set_worker_target_quantity
 
893
                        (ware_type(),  count, count, 0);
 
894
        }
 
895
}
 
896
 
 
897
#define PLAYER_CMD_RESETWORKERTARGETQUANTITY_VERSION 1
 
898
 
 
899
void Cmd_ResetWorkerTargetQuantity::Write
 
900
        (FileWrite & fw, Editor_Game_Base & egbase, Map_Map_Object_Saver & mos)
 
901
{
 
902
        fw.Unsigned16(PLAYER_CMD_RESETWORKERTARGETQUANTITY_VERSION);
 
903
        Cmd_ChangeTargetQuantity::Write(fw, egbase, mos);
 
904
}
 
905
 
 
906
void Cmd_ResetWorkerTargetQuantity::Read
 
907
        (FileRead & fr, Editor_Game_Base & egbase, Map_Map_Object_Loader & mol)
 
908
{
 
909
        try {
 
910
                uint16_t const packet_version = fr.Unsigned16();
 
911
                if (packet_version == PLAYER_CMD_RESETWORKERTARGETQUANTITY_VERSION) {
 
912
                        Cmd_ChangeTargetQuantity::Read(fr, egbase, mol);
 
913
                } else
 
914
                        throw game_data_error
 
915
                                (_("unknown/unhandled version %u"), packet_version);
 
916
        } catch (_wexception const & e) {
 
917
                throw game_data_error("reset worker target quantity: %s", e.what());
 
918
        }
 
919
}
 
920
 
 
921
Cmd_ResetWorkerTargetQuantity::Cmd_ResetWorkerTargetQuantity(StreamRead & des)
 
922
        : Cmd_ChangeTargetQuantity(des)
 
923
{}
 
924
 
 
925
void Cmd_ResetWorkerTargetQuantity::serialize(StreamWrite & ser)
 
926
{
 
927
        ser.Unsigned8 (PLCMD_RESETWORKERTARGETQUANTITY);
800
928
        Cmd_ChangeTargetQuantity::serialize(ser);
801
929
}
802
930