Exemple #1
0
        public ServerMiddleware(Store <PlayerData> store, IStoreService client, StoreLocalPersister persister)
        {
            _store          = store;
            _persistedStore = new Store <PlayerData>(store.State, store.Modifiers);
            _client         = client;
            _persister      = persister;
            _hasher         = SHA256.Create();
            _channel        = Channel.CreateUnbounded <ActionEvent>(new UnboundedChannelOptions()
            {
                SingleReader = true, SingleWriter = true
            });
            _nextId = 0;

            Task.Run(async() =>
            {
                while (await _channel.Reader.WaitToReadAsync())
                {
                    while (_channel.Reader.TryRead(out var e))
                    {
                        // TODO: handle timeout if no server response.
                        var response = await _client.SendEvent(e);
                        if (response.Id == e.Id)
                        {
                            switch (response.Status)
                            {
                            case EventStatus.Accepted:
                                // persist to local storage.
                                _persistedStore.Update(e.Action);
                                _persister.Set <PlayerData>("player", _persistedStore.State);
                                _persister.Save();
                                break;

                            case EventStatus.Rejected:
                                // discard remaining transactions in channel and revert to last valid store state.

                                break;

                            case EventStatus.Resend:
                                // resend last event.
                                break;

                            default:
                                break;
                            }
                        }
                        else
                        {
                            Console.WriteLine("Invalid Id = " + response.Id);
                        }
                    }
                }
            });
        }
