What do i need to create a CLI game? Any useful resources? - command-line

So have spent some time, and have decided to make a small game as a sideproject while I'm in school.
I'd like to make a command line game, perhaps some kind of rpg or mud.
My question is, what do I need to make this a reality?
I've looked at ncurses, and have been reading some documentation, is this a necessary step, or is there something easier? Are there any other particular technologies I will need compared to a regular command line application I might make it school?
Thanks.

You need two things:
A game engine
An interface
This is the exact same thing you need for a GUI game. The only only ONLY differences are your input and output mechanism.
So, write your game engine, make sure it's adaptable, and then your command line interface to control that engine.
========= Edit in regards to comments: =========
The goal of any interface is to map user requests to engine requests. Without knowing what language you're in, the specifics are going to be a bit... well ... nonspecific.
I can tell you how I would do it in Java.
I would create a UserRequest class with the following basic characteristics:
abstract class UserRequest {
protected GameEngine engine;
protected String command;
protected int numArgs;
public UserRequest(GameEngine engine) {
this.engine = engine;
this.command= command;
this.numArgs= numArgs;
}
public abstract void callback(User user, String[] args);
protected void checkArgs(String[] args) {
if(args == null || args.length != numArgs) {
throw new IllegalArgumentException("your args suck...");
}
if(!args[0].equals(command)) throw new IllegalArgumentException("commands don't match");
}
}
In my interface, I would have a Map<String,UserRequest> that is populated like this:
Map<String,UserRequest> behaviors = new HashMap<String,UserRequest>();
behaviors.add("MOVE",new UserRequest(engine,"MOVE",2) {
// define the engine callback
public void callback(User user, String[] args) {
// assume args[0] is command
int x = Integer.parseInt(args[1]);
int y = Integer.parseInt(args[2]);
engine.move(user,x,y);
}
}
public void repl() {
while(true) {
// assume you have a form of input - scanner perhaps?
String inputline = acquireNextInputLine();
String[] tokens = inputline.split("\\s"); // default split on white space
UserRequest behavior = behavior.get(tokens[0]);
if(tokens == null) displayError(inputLine);
try { behavior.callback(currentUser,tokens); }
catch(Exception e) displayError(e); // assume you have better error reporting than this!
}
}

Related

OOP avoid unnecessary repeated calls

so I have a question on OOP class design. I have read that we should "Tell, don't ask" and not use Exceptions for "Flow control". However in this particular case I see some redundant code being executed!
Lets assume Person have a list of events that he will be attending, and it must be enforced that he cannot attend an event that overlaps with his current schedule. So I have the following Java code
public class Person {
// this arraylist of events must not have overlapping events!
ArrayList<Events> eventsToAttend;
// checks if a person is free to attend a new event by viewing all events he is attending
public boolean canAttendEvent(Event newEvent) {
for(int i = 0; i < eventsToAttend.size(); i++) {
if (newEvent.isSameDayAndTime(eventsToAttend.get(i))) {
return false;
}
}
return true;
}
public void attendEvent(Event newEvent) {
// enforce the validity of the newEvent
if (!canAttendEvent(newEvent)) {
// throw exception and return
}
eventsToAttend.add(newEvent);
}
public static main(String[] args) {
// just an example usage!
Person person = somePersonWithEventsAlready;
Event event = new Event();
if (person.canAttendEvent(event)) {
// !!!
// Notice that canAttendEvent() is called twice!! how do you prevent this?
// !!!
person.attendEvent(event);
}
// Alternatively I could just try - catch around person.attendEvent(), but is that bad practise?
}
}
The issue I am facing in general with this way of doing things, is that "canAttendEvent()" is being called twice. However it is good practice according to OOP design patterns?
What would be a better way to do something like this? Thank you for reading this.
try - catch in the main is the best way to achieve what you are trying to avoid: call twice the function canAttendEvent

Bukkit How to change an int in the config file then be able to change it again without reloading (Custom config file class.))

