Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Please give some information on your develpment process #328

Closed
queueseven opened this issue Jul 5, 2015 · 42 comments
Closed

Please give some information on your develpment process #328

queueseven opened this issue Jul 5, 2015 · 42 comments

Comments

@queueseven
Copy link
Collaborator

While not an issue with the game, it would be cool to have some insight on how you actually develop the game, like

  • what tools do you use
  • how you do debug
  • how you do test
  • what components of the game do what

etc.

Also, some docstrings in the source would also help.

This would make it easier for people who want to join development of this game.

Maybe create a wiki page or something like that, where other people could also share their experience (I could write an essay of the PITA it was to get this game running on windows 8 with VS2013).

@nealterrell
Copy link
Collaborator

You're right about this. It's not a solution, but here are a few of my notes to get you started. @mtgred can probably throw some more details notes here, as I still feel rather unsure with my development process.

  • On Windows 8.1, I use IntelliJ IDEA with a plugin called Cursive for development. I recommend it.

  • Debugging is difficult for me, really only through console or chat log printouts. (system-msg) is one function for printing to the game's chat log; you pass it state and a side (:runner, :corp, or side if that binding is available depending on where you area), then a string message, and it will print to the chatlog. The downside here is that the action must complete and send the new game state to the client for you to see your printouts, so you can't use it (for example) to find out where you are throwing in the middle of a large function.

    Clojure's print has weird behaviors from what I've experienced; it often won't show to the console UNTIL an exception is thrown. Using System.out.println from Java is probably the most flexible; use it as (.println System/out (str "append strings and variable values here")).

  • Testing is difficult. I don't have a good answer here. For individual cards I test as many interactions as I can think of, using two browsers on my test machine. For large system changes I do more thorough testing, sometimes putting my dev server behind a reverse proxy to let other trusted users test the system on my codebase.

  • Obviously this needs a much more thorough answer, but generally... anything in /src/clj/game is game server code for implementing the game's logic. There is also some logic for communication with the web server. Anything in /src/cljs/netrunner is ClojureScript which cross-compiles to JavaScript and involves the web server. Most of the code there is for displaying the game (or deckbuilder, chat, and other parts of the UI). There is also some code for managing the communication with the game server.

@queueseven
Copy link
Collaborator Author

Thanks. I also ask because I have only limited experience with clojure.

I wrote a markdown parser some years ago (using Netbeans), but development was easy since I wrote unit tests and did the development mostly in the REPL.

Now I just set breakpoints and use the Evaluate Expression feature of Cursive, but it's a bit cumbersome. When you're a VS user, you're totally spoilet; like attach to running processes, break on execptions, change code while running, debug backward etc. Don't know if such features exists in Intellij/Cursive.

I also startet to code a Netrunner implementation in C# some time ago, but didn't work on it lately.

@mtgred
Copy link
Owner

mtgred commented Jul 6, 2015

  1. The preferred way to develop is to use a Clojure REPL and launch the game server with (future-call dev) in the REPL. When you modify a function or a card, simply reload the function or the cards.clj file to the REPL and it should be reflected in the game engine without having to recreate a new game. For cards already installed you have to drag it back to hand and install it again to reflect the new code. No need to refresh the browser, you can keep the game state.
  2. My dev setup is Emacs on Mac OS but Cursive is a good option too. If you want to use Emacs you have to install clojure-mode and cider. Cider allows you to connect Emacs to a REPL with C-c M-j. To reload a function, it's C-c C-c with the cursor inside the function definition. To reload a file (eg. card.clj) it's C-c C-k.
  3. To inspect the content of clojure data structure, prn is handy. You can add prn in your functions or inside (req ) macro in card definitions you want to inspect.
  4. When there is an exception, the game server might hang. It sucks and you have to kill the REPL, relaunch a game server and recreate and setup a game. If there is another solution, I'm interested to learn!
  5. To modify the client side, Figwheel is super awesome. Run lein figwheel and stylus -w src/css -o resources/public/css/. When you save a cljs or styl file, the Clojurescript or Stylus are automatically compiled and sent to the connected browsers. No need to refresh anything, you keep the game state. When you have an error in a cljs file, the UI might disappear. Don't panic! As soon as the error is corrected the UI will reappear. No need to reload anything.

@nealterrell
Copy link
Collaborator

OK, I wish I'd asked this when I got started. Launching the server in REPL is amazing. 👍

@queueseven
Copy link
Collaborator Author

Awesome! Thank you! 👍

Maybe consider creating a wiki page, as this are really helpful tips and should not be getting burried here.

@JoelCFC25
Copy link
Collaborator