Exemple #2
0
        static async Task Main(string[] args)
        {
            MagicOnion.MagicOnionInitializer.Register();
            RegisterResolvers();
            // var channel = new Channel("35.228.244.163", 80, ChannelCredentials.Insecure); // gcp load balancer external ip and port.
            var channel = new Channel("0.0.0.0", 8080, ChannelCredentials.Insecure); // local dev server.
            var client  = MagicOnionClient.Create <IStoreService>(channel);

            const int kDefaultStartCoins = 5000;
            var       gameConfig         = new GameConfig();
            var       configProvider     = new ConfigProvider();

            configProvider.Add("default", gameConfig);

            var store = new Store <Models.PlayerData>();

            var config = new StoreLocalPersister.Config {
                FilePath = "LocalData/Player.txt", TextFormat = true
            };
            var persister = new StoreLocalPersister(config);

            var server  = new ServerMiddleware(store, client, persister);
            var history = new HistoryMiddleware();

            store.AddMiddlewares(server, history);

            var guest = new GuestModifierProvider(new GuestModifierFactory(configProvider));

            var modifiers = new List <Modifier <Models.PlayerData> >();

            modifiers.AddRange(Currency.Modifiers);
            modifiers.AddRange(Inventory.Modifiers);
            modifiers.AddRange(Hotel.Modifiers);
            modifiers.AddRange(guest.Modifiers);
            store.AddModifiers(modifiers.ToArray());

            // store.Select().Subscribe(x => Console.WriteLine(x));
            store.Select(x => x.Stats.Coins).Subscribe(x => Console.WriteLine("Coins: " + x));
            store.Select(x => x.Inventory.Items).Subscribe(x => Console.WriteLine("Decos: " + (x == null ? "Empty" : x.Sum(x => x.Value.Count).ToString())));
            // store.Select(x => x.Hotel.Rooms).Subscribe(x => x.ForEach(r => Console.WriteLine($"Room[{r.TypeId}] => Level {r.Level}")));
            store.Select(x => x.Hotel.Rooms).Subscribe(x =>
            {
                if (x == null)
                {
                    Console.WriteLine("Rooms: Empty");
                }
                else
                {
                    x.ForEach(r => Console.WriteLine($"Room[{r.TypeId}] => Level {r.Level}"));
                }
            });

            store.Update(new NewGameAction {
                StartCoins = kDefaultStartCoins
            });

            var app = new Game(store);

            app.Command("newgame", config =>
            {
                var coins = config.Option("--coins", "Starting coins", CommandOptionType.SingleValue);

                config.OnExecute(() =>
                {
                    if (!int.TryParse(coins.Value(), out int val))
                    {
                        val = kDefaultStartCoins;
                    }

                    store.Update(new NewGameAction {
                        StartCoins = val
                    });
                });
            });

            app.Command("buy", config =>
            {
                var typeIdArg = config.Argument("TypeId", "Item TypeId");
                var costArg   = config.Argument("Cost", "Item Cost");

                config.OnExecute(() =>
                {
                    int.TryParse(typeIdArg.Value, out int typeId);
                    int.TryParse(costArg.Value, out int cost);
                    store.Update(new BuyDecoAction {
                        TypeId = typeId, Cost = cost
                    });
                });
            });

            app.Command("room", config =>
            {
                config.Command("up", sub =>
                {
                    const int kUpgradeRoomCost = 100;
                    var typeIdArg = sub.Argument("TypeId", "Item TypeId");

                    sub.OnExecute(() =>
                    {
                        int.TryParse(typeIdArg.Value, out int typeId);
                        store.Update(new UpgradeRoomAction {
                            TypeId = typeId, Cost = kUpgradeRoomCost
                        });
                    });
                });
            });

            app.AddCommand <int, int>("guest", "cin", (guestId, roomId) => new GuestCheckinAction {
                GuestTypeId = guestId, RoomTypeId = roomId
            });
            app.AddCommand <int>("guest", "cout", (guestId) => new GuestCheckoutAction {
                GuestTypeId = guestId
            });
            app.AddCommand("hotel", "status", () => ShowHotelStatus(store));

            app.AddAsyncCommand("sync", "new", async() =>
            {
                var t = new ActionEvent
                {
                    Id     = 1,
                    Hash   = "abc",
                    Action = new NewGameAction {
                        StartCoins = 250
                    }
                };

                var result = await client.SendEvent(t);
                Console.WriteLine("sync result = " + result);
            });

            app.AddCommand("sync", "test", () =>
            {
                var t = new ActionEvent
                {
                    Id     = 1,
                    Hash   = "abc",
                    Action = new NewGameAction {
                        StartCoins = 250
                    }
                };

                var bytes   = MessagePackSerializer.Serialize(t);
                var json    = MessagePackSerializer.ToJson(bytes);
                var result  = MessagePackSerializer.Deserialize <ActionEvent>(bytes);
                var newGame = result.Action as NewGameAction;
                Console.WriteLine("sync result = " + json + " => " + result.ToString());
            });

            app.AddCommand("data", "save", () =>
            {
                persister.Set <Models.PlayerData>("player", store.State);
                persister.Save();
            });
            app.AddCommand("data", "load", () =>
            {
                persister.Load();
                persister.Get <Models.PlayerData>("player", out var player);
                store.Update(new LoadGameAction {
                    State = player
                });
            });

            app.Command("timer", config =>
            {
                config.OnExecute(() =>
                {
                    var start = DateTime.Now;
                    var prev  = start;
                    Console.Write("Timer: " + 0);
                    Console.CursorVisible = false;
                    while (!Console.KeyAvailable)
                    {
                        var now   = DateTime.Now;
                        double dt = (now - prev).TotalSeconds;
                        if (dt >= 1.0)
                        {
                            prev = now;
                            Console.SetCursorPosition(0, Console.CursorTop);
                            Console.Write("Timer: " + (int)(now - start).TotalSeconds);
                        }
                    }
                    Console.ReadKey(true);
                    Console.WriteLine();
                });
            });

            while (true)
            {
                var command = Prompt.GetString("Command", "#");
                if (command == "bye")
                {
                    Console.WriteLine("bye!");
                    break;
                }

                var tokens = command.Split(" ");

                try
                {
                    await app.ExecuteAsync(tokens);
                }
                catch (Exception e)
                {
                    Console.WriteLine($"{e.GetType()}: {e.Message}");
                    Console.WriteLine(e.StackTrace);
                }
            }
        }