Okay so I am making a custom feature for my OP-Prison server, one of the things that I need to do is get an integer from the players.yml file, check if it is >= one, if it is take away one, save it and then if it is still above one then they can repeat the action untill it's 0.
The issue comes with the fact that I have to restart the server for the file to change, and even when I do, it will only go down by one integer at a time, before having to reload it again.
GUI Creation code:
Main main = Main.getPlugin(Main.class);
#SuppressWarnings("unused")
private FileControl fc;
#SuppressWarnings("unused")
private FileControl playerfc;
public static String inventoryname = Utils.chat(Main.pl.getFileControl().getConfig().getString("Backpacks.White.InventoryName"));
public List<Player> WhiteOpened = new ArrayList<>();
public static Inventory whiteBackpack(Player player) {
Inventory whiteBackpack = Bukkit.createInventory(null, 27, (inventoryname));
UUID uuid = player.getUniqueId();
whiteBackpack.setItem(10,
new ItemCreator(Material.INK_SACK).setData(8)
.setDisplayname(Utils.chat("&fCommon Packages &8» &f&l" + Main.pl.getPlayerFile().getConfig().getInt("Users." + uuid + ".Packages.Common")))
.getItem());
return whiteBackpack;
}
Code for updating the config + item when the Commonpackage is clicked:
#EventHandler
public void whiteBackpackInteract(InventoryClickEvent event) {
Player player = (Player) event.getWhoClicked();
UUID uuid = player.getUniqueId();
ItemStack clicked = event.getCurrentItem();
String title = event.getInventory().getName();
if (title.equals(inventoryname)) {
// Making it so that the item cannot be moved
event.setCancelled(true);
if (clicked != null) {
if (event.getSlot() == 10) {
// Getting the user's common packages section in the config and checking if it is greater than or equal to 1.
if (Main.pl.getPlayerFile().getConfig().getInt("Users." + uuid + ".Packages.Common") >= 1) {
// Saving the user's common package section to 'currentCommon'
Integer currentCommon = Main.pl.getPlayerFile().getConfig().getInt("Users." + uuid + ".Packages.Common");
// Taking away one from 'currentCommon' and saving it to 'newCommon'
Integer newCommon = currentCommon - 1;
// Getting the 'players.yml' file
File file = new File(main.getDataFolder(), "players.yml");
FileConfiguration config = YamlConfiguration.loadConfiguration(file);
// Checking if the current common keys is greater than or equal to 1
if (currentCommon >= 1) {
try {
//Now, Here's where the error lies.
//Gets the player's common package count and sets it to the 'newCommon' count
config.set("Users." + uuid + ".Packages.Common", newCommon);
//Saves the players.yml file
config.save(file);
} catch (IOException e) {
e.printStackTrace();
}
// Updates the inventory they're currently in (Atleast it's meant to...)
player.updateInventory();
// Sends them a message (This is just for testing purposes, making sure it's working.)
player.sendMessage(Utils.chat("&8(&9Vexil&8) &fCommon Package"));
}
}
}
}
}
}
If there is any other code that you need, just ask I'll happily provide it for you.
Right now, you need to restart the server for it to save the data to the file. This should not happen, since you are calling the method config.save(file). The following is simply speculation, but it's the only cause that I think can easily explain what is going on.
In the object that is returned by getPlayerFile().getConfig(), there is likely a variable that stores a FileConfiguration object. That variable houses all the data from the players.yml file. In your whiteBackpackInteract() method, you load the data all over again. You then continue on to write to this NEW FileConfiguration variable, rather than the one that is stored in getPlayerfile().getConfig(). Since you then proceed to save to the file directly, the variables stored in the getPlayerfile().getConfig() is never told that you changed some values around. To fix this, you need to change the following:
config.set("Users." + uuid + ".Packages.Common", newCommon);
config.save(file);
to this:
Main.pl.getPlayerFile().getConfig().set("Users." + uuid + ".Packages.Common", newCommon);
Main.pl.getPlayerFile().getConfig().save(file);
and then delete this line of code:
FileConfiguration config = YamlConfiguration.loadConfiguration(file);
This should solve your problem entirely. If it does not, I would recommend not using your friend's custom config API and instead just use the ones that are built in. Using third party code that you don't properly understand can very often lead to problems such as this.
The following are not the bugs, but are suggestions to help improve your code:
You should be sure to put your comments ABOVE or to the RIGHT over the code they describe. People read from top to bottom, so the comments (before I made the suggested edit to your post) were all below the code they describe.
Typically, you want to try to make sure that if code doesn't need to be run, it isn't. Since the int newCommon is not used until inside that if statement, you should move it in there.
You are using Main.getPlugin();
Now while that doesn't seem like such a bad thing, your getting an unassigned variable, I have no idea how it is working but you're assigning Main to Main. There are 2 proper ways to actually get the main class.
The first, and generally best way, is to use dependency injection.
So basically,
public class Main extends JavaPlugin {
#Override
public void onEnable() {
BackpackListener listener new Backpacklistener(this);
getServer().getPluginManager().registerEvents(listener, this);
}
}
public class BackpackListener implements Listener {
private Main instance;
private BackpackUtil util;
public BackpackListener(Main instance) {
this.instance = instance;
util = new BackpackUtil();
}
#EventHandler
public void onClick(InventoryClickEvent event) {
//code
util.whiteBackpack(instance);
}
public class BackpackUtil {
public Inventory whiteBackpack(Main instance) {
FileConfiguration config = instance.getConfig();
//Do things
instance.saveConfig();
}
}
The next way you can do it is less optimal, and frowned upon, but still an easier option.
public class Main() {
public static Main instance;
#Override
public void onEnable() {
instance = this;
}
}
public class ConfigHelper() {
Main instance = Main.instance;
FileConfiguration config = instance.getConfig();
//Do things
instance.saveConfig();
}
It's good to get out of the habit of using the second method (It's called a singleton), because normally the main class will change, or have multiple instances, etc... but with Spigot there can only be one main instance and one thread.

