I'll add to wiki once the first round of flaming has completed ;-)
Please find attached document. It probably needs some tweaking, but I
think the core idea is valid.
It's a bit more complex then the current version but it:
- Avoids the needs to serialise things
(eg multiple deletes or inserts).
- Allows order caching
- Allows smaller insertion messages
- Requires fewer messages
- Saves messages for small changes
One outstanding issue is when to know the specific order desctiption is
out of date.
My currnet thinking is to add a last changed field to the orderid,
version# list in current orders (so you can see it's changed there).
However I fear for non-trivial games it will need updating every turn
anyway :-(
Regards,
nash
New Order Identification
========================
Problem
-------
Orders in Thousand Parsec are currently broken. Inherently.
The main issue is they are identified by (ObjectID, PositionInQueue).
The main issue is of course position in queue. This is changed by:
- Turn (some orders are consumed during turn processing)
- Deleting _other_ orders
- Adding _other_ orders.
In particular, deleting or adding an order puts the queue in an indeterminate
state until the reply is received requiring the client to enqueue future order
operations until the first request is processed. If a game allowed multiple
users (or even the same user connected through two clients) to modify the same
order queue, the order queue is essentially ALWAYS in an indeterminate state
for all clients.
Your only hope is to delete everything and re-add everything and hope nothing
interrupts you in the middle... Good luck with that.
Additionally the lack of identifier means all orders on known objects need to
re-downloaded each turn, even though no real changes have been made. This is
no good.
Outline Proposed Solution
-------------------------
Orders are identified by:
<OrderID, Version#>
The OrderID, Version is unique, and unchangining.
The general idea is based on the way graphics contexts are used in things such
as X11, where contexts are registered with the server, then future operations
are defined in terms of these contexts. The Version# (alternatively) instance
allows the use of individual OrderIds to uniquely identified in their context.
Orders sharing the same OrderID are the same order, for instance (build a
Frigate), or (Move to planet Omicron Persei 8).
Orders are registered with the server:
Client Sends:
Order ID Register:
Order Paramaters
Server Replies:
Fail - Bad paramaters
Fail - Lack of resources
Ok + OrderID
If an order id is requested, and it already exists, the server may respond
with either the existing ID, or a new one at it's discretion. For instance
the simplest implementation is to use a new ID, a more sophisticated version
may check for existing use of that order, and send back an existing ID if
available.
Clients similarly may choose to either cache IDs and reuse them, or they may
naively register a new order each time.
Clients should(but don't need too) cache order IDs for performance reasons.
Similarly servers should re-use OrderIDs if possible.
The OrderID -1 is invalid, and is reserved for use in specific contexts.
If OrderIDs are shared between users, OrderIDs MUST be generated at random,
not sequentially. Ideally OrderIDs should be shared between players to save
server resources. It is recommended OrderIDs always be generated randomly.
Object Implementation
---------------------
Objects now contain an ordered list of:
<OrderID, Version#>
Order Manipulation
------------------
To manipulate the list orders are referred to relative to current orders in
the list, NOT order positions.
Delete
-------
Delete an order becomes:
Order delete, <ObjectID, OrderID, Version#>
This obviously unique, and multiple may be issued without concern.
Alternatively:
Order Delete <OrderID, Version#>
could in theory be allowed, but it makes the servers more complex (ObjectID
is redundant in this context).
Insert
------
Insert an order becomes:
Insert Order, <ObjectID, OrderID>
To insert into a particular slot you specify the order it should be inserted
before. To insert at end just specify the NIL order (0).
The response will be:
Fail - (standard failure reasons)
or
Ok + <ObjectId, VersionID>
+ Final Turn
+ List of Resources
Reorder Command
---------------
The ability to reorder the list of orders should also be supported.
It will simply be the list of new OrdertId, Version# pairs on the object.
ReorderOrders [List of <OrderID, Version#>]
It will fail if:
Any <OrderID, VersionID> pairs are missing in the new list
There are any <OrderID, VersionID> pairs extra in the new list
(ie, it cannot be used to add or delete orders, but will fail if there are any
changes to the list)
This can be used by a client to check the list is what they expect at any
time.
Valid Orders
------------
Valid orders on an object may additionally be checked using OrderIDs.
So a client could ask: Which of these orders are allowed on object N?
This is optional to this proposal.
Version#
--------
Each time an order is used a unique Version# for that OrderID is generated.
Version#s are not unique across OrderIDs, just amongst a particular OrderID.
Version#s may not be reused.
If OrderIds are being shared between users (recommended), Version#s MUST be
generated randomly (ala Non-sequentially). It is recommended Version#s always
be randomly generated.
OrderSpecific Data
------------------
The information currently contained in the order fields:
Number of turns
List of resources
Needs to retrieved separately for each OrderId, VersionID field.
A new:
GetSpecificOrderResources <ObjectID, OrderID, Version#>
message needs to be created.
It returns the data for this specific order.
Client Implementation Notes
---------------------------
Clients should cache and reuse orders as much as possible. In particular AIs
which will often use similar patterns for things should reuse orders as much
as possible.
Multiple orders can be safely appended in order by using the -1 OrderID,
Multiple orders can be inserted safely before another order by inserting in
reverse order. Alternatively append the orders, then atomically reorder.
Multiple deletions can be performed safely due to unique IDs.
Mixed insertions and deletions can be performed, using either a series of
appends and deletes with a reorder, or arbitrary insertions and deletions. A
failed deletion will generally mean the non-deleted object immediately
proceeds the new order.
Replacing an order safely can be performed in a few ways:
Insert Before Old order
Delete old order
If the delete fails, the new order will at least be in the queue first which
may or may not invalidate the second. Failure of insert means no order in
queue.
Alternatively:
Delete Old Order
Insert before next order
If the delete fails the new order is after the old. If in
Alternatively:
Move old order to end of list
Insert new order
delete old order
Send two reorders to cover the two failure cases, putting list in
safe order. Will fail with no consequence if insertion and deletion
work.
_______________________________________________
tp-devel mailing list
[email protected]
http://www.thousandparsec.net/tp/mailman.php/listinfo/tp-devel