Excellent information that will help me a ton. I got IntelliJ and Cursive installed on my MacBook Air last night, so hopefully in the coming days I can play around with this and get the hang of it. I installed Emacs too but for some reason got stuck trying to install the cider package.

@queueseven
Copy link
Collaborator Author

I took the liberty to create a WikiPage myself.

I will try to populate it with the data in this issue.

@JoelCFC25
Copy link
Collaborator

OK, last night I got as far as opening my netrunner/ directory in IntelliJ and actually getting the REPL running after a couple attempts. At first the middle option "Run nREPL with Leiningen" was greyed out and I couldn't choose it--the missing piece was the need to right-click project.clj and choose "Add as Leiningen project".

I still need to configure Apache so that my netrunner/ directory is visible when hitting localhost in my browser...I think that should be pretty straightforward with some Googling. After that, if I'm reading between the lines correctly, I can just make edits directly to cards.clj and reload it in the REPL without recompiling anything? And I just test cards and behaviors in my browser and keep an eye on the REPL window in IntelliJ for errors?

@queueseven
Copy link
Collaborator Author

I was able to run the Server in a REPL, but reloadi g files didnt work. Well, I could reload them but it wasnt reflected in the game (e.g. I changed Sure Gamble to give 100c, but that didnt work until restarting the Server)

Maybe I'm missing something?

@JoelCFC25 why do you need to run Apache?

@JoelCFC25
Copy link
Collaborator

Don't I? I assumed I would need a web server running in order to hit the game server with my browser to fire up games and test card implementations. It's very possible that I'm misunderstanding something about what the REPL can do--I'm very inexperienced in this arena.

If I try implementing a card or changing an existing one, how do I then test it?

@queueseven
Copy link
Collaborator Author

You have to start the game server, then start the Node server with coffee server.coffee. It will open a port in your machine which you then can connect to (See its console output to see which port it opened)

@JoelCFC25
Copy link
Collaborator

OK, thanks. That was the part I had missed. I got things going briefly before I had to stop and get some sleep last night, but I did actually make some code changes and saw them represented in test games, so that's major progress.

coffee server.coffee
In IntelliJ: start the REPL, then (future-call dev)

I had (wrongly?) used the java -jar target/netrunner-0.1.0-SNAPSHOT-standalone.jar from a terminal.

@nealterrell
Copy link
Collaborator

java -jar... is basically the equivalent of starting a REPL with future-call dev: it starts the game logic server. coffee server.coffee is the web server. Together, they are unstoppable!

@queueseven
Copy link
Collaborator Author

simply reload the function or the cards.clj file to the REPL and it should be reflected in the game engine without having to recreate a new game