Keeping Unity networking code separate from game logic

I want to keep network code separate from my game logic. Not only do I need to do that to be able to share game logic between single and multiplayer game modes, I also want it because of the Separation Of Concerns thing.
My current approach is to generate the code for my network related classes in such a way that there is an online and an offline version. I do this using T4 templates.
The resulting classes look like this:
Standalone/Singleplayer version:
// T4 GENERATED CODE
// Head (Singleplayer version)
class StandaloneHelloWorld : MonoBehaviour, IHelloWorld
{
private string name;
public void SayHello()
{
SayHelloInternal();
}
// Body
public string Name
{
get { return name; }
set { name = value; }
}
void SayHelloInternal()
{
Debug.Log(Name + ": Hello World");
}
}
Multiplayer version:
// T4 GENERATED CODE
// Head (Multiplayer version)
class NetworkedHelloWorld : NetworkBehaviour, IHelloWorld
{
[SyncVar]
private string name;
public void SayHello()
{
CmdSayHello();
}
[Command]
void CmdSayHello()
{
RpcSayHello();
}
[ClientRpc]
void RpcSayHello()
{
SayHelloInternal();
}
// Body
public string Name
{
get { return name; }
set { name = value; }
}
void SayHelloInternal()
{
Debug.Log(Name + ": Hello World");
}
}
They both share an interface to hide the implementation from the callers:
interface IHelloWorld
{
string Name { get; set; }
void SayHello();
}
So as you can see, both implementations use the same body, sharing most of the code, while the entry points depend on the implementation being networked or not. Also note that the two implementations inherit different base classes.
Advantages:
Singleplayer code has no dependencies towards networked code and vice versa
No duplicate code (none that has to be maintained manually at least)
Disadvantages:
Support for interfaces in Unity is limited. I would not be able to reference scene instances of IHelloWorld from inside the Editor.
Having to maintain separate Prefabs for singleplayer/multiplayer game modes
Having to meddle with T4/code generation
Do you know of better ways to deal with this? How did you solve this problem?
You could structure the code in an event-based fashion. This will allow systems to register to events they're interested in. This naturally separates the logic from the network code.
As an example, let's say you want to fire a projectile.
You can fire it by calling:
new Event(EventType.FireProjectile, pos, dir, template)
You can then register systems that are interested in this event:
CollisionSystem.Register(EventType.FireProjectile, (e) => {
CollisionSystem.AddCollider(e.template.bounds);
});
AudioSystem.Register(EventType.FireProjectile, (e) => {
AudioSystem.PlaySound("Woosh");
});
AISystem.Register(EventType.FireProjectile, (e) => {
AISystem.AlertAtPosition(e.pos);
});
What's cool is next you can register this event to the NetworkSystem that will serialize it, move it across the net, deserialize it, and fire it off on the client's machine. So as far as the client is concerned this event was called locally.
NetworkSystem.Register(EventType.FireProjectile, (e) => {
NetworkSystem.Broadcast(e, Channel.Reliable);
});
This is pretty great, except that you'll soon realize that this will cause an infinite loop of events. As you send a FireProjectile event to the other client, they catch it and fire it. Instantly their NetworkSystem catches it and fires it over the net.
To fix this you need two events for every action – a request: FireProjectile, and response: ProjectileFired.
I've worked with a codebase like this for a personal project a while ago. It's in C++, but if you're interested you can read more here. Notice how the server and the client are registering to certain events, which they will forward across.

