mirror of https://github.com/OpenTTD/OpenTTD.git
(svn r240) -Fix: desync on subsidy generation
-Fix: sometimes commands got executed to early on some clients -Feature: universal event packets for transmitting subsidys
This commit is contained in:
parent
9258f81405
commit
bb2f8d8d1a
39
economy.c
39
economy.c
|
@ -11,6 +11,7 @@
|
||||||
#include "economy.h"
|
#include "economy.h"
|
||||||
#include "industry.h"
|
#include "industry.h"
|
||||||
#include "town.h"
|
#include "town.h"
|
||||||
|
#include "network.h"
|
||||||
|
|
||||||
void UpdatePlayerHouse(Player *p, uint score)
|
void UpdatePlayerHouse(Player *p, uint score)
|
||||||
{
|
{
|
||||||
|
@ -807,11 +808,11 @@ static void FindSubsidyPassengerRoute(FoundRoute *fr)
|
||||||
|
|
||||||
fr->distance = (uint)-1;
|
fr->distance = (uint)-1;
|
||||||
|
|
||||||
fr->from = from = DEREF_TOWN(RandomRange(_total_towns));
|
fr->from = from = DEREF_TOWN(InteractiveRandomRange(_total_towns));
|
||||||
if (from->xy == 0 || from->population < 400)
|
if (from->xy == 0 || from->population < 400)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
fr->to = to = DEREF_TOWN(RandomRange(_total_towns));
|
fr->to = to = DEREF_TOWN(InteractiveRandomRange(_total_towns));
|
||||||
if (from==to || to->xy == 0 || to->population < 400 || to->pct_pass_transported > 42)
|
if (from==to || to->xy == 0 || to->population < 400 || to->pct_pass_transported > 42)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -826,12 +827,12 @@ static void FindSubsidyCargoRoute(FoundRoute *fr)
|
||||||
|
|
||||||
fr->distance = (uint)-1;
|
fr->distance = (uint)-1;
|
||||||
|
|
||||||
fr->from = i = DEREF_INDUSTRY(RandomRange(_total_industries));
|
fr->from = i = DEREF_INDUSTRY(InteractiveRandomRange(_total_industries));
|
||||||
if (i->xy == 0)
|
if (i->xy == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Randomize cargo type
|
// Randomize cargo type
|
||||||
if (Random()&1 && i->produced_cargo[1] != 0xFF) {
|
if (InteractiveRandom()&1 && i->produced_cargo[1] != 0xFF) {
|
||||||
cargo = i->produced_cargo[1];
|
cargo = i->produced_cargo[1];
|
||||||
trans = i->pct_transported[1];
|
trans = i->pct_transported[1];
|
||||||
total = i->total_production[1];
|
total = i->total_production[1];
|
||||||
|
@ -851,7 +852,7 @@ static void FindSubsidyCargoRoute(FoundRoute *fr)
|
||||||
|
|
||||||
if (cargo == CT_GOODS || cargo == CT_FOOD) {
|
if (cargo == CT_GOODS || cargo == CT_FOOD) {
|
||||||
// The destination is a town
|
// The destination is a town
|
||||||
Town *t = DEREF_TOWN(RandomRange(_total_towns));
|
Town *t = DEREF_TOWN(InteractiveRandomRange(_total_towns));
|
||||||
|
|
||||||
// Only want big towns
|
// Only want big towns
|
||||||
if (t->xy == 0 || t->population < 900)
|
if (t->xy == 0 || t->population < 900)
|
||||||
|
@ -860,7 +861,7 @@ static void FindSubsidyCargoRoute(FoundRoute *fr)
|
||||||
fr->to = t;
|
fr->to = t;
|
||||||
} else {
|
} else {
|
||||||
// The destination is an industry
|
// The destination is an industry
|
||||||
Industry *i2 = DEREF_INDUSTRY(RandomRange(_total_industries));
|
Industry *i2 = DEREF_INDUSTRY(InteractiveRandomRange(_total_industries));
|
||||||
|
|
||||||
// The industry must accept the cargo
|
// The industry must accept the cargo
|
||||||
if (i == i2 || i2->xy == 0 ||
|
if (i == i2 || i2->xy == 0 ||
|
||||||
|
@ -890,6 +891,25 @@ static bool CheckSubsidyDuplicate(Subsidy *s)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RemoteSubsidyAdd(Subsidy *s_new)
|
||||||
|
{
|
||||||
|
Subsidy *s;
|
||||||
|
Pair pair;
|
||||||
|
|
||||||
|
// search the first free subsidy
|
||||||
|
for(s=_subsidies; s != endof(_subsidies); s++)
|
||||||
|
if (s->cargo_type == 0xFF)
|
||||||
|
break;
|
||||||
|
|
||||||
|
memcpy(s,s_new,sizeof(Subsidy));
|
||||||
|
|
||||||
|
pair = SetupSubsidyDecodeParam(s, 0);
|
||||||
|
AddNewsItem(STR_2030_SERVICE_SUBSIDY_OFFERED, NEWS_FLAGS(NM_NORMAL, NF_TILE, NT_SUBSIDIES, 0), pair.a, pair.b);
|
||||||
|
|
||||||
|
InvalidateWindow(WC_SUBSIDIES_LIST, 0);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
static void SubsidyMonthlyHandler()
|
static void SubsidyMonthlyHandler()
|
||||||
{
|
{
|
||||||
Subsidy *s;
|
Subsidy *s;
|
||||||
|
@ -921,8 +941,10 @@ static void SubsidyMonthlyHandler()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((_networking) && (!_networking_server)) return;
|
||||||
|
|
||||||
// 25% chance to go on
|
// 25% chance to go on
|
||||||
if (CHANCE16(1,4)) {
|
if (ICHANCE16(1,4)) {
|
||||||
// Find a free slot
|
// Find a free slot
|
||||||
s = _subsidies;
|
s = _subsidies;
|
||||||
while (s->cargo_type != 0xFF) {
|
while (s->cargo_type != 0xFF) {
|
||||||
|
@ -948,12 +970,13 @@ static void SubsidyMonthlyHandler()
|
||||||
if (!CheckSubsidyDuplicate(s)) {
|
if (!CheckSubsidyDuplicate(s)) {
|
||||||
s->age = 0;
|
s->age = 0;
|
||||||
pair = SetupSubsidyDecodeParam(s, 0);
|
pair = SetupSubsidyDecodeParam(s, 0);
|
||||||
|
if (_networking_server) NetworkSendEvent(NET_EVENT_SUBSIDY,sizeof(Subsidy),s);
|
||||||
AddNewsItem(STR_2030_SERVICE_SUBSIDY_OFFERED, NEWS_FLAGS(NM_NORMAL, NF_TILE, NT_SUBSIDIES, 0), pair.a, pair.b);
|
AddNewsItem(STR_2030_SERVICE_SUBSIDY_OFFERED, NEWS_FLAGS(NM_NORMAL, NF_TILE, NT_SUBSIDIES, 0), pair.a, pair.b);
|
||||||
modified = true;
|
modified = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} while (--n);
|
} while (n--);
|
||||||
}
|
}
|
||||||
no_add:;
|
no_add:;
|
||||||
if (modified)
|
if (modified)
|
||||||
|
|
|
@ -70,6 +70,7 @@ VARDEF Subsidy _subsidies[MAX_PLAYERS];
|
||||||
Pair SetupSubsidyDecodeParam(Subsidy *s, bool mode);
|
Pair SetupSubsidyDecodeParam(Subsidy *s, bool mode);
|
||||||
void DeleteSubsidyWithIndustry(byte index);
|
void DeleteSubsidyWithIndustry(byte index);
|
||||||
void DeleteSubsidyWithStation(byte index);
|
void DeleteSubsidyWithStation(byte index);
|
||||||
|
void RemoteSubsidyAdd(Subsidy *s_new);
|
||||||
|
|
||||||
int32 GetTransportedGoodsIncome(uint num_pieces, uint dist, byte transit_days, byte cargo_type);
|
int32 GetTransportedGoodsIncome(uint num_pieces, uint dist, byte transit_days, byte cargo_type);
|
||||||
uint MoveGoodsToStation(uint tile, int w, int h, int type, uint amount);
|
uint MoveGoodsToStation(uint tile, int w, int h, int type, uint amount);
|
||||||
|
|
|
@ -100,6 +100,8 @@ uint RandomRange(uint max);
|
||||||
void InitPlayerRandoms();
|
void InitPlayerRandoms();
|
||||||
|
|
||||||
uint32 InteractiveRandom(); /* Used for random sequences that are not the same on the other end of the multiplayer link */
|
uint32 InteractiveRandom(); /* Used for random sequences that are not the same on the other end of the multiplayer link */
|
||||||
|
uint InteractiveRandomRange(uint max);
|
||||||
|
|
||||||
void SetDate(uint date);
|
void SetDate(uint date);
|
||||||
/* facedraw.c */
|
/* facedraw.c */
|
||||||
void DrawPlayerFace(uint32 face, int color, int x, int y);
|
void DrawPlayerFace(uint32 face, int color, int x, int y);
|
||||||
|
@ -132,6 +134,7 @@ void NetworkListen();
|
||||||
void NetworkInitialize();
|
void NetworkInitialize();
|
||||||
void NetworkShutdown();
|
void NetworkShutdown();
|
||||||
void NetworkSendCommand(TileIndex tile, uint32 p1, uint32 p2, uint32 cmd, CommandCallback *callback);
|
void NetworkSendCommand(TileIndex tile, uint32 p1, uint32 p2, uint32 cmd, CommandCallback *callback);
|
||||||
|
void NetworkSendEvent(uint16 type, uint16 data_len, void * data);
|
||||||
void NetworkStartSync(bool fcreset);
|
void NetworkStartSync(bool fcreset);
|
||||||
void NetworkClose(bool client);
|
void NetworkClose(bool client);
|
||||||
void NetworkSendReadyPacket();
|
void NetworkSendReadyPacket();
|
||||||
|
|
1
macros.h
1
macros.h
|
@ -170,6 +170,7 @@ static INLINE int FindFirstBit2x64(int value)
|
||||||
|
|
||||||
|
|
||||||
#define CHANCE16(a,b) ((uint16)Random() <= (uint16)((65536 * a) / b))
|
#define CHANCE16(a,b) ((uint16)Random() <= (uint16)((65536 * a) / b))
|
||||||
|
#define ICHANCE16(a,b) ((uint16)InteractiveRandom() <= (uint16)((65536 * a) / b))
|
||||||
#define CHANCE16R(a,b,r) ((uint16)(r=Random()) <= (uint16)((65536 * a) / b))
|
#define CHANCE16R(a,b,r) ((uint16)(r=Random()) <= (uint16)((65536 * a) / b))
|
||||||
#define CHANCE16I(a,b,v) ((uint16)(v) <= (uint16)((65536 * a) / b))
|
#define CHANCE16I(a,b,v) ((uint16)(v) <= (uint16)((65536 * a) / b))
|
||||||
|
|
||||||
|
|
5
misc.c
5
misc.c
|
@ -44,6 +44,11 @@ uint32 InteractiveRandom()
|
||||||
return _random_seeds[1][1] = ROR(s, 3);
|
return _random_seeds[1][1] = ROR(s, 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint InteractiveRandomRange(uint max)
|
||||||
|
{
|
||||||
|
return (uint16)InteractiveRandom() * max >> 16;
|
||||||
|
}
|
||||||
|
|
||||||
void InitPlayerRandoms()
|
void InitPlayerRandoms()
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
49
network.c
49
network.c
|
@ -4,6 +4,7 @@
|
||||||
#include "command.h"
|
#include "command.h"
|
||||||
#include "player.h"
|
#include "player.h"
|
||||||
#include "console.h"
|
#include "console.h"
|
||||||
|
#include "economy.h"
|
||||||
|
|
||||||
#if defined(WIN32)
|
#if defined(WIN32)
|
||||||
# include <windows.h>
|
# include <windows.h>
|
||||||
|
@ -87,6 +88,7 @@ enum {
|
||||||
PACKET_TYPE_FSYNC,
|
PACKET_TYPE_FSYNC,
|
||||||
PACKET_TYPE_XMIT,
|
PACKET_TYPE_XMIT,
|
||||||
PACKET_TYPE_COMMAND,
|
PACKET_TYPE_COMMAND,
|
||||||
|
PACKET_TYPE_EVENT,
|
||||||
};
|
};
|
||||||
|
|
||||||
// sent from client -> server whenever the client wants to exec a command.
|
// sent from client -> server whenever the client wants to exec a command.
|
||||||
|
@ -102,6 +104,13 @@ typedef struct CommandPacket {
|
||||||
uint32 dp[8];
|
uint32 dp[8];
|
||||||
} CommandPacket;
|
} CommandPacket;
|
||||||
|
|
||||||
|
typedef struct EventPacket {
|
||||||
|
byte packet_length;
|
||||||
|
byte packet_type;
|
||||||
|
byte event_type;
|
||||||
|
byte data_start;
|
||||||
|
} EventPacket;
|
||||||
|
|
||||||
#define COMMAND_PACKET_BASE_SIZE (sizeof(CommandPacket) - 8 * sizeof(uint32))
|
#define COMMAND_PACKET_BASE_SIZE (sizeof(CommandPacket) - 8 * sizeof(uint32))
|
||||||
|
|
||||||
// sent from server -> client periodically to tell the client about the current tick in the server
|
// sent from server -> client periodically to tell the client about the current tick in the server
|
||||||
|
@ -343,9 +352,9 @@ static void QueueClear(CommandQueue *nq)
|
||||||
static int GetNextSyncFrame()
|
static int GetNextSyncFrame()
|
||||||
{
|
{
|
||||||
uint32 newframe;
|
uint32 newframe;
|
||||||
if (_frame_fsync_last == 0) return -1;
|
if (_frame_fsync_last == 0) return -5;
|
||||||
newframe = (_frame_fsync_last + 9);
|
newframe = (_frame_fsync_last + 16);
|
||||||
if ( (newframe + 4) > _frame_counter_max) return -1;
|
if ( (newframe + 4) > _frame_counter_max) return -5;
|
||||||
return (_frame_counter_max - newframe);
|
return (_frame_counter_max - newframe);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -367,7 +376,7 @@ void NetworkProcessCommands()
|
||||||
if (!(nq->head = qp->next)) nq->last = &nq->head;
|
if (!(nq->head = qp->next)) nq->last = &nq->head;
|
||||||
|
|
||||||
if (qp->frame < _frame_counter && _networking_sync) {
|
if (qp->frame < _frame_counter && _networking_sync) {
|
||||||
DEBUG(net,0) ("error: !qp->cp.frame < _frame_counter, %d < %d\n", qp->frame, _frame_counter);
|
DEBUG(net,0) ("warning: !qp->cp.frame < _frame_counter, %d < %d [%d]\n", qp->frame, _frame_counter, _frame_counter_srv+4);
|
||||||
}
|
}
|
||||||
|
|
||||||
// run the command
|
// run the command
|
||||||
|
@ -495,6 +504,25 @@ void NetworkSendCommand(TileIndex tile, uint32 p1, uint32 p2, uint32 cmd, Comman
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void NetworkSendEvent(uint16 type, uint16 data_len, void * data)
|
||||||
|
{
|
||||||
|
EventPacket * ep;
|
||||||
|
ClientState *cs;
|
||||||
|
|
||||||
|
// encode the event ... add its data
|
||||||
|
ep=malloc(data_len+sizeof(EventPacket)-1);
|
||||||
|
ep->event_type = type;
|
||||||
|
ep->packet_length = data_len+sizeof(EventPacket)-1;
|
||||||
|
ep->packet_type = PACKET_TYPE_EVENT;
|
||||||
|
memcpy(&ep->data_start,data,data_len);
|
||||||
|
|
||||||
|
// send it to the peers
|
||||||
|
for(cs=_clients; cs->socket != INVALID_SOCKET; cs++) if (!cs->inactive) SendBytes(cs, ep, ep->packet_length);
|
||||||
|
|
||||||
|
// free the temp packet
|
||||||
|
free(ep);
|
||||||
|
}
|
||||||
|
|
||||||
// client:
|
// client:
|
||||||
// server sends a command from another player that we should execute.
|
// server sends a command from another player that we should execute.
|
||||||
// put it in the command queue.
|
// put it in the command queue.
|
||||||
|
@ -572,6 +600,15 @@ static void HandleCommandPacket(ClientState *cs, CommandPacket *np)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void HandleEventPacket(EventPacket *ep)
|
||||||
|
{
|
||||||
|
switch (ep->event_type) {
|
||||||
|
case NET_EVENT_SUBSIDY:
|
||||||
|
RemoteSubsidyAdd((Subsidy *)&ep->data_start);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// sent from server -> client periodically to tell the client about the current tick in the server
|
// sent from server -> client periodically to tell the client about the current tick in the server
|
||||||
// and how far the client may progress.
|
// and how far the client may progress.
|
||||||
static void HandleSyncPacket(SyncPacket *sp)
|
static void HandleSyncPacket(SyncPacket *sp)
|
||||||
|
@ -785,6 +822,9 @@ static bool ReadPackets(ClientState *cs)
|
||||||
case PACKET_TYPE_READY:
|
case PACKET_TYPE_READY:
|
||||||
HandleReadyPacket((ReadyPacket*)packet, cs);
|
HandleReadyPacket((ReadyPacket*)packet, cs);
|
||||||
break;
|
break;
|
||||||
|
case PACKET_TYPE_EVENT:
|
||||||
|
HandleEventPacket((EventPacket*)packet);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
DEBUG (net,0) ("net: unknown packet type");
|
DEBUG (net,0) ("net: unknown packet type");
|
||||||
}
|
}
|
||||||
|
@ -1907,6 +1947,7 @@ void NetworkConnect(const char *hostname, int port) {}
|
||||||
void NetworkReceive() {}
|
void NetworkReceive() {}
|
||||||
void NetworkSend() {}
|
void NetworkSend() {}
|
||||||
void NetworkSendCommand(TileIndex tile, uint32 p1, uint32 p2, uint32 cmd, CommandCallback *callback) {}
|
void NetworkSendCommand(TileIndex tile, uint32 p1, uint32 p2, uint32 cmd, CommandCallback *callback) {}
|
||||||
|
void NetworkSendEvent(uint16 type, uint16 data_len, void * data) {};
|
||||||
void NetworkProcessCommands() {}
|
void NetworkProcessCommands() {}
|
||||||
void NetworkStartSync(bool fcreset) {}
|
void NetworkStartSync(bool fcreset) {}
|
||||||
void NetworkSendReadyPacket() {}
|
void NetworkSendReadyPacket() {}
|
||||||
|
|
|
@ -24,6 +24,10 @@ typedef struct NetworkGameList {
|
||||||
struct NetworkGameList * _next;
|
struct NetworkGameList * _next;
|
||||||
} NetworkGameList;
|
} NetworkGameList;
|
||||||
|
|
||||||
|
enum {
|
||||||
|
NET_EVENT_SUBSIDY = 0,
|
||||||
|
};
|
||||||
|
|
||||||
NetworkGameInfo _network_game;
|
NetworkGameInfo _network_game;
|
||||||
NetworkGameList * _network_game_list;
|
NetworkGameList * _network_game_list;
|
||||||
|
|
||||||
|
|
2
ttd.c
2
ttd.c
|
@ -889,7 +889,7 @@ void StateGameLoop()
|
||||||
// store the random seed to be able to detect out of sync errors
|
// store the random seed to be able to detect out of sync errors
|
||||||
_sync_seed_1 = _random_seeds[0][0];
|
_sync_seed_1 = _random_seeds[0][0];
|
||||||
_sync_seed_2 = _random_seeds[0][1];
|
_sync_seed_2 = _random_seeds[0][1];
|
||||||
if (_networking) disable_computer=true;
|
if (_networking) disable_computer=true;
|
||||||
|
|
||||||
if (_savedump_path[0] && (uint)_frame_counter >= _savedump_first && (uint)(_frame_counter -_savedump_first) % _savedump_freq == 0 ) {
|
if (_savedump_path[0] && (uint)_frame_counter >= _savedump_first && (uint)(_frame_counter -_savedump_first) % _savedump_freq == 0 ) {
|
||||||
char buf[100];
|
char buf[100];
|
||||||
|
|
Loading…
Reference in New Issue