@mtgred Any idea why it does not seem to work inside Intellij? I can reload the files in the REPL, and I see my changes, but they are not reflected in the game :-( Maybe I'm doing something wrong?

@JoelCFC25 Did you have any luck with reloading files/functions inside the REPL?

@mtgred
Copy link
Owner

mtgred commented Jul 10, 2015

Let's take a simple example:

  1. Change Hedge Funds to give 10 credits instead of 9.
  2. Reload cards.clj into the REPL. (Tools→REPL. “Load file in REPL”)
  3. Play the card, you should gain 10 credits.

For installed cards you have to drag them back to hand and install them again to see the change.

@queueseven
Copy link
Collaborator Author

Does not work for me. I tried running the REPL from the command line (lein repl).

I changed Hedge Fund:

"Hedge Fund"
{:effect (effect (gain :credit 99)) :test 123}

reloaded the file (use 'game.core :reload), and checked it:

game.main=> (get-in cards '("Hedge Fund" :test))
123

So the file was reloaded, but when I play Hedge Fund in the game, it will still only give 9 credits, not 99.

Anyone any idea how to troubleshoot this issue?

@nealterrell
Copy link
Collaborator

I reload with (load-file "src/clj/game/cards.clj"), not sure if that is different.

@queueseven
Copy link
Collaborator Author

I did

lein clean
lein uberjar
lein repl

now reloading works for me with

(load-file "src/clj/game/cards.clj")

Thanks!

@gaverhae
Copy link
Contributor

Hi all!

I'm just starting with this project, but I do have some experience with Clojure. I think I can clarify a few things in this discussion:

  • Clojure's clojure.lang/print function is equivalent to System.out.print in Java. Both are buffered, i.e. the printed text does not actually appear on the console until there's either "enough" of it to fill the buffer (which is big) or there is a newline. There is a clojure.lang/println function which is an equivalent to System.out.println in Java. However, for debugging, prn is usually better (println tries to print a user-friendly representation, whereas prn strives for a machine-readable one).
  • (use 'game.core :reload) seems to be a typo: it reloads the game.core namespace, whereas you wanted to reload the game/cards.clj file (which is not directly associated with a namespace).
  • java -jar ...standalone.jar does basically start the server, but does not start a REPL, and does not provide any opportunity for code reloading (in particular, it never looks at the source files). For more details on that point, you can look at game/main.clj: java -jar essentially runs the game.main/main function directly (i.e. not from a REPL), which is very similar but not equivalent to the game.main/dev function you call with (future-call dev) from the REPL.

@nealterrell
Copy link
Collaborator

Thanks for the clarifications! Very happy to see more people becoming interested in contributing :).

@queueseven
Copy link
Collaborator Author

I could need some help on client side development. I never touched clojurescript/react/sablono etc before so bear with me if I'm missing something obvious.

I changed log-pane to simply create [:spans ... ] elements to handle the credit/click/etc. items instead of the :dangerouslySetInnerHTML #js {:__html (add-symbols ... part. So far, so good. Works.

Now, I wanted to add an event handler to one of the [:span ] elements, something like:

[:span {:on-mouse-enter #(put! zoom-channel {:code card})
        :on-mouse-leave #(put! zoom-channel false)} title]

to enable the card-view in gameboard.

But that does not work. What am I missing?

Also, I don't know why the second span element (the element where I try to attach the event handler) is so big and the other two span elements are sized right.

image
image
image

Would be awesome if any of you web gurus could help me out on this :-)

@gaverhae
Copy link
Contributor

Nothing jumps at me based on your description. Could you fork this project and push your current code there? Maybe playing with your complete code will help us figure out what's wrong.

@queueseven
Copy link
Collaborator Author

You can find my branch here: https://github.com/DominicKexel/netrunner/tree/cards. Look at gameboard.cljs.

If you also have some debugging tipps that are better than js/console.log I would love to hear. I can set breakpoints in chrome's dev tools can't evaluate variables in there.

@gaverhae
Copy link
Contributor

As far as I can see, the on-mouse-* triggers work well. It seems to be the surrounding if that "fails". Keep in mind that I'm highly unfamiliar with both the codebase and the card game, do maybe I'm misunderstanding something, but here's what I've done:

Change the span generation to add classes, i. e.:
(if ...
  [:span {:class "if-true"
          :on-mouse-enter #(...)
          :on-mouse-leave #(...)} title]
  [:span {:class "if-false"} item])

This shows that, in my limited tests, all generated spans have the class if-false.

Add on-mouse-enter to false case

I've added the same event triggers to the false case, except of course that the card variable is not define, so I replaced it with a simple string (hello). Additionally, I changed the definition of the zoom-channel receiver (around line 530) to add a log:

(go (while true
       (let [card (<! zoom-channel)]
         (js/console.log (pr-str [:zoom-channel card]))
         (om/set-state! owner :zoom card))))

This shows that it works as expected: when hovering the chat log, the console does print "hello", although of course there is subsequently an error message as hello is not a valid card.

I'm unfortunately unable to help you correcting the conditions in the if expression.

@queueseven
Copy link
Collaborator Author

Hey @gaverhae thanks for your input!

The if conditions where correct, turned out that there was an error in an unrelated function in another file that caused my code to fail.

The fact that the size of the span is wrong seem to be just a display issue with chrome's developer tools. When I add a class to the spans, the size is shown correctly.

Hovering the mouse over a card name in the log window now previous the card correctly. I will polish it a bit and then create a pull request.

@queueseven
Copy link
Collaborator Author

BTW, figwheel is awesome.

@Quarg
Copy link

Quarg commented Aug 9, 2015

I'm having a few issues with attempting to help with this;

1: I'm not sure what URL to use for testing locally.
2: Attempting to use the run configuration listed for IntelliJ makes it complain about no SDK being selected.

@JoelCFC25
Copy link
Collaborator

  1. http://localhost:1042/
  2. Select your JDK in File -> Project Structure

@Quarg
Copy link

Quarg commented Aug 9, 2015

Ok, now I'm getting this error when trying to run from IntelliJ:

Exception in thread "main" java.lang.ExceptionInInitializerError, compiling:(C:\Users\Max\.IdeaIC14\system\tmp\form-init5041530868960999582.clj:1:107)
Caused by: java.lang.ExceptionInInitializerError
    at game.cards__init.<clinit>(Unknown Source)
    at game.core__init.<clinit>(Unknown Source)
    at game.main$loading__4958__auto__.invoke(main.clj:1)
    at game.main__init.<clinit>(Unknown Source)
    ... 16 more
Caused by: clojure.lang.ArityException: Wrong number of args (0) passed to: core/fn--2677
    at game.cards-assets__init.load(Unknown Source)
    at game.cards-assets__init.<clinit>(Unknown Source)
    ... 80 more

Process finished with exit code 1
Exception starting REPL: java.lang.InterruptedException

@justinliew
Copy link
Contributor

Do you have any local changes?
Do you get it when running from the command line, ie. lein repl?
Can you compile from command line with lein uberjar and see if it still happens?

@Quarg
Copy link

Quarg commented Aug 10, 2015

I don't have any local changes.
Compiling and running from the command line results with this:

nREPL server started on port 50765 on host 127.0.0.1 - nrepl://127.0.0.1:50765
REPL-y 0.3.7, nREPL 0.2.10
Clojure 1.6.0
Java HotSpot(TM) 64-Bit Server VM 1.7.0_25-b17
    Docs: (doc function-name-here)
          (find-doc "part-of-name-here")
  Source: (source function-name-here)
 Javadoc: (javadoc java-object-or-class-here)
    Exit: Control+D or (exit) or (quit)
 Results: Stored in vars *1, *2, *3, an exception in *e

game.main=> (-main)
[Prod] Listening on port 1043 for incoming commands...
nil

@queueseven
Copy link
Collaborator Author

So it seems like a problem just with IntelliJ. You don't really need it, except for the debugger and maybe code navigation (but the source code is not large in size).

@Quarg
Copy link

Quarg commented Aug 11, 2015

I'm still not able to get anything useful from running it from the command line like that though, as the page remains effectively blank (no menu buttons in top left etc, just like if you were to run the coffee script on it's own, (I presume this means that the main core of the server isn't running))

@queueseven
Copy link
Collaborator Author

Do you have MongoDB running? Does the Webserver (coffee Server.coffee) report any errors? Have you tried starting the game Server with (future-call dev) instead of (-main)?

@Quarg
Copy link

Quarg commented Aug 11, 2015

MongoDB is running (and shows connections being opened when starting the webserver and opening the page in browser (only once though))
The webserver doesn't report any errors.
Attempting to start the game server with(future-call dev) gives

game.main=> (future-call dev)
[Dev] Listening on port 1043 for incoming commands...
#<core$future_call$reify__6320@b1c929f: :pending>
game.main=>

and does not affect the page in any noticable way.

@justinliew
Copy link
Contributor

@Quarg - that's right. Once you start a game then the server will receive connections and start doing stuff. You won't see any output, however, as by default there isn't any debug prints happening. You'll have to start adding your own if there are areas of the code you're interested in. You can also type stuff in the REPL to inspect values. I'd start with @game-states, which returns you a map of gameid -> game state. Then you can do something like @(get @game-states 2) to get the map of a specific game id (in this case 2).

@Quarg
Copy link

Quarg commented Aug 11, 2015

@justinliew Ok, so using @game-states proves it is at least partially working (in that it shows an empty map rather than complaining it isn't defined), though it doesn't solve the issue that I can't start games, due to the lack of a "play" page etc.

@nealterrell
Copy link
Collaborator

The first thing I like to do when in a repl is start my game then execute (def state (second (first @game-states))). You can then use state to inspect the current game state, the same as if you were in a card our core function. Execute the def again when you make a new game.

@JoelCFC25
Copy link
Collaborator

I'm closing this since we have good information on the wiki now for those who want to try and get up and running.

@matthiasfabry
Copy link

matthiasfabry commented Jun 28, 2016

Hi there, i'm trying to set up my machine for development, but
npm install
throws errors at me:
failed to locate CL.exe
et cetera. therefore
coffee server.coffee also doesn't work.

Besides this i think i have all dependencies properly installed

EDIT:
Maybe some extra info to help you guys solving this problem:
server.coffee can't find the module ../build/Release/bson
and all the way down the stacktrace it says at node.js:456:3
which (i think) confirms this has to do with the node.js dependencies.

@JoelCFC25
Copy link
Collaborator

There are some suggestions on Stack Overflow here and here that the Visual C++ compiler might not be installed by default with some versions of Visual Studio. Could be worth a try--and searching Stack Overflow is often very helpful.

@queueseven
Copy link
Collaborator Author

It seems you have problems building the native (non-javascript) modules. First of all, delete the node_modules folder. You're on Windows, so make sure you have Visual Studio with the C++ compiler installed. You have to pass the version of Visual Studio to npm, look at the wiki on how to do this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

8 participants