Actionscript in a single class or in multiple scenes?

I am completely new to Actionscript and Adobe Flash CS6 and for a little bit of fun I have decided to try and make a little game. I had a few newbie (or noob-y) questions to ask about a general implementation approach.
The documentation I've been reading so far suggests creating a new flash project, and then create a document class so:
package {
import flash.display.MovieClip;
public class MyMainClass extends MovieClip {
public function MyMainClass() {
}
}
}
and I am wondering if I use this MainClass to code the whole game or include actionscript within a scene and have multiple scenes, or some combination of both.
Lets say I had a wanted 5 Levels in my game, would I do something like:
package {
import flash.display.MovieClip;
public class MyMainClass extends MovieClip {
public function MyMainClass() {
StartLevel1();
StartLevel2();
StartLevel3();
StartLevel4();
StartLevel5();
}
public function StartLevel1() {
// Do something
}
public function StartLevel2() {
// Do something
}
public function StartLevel3() {
// Do something
}
public function StartLevel4() {
// Do something
}
public function StartLevel5() {
// Do something
}
}
}
or create 5 scenes with actionscript in each scene?
Can anyone provide me with a bit of a starting point?
Thanks
I don't know of anyone who has anything good to say about scenes.
However, as you intuit, the timeline itself is a wonderful tool for managing the state of your Flash assets over time. If you use it, you also get the hidden advantage that you don't have to download 100% of your file to be able to use it (so you can reduce or even eliminate the need for a preloader by unchecking "Export in frame N" on your library symbols.
Lars has quite rightly pointed out that there are very few developers who understand this technique, and I know of exactly one who can and will help people who are interested in exploring this technique. That person is helping you right now. So if you choose to go that way, keep in mind you are mostly on your own except if I happen to notice your post and respond to it.
I am not in favor of timeline scripts, with a very few exceptions. What I suggest is a "both and" approach, where you use a Document Class to control timeline instances.
Your document Class might look something like this:
public class Game extends MovieClip {
protected var _level:ILevel;//Interface your Level MovieClips will implement
protected var levelController:LevelController = new LevelControler();
protected var currentLevel:int;
protected var maxLevels:int = 5;
public function Game() {
levelController.addEventListener(LevelEventKind.LEVEL_COMPLETE, nextLevel);
levelController.addEventListener(LevelEventKind.LEVEL_FAILED, gameOver);
startLevel(currentLevel);
}
public function startLevel(levelNumber:int):void {
goToLabel('Level' + String(levelNumber));
}
public function get level():ILevel {
return _level;
}
public function set level(value:ILevel):void {
_level = value;
//internally, this should release all listeners to the last
//level object (if any) so you don't get a memory leak
levelController.level = _level;
}
protected function nextLevel(e:Event):void {
if (currentLevel < maxLevels) {
startLevel(++currentLevel);
} else {
//do you won logic here
}
}
protected function gameOver(e:Event):void {
//do bombed out logic here
}
protected function goToLabel(label:String):void {
for each (var frameLabel:FrameLabel in currentLabels) {
if (frameLabel.name==label) {
//if your swf is media-heavy, may want to check that frame
//is loaded if you chose to reduce/eliminate preloader
goToAndStop(label);
return;
}
}
trace('no such label as', label);
}
}
What this gets you is a game where you can change how the different levels look without changing a single line of ActionScript, and you can change how they work by assigning different Base Classes that implement ILevel slightly differently. You can also change your functionality by swapping out different flavors of LevelController, but your Main Document Class (Game in this instance) would be aware of this change (wheras the other changes could be made without altering Game at all).

