Commit cd8d742 mechanically combined struct mlist's mcp and struct
llist's llp into struct ulist's chrp, adding type casts to every use.
Not necessary, simply use mchr[] and lchr[] directly.
Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
TREATIES has issues:
* Treaties can cover attack, assault, paradrop, board, lboard, fire,
build (s|p|l|n) and enlist, but not bomb, launch, torpedo and
enlistment centers.
* Usability is very poor. While a treaty is in effect, every player
action that violates a treaty condition triggers a prompt like this:
This action is in contravention of treaty #0 (with Curmudgeon)
Do you wish to go ahead anyway? [yn]
If you decline, the action is not executed. If you accept, it is.
In both cases, your decision is reported in the news.
You cannot get rid of these prompts until the treaty expires.
* Virtually nobody uses them.
* Virtually unused code is buggy code. There is at least one race
condition: multifire() reads the firing sector, ship or land unit
before the treaty prompt, and writes it back after, triggering a
generation oops. Any updates made by other threads while trechk()
waits for input are wiped out, triggering a seqno mismatch oops.
* The treaty prompts could confuse smart clients that aren't prepared
for them. WinACE isn't, but is reported to work anyway at least
common usage. Ron Koenderink (the WinACE maintainer) suspects there
could be a few situations where it will fail.
This feature is not earning its keep. Remove it. Drop command
treaty, consider treaty, offer treaty, xdump treaty, reject treaties.
Output of accept changed, obviously.
Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
verify_row() refrains from rejecting zero uids, because some tables
may contain blank entries, with zero uid.
Change it to check only header sanity for entries that are not in use.
This filters out all legitimately blank entries. Tighten up the uid
check.
For computing "in use", factor empobj_in_use() out of xdvisible().
Note that xdvisible()'s case EF_COUNTRY doesn't bother to check
nat_stat, because that's implied by what it does check. It's not
implied in empobj_in_use(), so add it there.
Why upgrade? I'm not a lawyer, but here's my take on the differences
to version 2:
* Software patents: better protection against abuse of patents to
prevent users from exercising the rights under the GPL. I doubt
we'll get hit with a patent suit, but it's a good move just on
general principles.
* License compatibility: compatible with more free licenses, i.e. can
"steal" more free software for use in Empire. I don't expect to steal
much, but it's nice to have the option.
* Definition of "source code": modernization of some details for today's
networked world, to make it easier to distribute the software. Not
really relevant to us now, as we normally distribute full source code.
* Tivoization: this is about putting GPL-licensed software in hardware,
then make the hardware refuse to run modified software. "Neat" trick
to effectively deny its users their rights under the GPL. Abuse was
"pioneered" by TiVo (popular digital video recorders). GPLv3 forbids
it. Unlikely to become a problem for us.
* Internationalization: more careful wording, to harden the license
outside the US. The lawyers tell us it better be done that way.
* License violations: friendlier way to deal with license violations.
This has come out of past experience enforcing the GPL.
* Additional permissions: Probably not relevant to us.
Also include myself in the list of principal authors.
Oops when a stale copy is written back, i.e. the processor was yielded
since the copy was made. Such bugs are difficult to spot. Sequence
numbers catch them when they do actual harm (they also catch different
bugs). Generation numbers catch them even when they don't.
New ef_generation to count generations. Call new ef_make_stale() to
increment it whenever the processor may be yielded.
New struct emptypedstr member generation. To conserve space, make it
a bit-field of twelve bits, i.e. generations are only recorded modulo
2^12. Make sure all members of unit empobj_storage share it. It is
only used in copies; its value on disk and in the cache is
meaningless. Copies with generation other than ef_generation are
stale. Stale copies that are a multiple of 2^12 generations old can't
be detected, but that is sufficiently improbable.
Set generation to ef_generation by calling new ef_mark_fresh() when
making copies in ef_read() and ef_blank(). nav_ship() and
fltp_to_list() make copies without going through ef_read(), and
therefore need to call ef_mark_fresh() as well. Also call it in
obj_changed() to make check_sect_ok() & friends freshen their argument
when it is unchanged.
New must_be_fresh() oopses when its argument is stale. Call it in
ef_write() to catch write back of stale copies.
Store them and ef_type in bit-fields.
Allocate eight bits for ef_type. Values range from 0 to EF_GAME
(currently 16), so this is plenty.
Allocate twelve bits for sequence numbers. Sequence number mismatches
are now missed when the numbers are equal modulo 2^12. Still
sufficiently improbable.
Common machines store the bit-fields in a 32 bit word. There are
twelve bits left in that word for future use. Total savings 16 bits,
which is exactly what the previous commit spent on wider uids on
common machines.
Before, they were stored as short. Wider uids use more space, but the
next commit will recover it by narrowing other members.
The use of short has always limited the number of ships, planes, land
units and nukes to SHRT_MAX (commonly 32768). Only the most extreme
games ever came close.
Commit 49780e2c (v4.3.12) added struct sctstr member sct_uid to make
struct empobj member uid work for sectors. This made the limit apply
to sectors as well. We've had games with more than 32768 sectors.
Member nws_uid is unused since the commit before previous. Remove it.
Member nws_seqno is of marginal value, because we write news only
through ncache[], and thus aren't prone to the errors sequence numbers
can catch. Remove it.
Make timestamp selector virtual, computing nws_when + nws_duration,
and remove member nws_timestamp. Impact:
* In ncache(), the removed timestamp equals nws_when + nws_duration,
both for new news and updated news. No change.
* delete_old_news() becomes invisible. Before, its move of unexpired
news to the beginning of the news file touched all the timestamps.
That was unwanted, because the move does not change news, only their
storage. Improvement.
* empdump no longer flags the imported news changed via the timestamp.
This is somewhat unfortunate. Document as bug.
With these members removed, struct nwsstr no longer matches struct
emptypedstr, so clear news table flag EFF_TYPED and remove union
empobj_storage member news. This loses the automatic maintenance of
member ef_type via struct emptypedstr. Remove ef_type as well.
This shrinks struct nwsstr from 20 to 12 bytes on common 32 bit
machines, and from 32 to 16 bytes on common 64 bit machines. Since
the server doesn't map the whole news file (EFF_MAP is off), this
reduces I/O, while the table's memory use remains the same.
Historical note: struct nwsstr is now pretty much what it was back in
BSD Empire 1.1. Members ef_type and nws_uid go back to Empire 3 (for
C_SYNC?). v4.3.12 added member nws_timestamp, which doubled the size
on common 64 bit machines. v4.3.15 added nws_seqno.
This oopses on output dependency violations, e.g. two threads doing a
read-modify-write without synchronization, or the one thread nesting
several read-modify-writes. Such bugs are difficult to spot, and tend
to be abusable. I figure we have quite a few of them.
New struct emptypedstr member seqno. Make sure all members of unit
empobj_storage share it. Initialize it in files: main() and
file_sct_init(). Set it in ef_blank() and new ef_set_uid() by calling
new get_seqno(). Use ef_set_uid() when copying objects: swaps(),
doland(), doship(), doplane(), dounit(), delete_old_news(). Step it
in ef_write() by calling new new_seqno().
Factor do_read() out of fillcache() to make it available for
get_seqno().
Make sure all members of unit empobj_storage share it.
Add matching timestamp member to struct comstr, struct empobj, struct
gamestr, struct lonstr, struct natstr, struct nwsstr, struct trdstr,
struct trtstr. The timestamp isn't yet set for these. To be fixed.
Move the timestamp member to the right place in struct lndstr, struct
loststr, struct realmstr, struct nukstr, struct plnstr, struct sctstr,
struct shpstr.
New struct emptypedstr to avoid depending on empobj.h there.
Remove now superfluous manual initializations elsewhere.
This doesn't fix any missing initializations.
Make sure all members of unit empobj_storage share uid in addition to
ef_type.
Add matching uid member to struct gamestr, struct natstr and struct
sctstr, and set them.
Swap struct empobj members uid and own to make that easier, and update
struct comstr, struct lndstr, struct lonstr, struct loststr, struct
nwsstr, struct nukstr, struct plnstr, struct realmstr, struct shpstr,
struct trdstr, struct trtstr accordingly.
Note that the uid isn't properly set for struct nwsstr, struct lonstr,
struct trdstr, struct comstr and struct loststr. To be fixed.
put_empobj() used struct empobj member uid, which is valid only for
units. Existing users pass only units, fortunately. Fix by making it
take type and uid parameters.
get_empobj_chr() and emp_obj_chr_name() access struct sctstr member
sct_type through struct empobj member type. This is technically
non-portable, because the two differ in signedness. It was also
undocumented. Fix by making sct_type signed. sct_newtype as well,
for consistency.
map_char() uses unsigned char for a sector type argument. Change that
to int. Matches how this is done elsewhere.
(gamestr, EF_GAME, game_ca): New.
(empfile): Declare the table.
(ef_open_srv, ef_close_srv): Open and close it.
(main): Create it.
(empobj_storage): New member game.
(EF_DYNMAX): New.
(EF_IS_GAME_STATE): Use it.
(emp_obj_chr_name): New. Returns a pointer to the characteristics name
for an empobj.
(unit_map): Simplify unit_map() by using get_empobjp() and
emp_obj_chr_name().
(map, cmd_move_map): Switch to EF_SHIP as unit_map does not default
to EF_SHIP for EF_BAD anymore.
(get_empobj_chr): New. Get characteristics for empobj.
(mission, build_mission_list_type): Switch to use new
functions put_empobj() and get_empobj_chr().
other. Ensure headers in include/ can be included in any order
(except for econfig-spec.h, which is special). New header types.h to
help avoid inclusion cycles. Sort include directives. Remove some
superflous includes.
oprange, show_mission, nameofitem, build_mission_list_type,
unit_map, xdvisible, trdswitchown, ontradingblock, trad, check_trade,
unit_type_name, start_stop_unit, scut, scra, mission, multifire,
perform_mission, fuel, NSC_GENITEM): Replace struct genitem with
struct empobj. Remove genitem.h and create a new file empobj.h.
Replace multiple instances of unions of ef_type structures with
one standard union empobj_storage which is a superset of the individual
instances.