How to resolve generic type at runtime

I'm trying to build a command processor that can take any command that implements a marker interface (or maybe descends from a base class). The processor will handle the command that it is asked to process. However I'm struggling with resolving the true generic type as Resolve(Type) returns an object.
I'm not sure is how to cast this if at all possible?
public void Process(ICommand command)
{
var c = command.GetType();
var t = typeof(ICommandHandler<>).MakeGenericType(new[] { c });
var o = container.Resolve(t);
//((ICommandHandler)o).Handle(command); *** This doesn't work
}
The calling code would be something like this -
Dispatcher.Process(new SomeCommand(Guid.NewGuid(),"Param1",12345));
If you absolutely have to call the ICommandHandler<T>.Handle method and you have no other control over the design of the system, then reflection may be your only choice. There's no great way to deal with the switch from generic to non-generic.
Otherwise, you may have a couple of options.
First, if your Dispatcher.Process can be made generic, you can save all the casting.
public static class Dispatcher
{
public static void Process<T>(T command) where T : ICommand
{
var handler = container.Resolve<ICommandHandler<T>>();
handler.Handle(command);
}
}
This is a pretty common solution to a problem like this that I've seen out in the wild.
If you can't do that, then you may be able to make your ICommandHandler<T> interface implement a non-generic ICommandHandler base interface.
public interface ICommandHandler
{
void Handle(ICommand command);
}
public interface ICommandHandler<T> : ICommandHandler
{
void Handle(T command);
}
In this latter case you'd have to switch your strongly-typed command handler implementations to call the same internal logic for generic or basic handling or you'll get different handling based on the call, which would be bad:
public class SomeCommandHandler : ICommandHandler<SomeCommand>
{
public void Handle(ICommand command)
{
var castCommand = command as SomeCommand;
if(castCommand == null)
{
throw new NotSupportedException("Wrong command type.");
}
// Hand off to the strongly-typed version.
this.Handle(castCommand);
}
public void Handle(SomeCommand command)
{
// Here's the actual handling logic.
}
}
Then when you resolve the strongly-typed ICommandHandler<T> your cast down to ICommandHandler (as shown in your question's sample code) will work.
This is also a pretty common solution, but I've seen it more in systems that existed before generics were available where an updated API was being added.
However, in all cases here, the problem really isn't that Autofac is returning an object; it's a class/type design problem that affects any generic-to-non-generic conversion scenario.
Using Reflection - but is this the best way to approach this?
public void Process(Command command)
{
var c = command.GetType();
var ot = typeof(ICommandHandler<>);
var type = ot.MakeGenericType(new[] { c });
var mi = type.GetMethod("Handle");
var o = container.Resolve(type);
mi.Invoke(o, new object[] { command });
}