Java-Gaming.org Hi !
Featured games (83)
games approved by the League of Dukes
Games in Showcase (522)
Games in Android Showcase (127)
games submitted by our members
Games in WIP (590)
games currently in development
News: Read the Java Gaming Resources, or peek at the official Java tutorials
 
    Home     Help   Search   Login   Register   
Pages: 1 [2] 3
  ignore  |  Print  
  Java Continuations and GreenThreads  (Read 17743 times)
0 Members and 1 Guest are viewing this topic.
Offline Riven
« League of Dukes »

« JGO Overlord »


Medals: 835
Projects: 4
Exp: 16 years


Hand over your head.


« Reply #30 - Posted 2013-01-11 02:17:45 »

Version 0.8.6 has been released.


Bug fixes
I found an issue with the callsite of certain constructors and Matthias solved it immediately by letting the instrumentation code emit an exception. Matthias is looking into a permanent solution, but for now it's good to have the instrumentator notify you of the edge case where it cannot produce valid continuations... yet. More info on this later, until then, download the latest version and pay attention to any warnings printed on the console.


Features

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
      final VirtualExchanger<String> ex = new VirtualExchanger<>();

      new VirtualThread(new VirtualRunnable() {
         @Override
         public void run() throws SuspendExecution {
           String got = ex.exchange("object1a");
            System.out.println("thread1 got: " + got);
           
           got = ex.exchange("object1b");
            System.out.println("thread1 got: " + got);
         }
      }).start();

      new VirtualThread(new VirtualRunnable() {
         @Override
         public void run() throws SuspendExecution {
           String got = ex.exchange("object2a");
            System.out.println("thread2 got: " + got);
           
           got = ex.exchange("object2b");
            System.out.println("thread2 got: " + got);
         }
      }).start();

1  
2  
3  
4  
5  
6  
7  
// exchange #1
thread2 got: object1a
thread1 got: object2a

// exchange #2
thread1 got: object2b
thread2 got: object1b




Download files

Hi, appreciate more people! Σ ♥ = ¾
Learn how to award medals... and work your way up the social rankings
Offline delt0r

JGO Knight


Medals: 27
Exp: 18 years


Computers can do that?


« Reply #31 - Posted 2013-01-11 09:34:05 »

I am currently using the Matthias continuations library and have found that it has greatly simplified my AI and network code. Perhaps i am a bit slow, but what have you added from that original lib? Is it just a green threads implementation?

Can't you already run many many native threads in linux for example anyway (aka the old thread per socket web server or a Selector).

I have no special talents. I am only passionately curious.--Albert Einstein
Offline princec

« JGO Spiffy Duke »


Medals: 421
Projects: 3
Exp: 16 years


Eh? Who? What? ... Me?


« Reply #32 - Posted 2013-01-11 10:24:13 »

You can run many threads on any OS; the problem is that you are then dealing with synchronization and non-deterministic behaviour. And on ARM you even have significant memory barrier overhead as the ARM architecture doesn't enforce memory consistency between cores.

Cas Smiley

Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline Riven
« League of Dukes »

« JGO Overlord »


Medals: 835
Projects: 4
Exp: 16 years


Hand over your head.


« Reply #33 - Posted 2013-01-11 12:06:51 »

I am currently using the Matthias continuations library and have found that it has greatly simplified my AI and network code. Perhaps i am a bit slow, but what have you added from that original lib? Is it just a green threads implementation?
It's 'just' that, yes. If you browse through the code you'll see that 'just' is relative Smiley

I wrote this highlevel library on top of the continuations library, so that the concepts (processor, thread, sleep, lock, etc) are familiar for anybody having minimal experience with threading. Writing a proper scheduler (the VirtualProcessor) is not quite trivial, and it took me a few iterations to get it to where it is now. I think it's good to share the code, so others don't have to reinvent the wheel, lowering the bar for usage of Matthias Mann's ingenious library.

Can't you already run many many native threads in linux for example anyway (aka the old thread per socket web server or a Selector).
What Cas said, and your native threads need at least a 256K stack size to do anything non trivial. When you'd run the AI of every unit ingame on a native thread you'd quickly run out of memory.

Hi, appreciate more people! Σ ♥ = ¾
Learn how to award medals... and work your way up the social rankings
Offline Matthias

Senior Devvie


Medals: 3
Projects: 1


TWL - Themable Widget Library


« Reply #34 - Posted 2013-01-11 19:06:42 »

I added another update. Besides fixing methods which return 'long' - this version adds support to call suspendable methods as arguments for constructors (constructors itself are not suspendable).

This now allows constructs like this:
1  
2  
3  
System.out.println(new StringBuilder(someSuspendableMethodWhichReturnString()).append(" Bla").toString());
// Eclipse generates the above code for the following Java statement:
System.out.println(someSuspendableMethodWhichReturnString()+" Bla");
Offline Riven
« League of Dukes »

« JGO Overlord »


Medals: 835
Projects: 4
Exp: 16 years


Hand over your head.


« Reply #35 - Posted 2013-01-11 19:30:23 »

Version 0.8.7 has been released.


Bug fixes
  • See Matthias's post.

Download files

Hi, appreciate more people! Σ ♥ = ¾
Learn how to award medals... and work your way up the social rankings
Offline jonjava
« Reply #36 - Posted 2013-01-13 09:16:09 »

Anyone tried making a Server Client model with green thread clients?

Where does it lie in scalability between old Client/Thread and nio channels?

Offline Matthias

Senior Devvie


Medals: 3
Projects: 1


TWL - Themable Widget Library


« Reply #37 - Posted 2013-01-13 09:34:36 »

I started a HTTP client back in 2008 when I first wrote the lib, it is basically working - but I didn't do much testing on it.
Offline sproingie

JGO Kernel


Medals: 202



« Reply #38 - Posted 2013-01-13 17:41:04 »

Anyone tried making a Server Client model with green thread clients?

Most scalable servers use a model that isn't thread-per-client, but they tend to use nio, which is probably not what you meant.  JRockit uses a hybrid green/native model, and that runs some pretty heavy duty servers.
Offline Roquen
« Reply #39 - Posted 2013-01-13 19:53:32 »

Well for that matter Ericsson has been since the mid-80s.  Highly reliable and heavy workload.
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline Riven
« League of Dukes »

« JGO Overlord »


Medals: 835
Projects: 4
Exp: 16 years


Hand over your head.


« Reply #40 - Posted 2013-02-17 15:34:18 »

Version 0.8.10 has been released.


New features
  • New custom scheduler, capable of handling 2-3 million concurrent virtual threads on one native thread with half the scheduling overhead to about 900ns per context switch
  • Support for VirtualThreadLocal<T>
  • Support for message passing mailboxes
  • Reduced memory consumption per virtual thread, through lazy initialization
  • Reduced memory consumption per coroutine, for more efficient packing/unpacking of data (credits to Matthias Mann)

Everybody is encouraged to update to this new version!



Usage

VirtualThreadLocal code sample:
1  
2  
3  
4  
5  
6  
7  
8  
9  
VirtualThreadLocal<String> threadLocal = new VirtualThreadLocal<String>() {
   protected String initialValue() {
      return "undefined";
   }
};

String s = threadLocal.get();
threadLocal.set("initialized");
String t = threadLocal.get();


VirtualMessage code sample:
1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
final VirtualThread threadA = new VirtualThread(new VirtualRunnable() {
   @Override
   public void run() throws SuspendExecution {
      VirtualMessage got = VirtualThread.pollMessage();
      // ... or ...
      VirtualMessage got = VirtualThread.awaitMessage();


      VirtualThread source = got.author();
      Object actualMessage = got.message();
   }
});

final VirtualThread threadB = new VirtualThread(new VirtualRunnable() {
   @Override
   public void run() throws SuspendExecution {
      threadA.passMessage("hello");
   }
});




Download files



Hi, appreciate more people! Σ ♥ = ¾
Learn how to award medals... and work your way up the social rankings
Offline Riven
« League of Dukes »

« JGO Overlord »


Medals: 835
Projects: 4
Exp: 16 years


Hand over your head.


« Reply #41 - Posted 2013-02-18 01:52:00 »

For everybody wondering what this library can be used for apart from AI, I just wrote a simple (http) server that was load-tested with a utility called load_http. My server reads the request, sends the response and closes the connection. There is no logic or file I/O involved.

The code is based on NIO, but without Selectors. It will forcefully perform I/O, until the SocketChannel tells the http server that it cannot read/write anything, and cause the VirtualThread to sleep for a bit and try again. Imagine the process like this:
1  
2  
3  
4  
5  
while(data.hasRemaining()) {
   if(socketChannel.write(data) == 0) {
      VirtualThread.sleep(10);
   }
}


Using this approach, I managed to create a http server that handles literally (slightly) over 9000 http-requests & responses per second, over a 50 second period.

This simply cannot be achieved with NIO Selectors, which get stuck at about 550 requests & responses per second.

Everything runs on 1 native thread. I might multithread the code to see how it improves performance.

Hi, appreciate more people! Σ ♥ = ¾
Learn how to award medals... and work your way up the social rankings
Offline ra4king

JGO Kernel


Medals: 355
Projects: 3
Exp: 5 years


I'm the King!


« Reply #42 - Posted 2013-02-18 05:32:28 »

I am extremely impressed. Great job Riven O__O

Offline jonjava
« Reply #43 - Posted 2013-02-18 21:37:42 »

What... you sure? o.O

[EDIT]: I must try this

Offline Riven
« League of Dukes »

« JGO Overlord »


Medals: 835
Projects: 4
Exp: 16 years


Hand over your head.


« Reply #44 - Posted 2013-02-19 15:55:56 »

I can imagine most of you guys will yawn, but on a quad-core, with 4 native threads each running a VirtualProcessor, I managed 12,000 16,000 requests & responses per second (each with its own tcp connection), within a VirtualBox VM running Debian 2.6.32 on a Win7 host.

1  
2  
3  
4  
5  
6  
7  
./http_load -parallel 1000 -second 50 urls.txt

813412 fetches, 1000 max parallel, 2.4988e+09 bytes, in 50 seconds
3072 mean bytes/connection
16268.2 fetches/sec, 4.9976e+07 bytes/sec
msecs/connect: 5.78194 mean, 9000.63 max, 0.036 min
msecs/first-response: 5.23287 mean, 642.339 max, 0.623 min


http://pastebin.java-gaming.org/a8dea333443 (the core of the beast)

Edit: it turned out the VirtualBox VM was limited to 1 CPU core. After changing that I get 16K instead of 12K fetches/sec.

Hi, appreciate more people! Σ ♥ = ¾
Learn how to award medals... and work your way up the social rankings
Offline theagentd

« JGO Bitwise Duke »


Medals: 361
Projects: 2
Exp: 8 years



« Reply #45 - Posted 2013-02-19 16:09:23 »

That IS cool as hell! Still, I find it a bit hard to justify its use in games though. I guess the win lies in how you can design things like AI more than performance. So, when will JGO be hosted with that? ^^

Myomyomyo.
Offline Riven
« League of Dukes »

« JGO Overlord »


Medals: 835
Projects: 4
Exp: 16 years


Hand over your head.


« Reply #46 - Posted 2013-02-19 16:13:15 »

Why is it hard to justify in games? Especially in AI the possibilities are endless. AI with intelligent (!) and complex behaviour is very hard to achieve without flow-control. I agree that for simple AI, this library is indeed over the top.

Hi, appreciate more people! Σ ♥ = ¾
Learn how to award medals... and work your way up the social rankings
Offline theagentd

« JGO Bitwise Duke »


Medals: 361
Projects: 2
Exp: 8 years



« Reply #47 - Posted 2013-02-19 16:17:46 »

But it's not difficult to add the ability for an entity's AI to "sleep". Wait-notify is a bit trickier I guess.

Is the library deterministic enough to be used for network lock-stepping? Does it have some amazing feature I'm missing?

Myomyomyo.
Offline Riven
« League of Dukes »

« JGO Overlord »


Medals: 835
Projects: 4
Exp: 16 years


Hand over your head.


« Reply #48 - Posted 2013-02-19 16:23:09 »

It's not about the ability to sleep. It's about having inherent state (in local variables, in loops, etc).

To show you an example of a lumberjack AI:
1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  
32  
33  
34  
35  
36  
37  
38  
39  
40  
41  
42  
43  
44  
45  
46  
47  
48  
49  
50  
51  
52  
53  
54  
55  
56  
57  
58  
59  
60  
61  
62  
63  
64  
65  
66  
67  
68  
69  
70  
71  
72  
73  
74  
75  
76  
77  
78  
79  
80  
81  
82  
83  
84  
85  
86  
87  
88  
89  
90  
91  
92  
93  
94  
95  
96  
97  
98  
99  
100  
101  
102  
103  
104  
105  
106  
107  
108  
109  
110  
111  
112  
113  
114  
115  
116  
117  
118  
119  
120  
121  
122  
123  
124  
125  
126  
127  
128  
129  
130  
public class Lumberjack extends Human {

   final ResourceConversion makeLogs;

   public Lumberjack() {
      this.name = "lumberjack";

      // ....
   }

   @Override
   public void ai() throws SuspendExecution {

      GameItem lastTree = null;

      while (true) {
         this.survive();

         lastTree = this.gatherWood(lastTree);

         this.dumpWood();

         VirtualThread.sleep(1000);
      }
   }

// this acutally is a method in the class Human
   protected void survive() throws SuspendExecution {
      Vec2 goBackTo = new Vec2(this.position);

      boolean didSomethingElse = false;
      while (this.isThirsty()) {
         this.task = "looking for water";
         GameItem water = this.findNearestWater();
         if (water == null) {
            break;
         }

         didSomethingElse = true;

         this.task = "walking to water";
         moveTo(water.position);

         this.task = "drinking water";
         this.drinkWater(water);
      }

      if (didSomethingElse) {
         this.task = "going back...";
      }
      moveTo(goBackTo);
   }

   public int chop(GameItem tree) throws SuspendExecution {

      int transfer = tree.transfer(TREE, this, 1);
      if (tree.isEmpty()) {
         tree.kill();
      }

      return transfer;
   }

   private GameItem gatherWood(GameItem tree) throws SuspendExecution {
      while (!this.inventory.logs.isFull()) {
         this.survive();

         this.task = "looking for a tree";
         if (tree == null || !tree.isAlive()) {
            tree = this.findNearestTree();
            if (tree == null) {
               break;
            }
         }

         this.task = ((Math.random() < 0.1) ? 't' : 'w') + "alking to a tree";
         this.moveTo(tree.position);

         this.task = "chopping tree";
         while (this.chop(tree) > 0) {
            VirtualThread.sleep(Misc.random(500, 1500));
            this.survive();
         }

         this.task = "chopping tree into logs";
         do {
            VirtualThread.sleep(Misc.random(500, 1500));
            this.survive();
         } while (this.makeLogs.convert(this));
      }
      return tree;
   }

   private void dumpWood() throws SuspendExecution {
      while (!this.inventory.logs.isEmpty()) {
         this.task = "looking for storage";
         GameItem storage = this.findNearestStorageWithFreeSpace();
         if (storage == null) {
            break;
         }

         this.task = "dragging logs to " + storage;
         this.moveTo(storage.position);

         this.survive();

         this.task = "dumping logs at " + storage;
         /* int dumped = */this.transfer(LOG, storage);

         VirtualThread.sleep(1000);
      }
   }

   private GameItem findNearestTree() throws SuspendExecution {
      return Game.nearestProducer(TREE, false, null, this.position);
   }

   private GameItem findNearestStorageWithFreeSpace() throws SuspendExecution {
      GameItem item1 = Game.nearestHolderWithSpace(LOG, null, this.position);
      GameItem item2 = Game.nearestConsumer(LOG, false, null, this.position);

      if (item1 != null && item2 != null) {
         float dist1 = Vec2.distanceSquared(item1.position, this.position);
         float dist2 = Vec2.distanceSquared(item2.position, this.position);
         return dist1 < dist2 ? item1 : item2;
      }

      return (item1 != null) ? item1 : item2;
   }
}


This sample falls in the category of 'dirt stupid AI', so continuations are overkill, but at the very least it shows how 'state' is stored in (recursive) methods.

Hi, appreciate more people! Σ ♥ = ¾
Learn how to award medals... and work your way up the social rankings
Offline sproingie

JGO Kernel


Medals: 202



« Reply #49 - Posted 2013-02-19 17:06:48 »

"continuations are overkill"

Nothing of the sort.  Why would they be more overkill than, say, a loop?  Okay, yes, I'll grant that a continuations library with its kinky bytecode manipulation to get around a language not having native support might not be the first thing to reach for when a native approach would work equally well.  But continuations aren't mysterious exotic things -- in fact their main problem is that they're too low-level for most circumstances, a sort of "functional GOTO" you can build any other control flow construct you want from.

Let's demystify continuations.  This library is a great first step toward that.  Interestingly it seems to be following the path of Stackless Python, which started with first-class continuations, then increasingly focused on microthreads until ultimately abandoning callcc-style mechanisms altogether.  But I'm also a sucker for CSP primitives too, so this library is awesome any way you slice it.

Offline Riven
« League of Dukes »

« JGO Overlord »


Medals: 835
Projects: 4
Exp: 16 years


Hand over your head.


« Reply #50 - Posted 2013-02-19 17:11:04 »

Is the library deterministic enough to be used for X?
Yes, VirtualThread scheduling is deterministic.



Let's demystify continuations.  This library is a great first step toward that.  Interestingly it seems to be following the path of Stackless Python, which started with first-class continuations, then increasingly focused on microthreads ---
In my opinion coroutines and continuations are too lowlevel for just about all developers. The idea that you can store a capture of a method in memory and then execute it multiple times will scare the hell out of just about everybody dealing with C-like languages, although I think it comes reasonably close to an out-of-bounds POSIX fork.

I think this incredibly powerful and awesome functionality, provided by Matthias Mann's library, is best hidden away from average Joe and put behind a simple abstraction layer that exposes it as a concept that the developer is already familiar with: threads.

The only thing people have got to get used to is co-operative scheduling, which (obviously) isn't a requirement in a native thread.

Hi, appreciate more people! Σ ♥ = ¾
Learn how to award medals... and work your way up the social rankings
Offline Roquen
« Reply #51 - Posted 2013-02-20 11:10:28 »

I dunno. For someone that knows nothing about either (coop & pre-emptive) I'd think that learning coop is easier...but I suppose it's all about the API/language integration.  As an aside one of the uni's very active in HotSpot (and other Sun/Oracle JVMs) has implemented coroutines in the JVM (along with a fair number of other nice features like real mixins) (http://ssw.jku.at/Research/Projects/JVM/).

I haven't (yet) looked at Riven's source.  Serialization?  Have you thought about a watchdog thread with time-out as an option?
Offline Nate

« JGO Bitwise Duke »


Medals: 158
Projects: 4
Exp: 14 years


Esoteric Software


« Reply #52 - Posted 2013-02-20 12:01:56 »

I'm using this for an export dialog, simply to display progress without needing a state machine for my huge export method that has to run in the GL thread. It isn't really a big deal to use the agent and put some processing in the build. Just now upgrading to the latest, if you break all my stuff Riven, I kill you! Wink Tongue Edit: seems to still work. Smiley

Offline Riven
« League of Dukes »

« JGO Overlord »


Medals: 835
Projects: 4
Exp: 16 years


Hand over your head.


« Reply #53 - Posted 2013-02-20 15:24:30 »

As an aside one of the uni's very active in HotSpot (and other Sun/Oracle JVMs) has implemented coroutines in the JVM (along with a fair number of other nice features like real mixins) (http://ssw.jku.at/Research/Projects/JVM/).
I wrote a simple Java bytecode interpreter in Java *gasp* and implementing continuations in that was trivial. After all, you basically just save and change the instruction-pointer (and stack - which contains the execution frames) and restore the stack some time later by simply setting a pointer. The amount of trickely involved to support this with bytecode instrumentation is mind boggling.

I haven't (yet) looked at Riven's source.  Serialization?  Have you thought about a watchdog thread with time-out as an option?
Serialization is already supported. The downside of using a watchdog thread is that when you want to kill a VirtualThread you really have to kill the native thread, which... doesn't exactly equate to pre-emptive scheduling as it will kill your entire single-threaded application. Smiley

Hi, appreciate more people! Σ ♥ = ¾
Learn how to award medals... and work your way up the social rankings
Offline Roquen
« Reply #54 - Posted 2013-02-20 16:21:16 »

I was thinking more along the lines of (as an example): you have a single real thread running just AIs and one of the fibers goes into an infinite loop (or is simply taking too long)...watchdog kills, the system starts a new thread to continue running (after perhaps calling a "you've been a bad boy" method on the offender)..etc.
Offline Riven
« League of Dukes »

« JGO Overlord »


Medals: 835
Projects: 4
Exp: 16 years


Hand over your head.


« Reply #55 - Posted 2013-02-20 17:11:50 »

Again, the problem is that you can only kill a VirtualThread by killing the native thread, and thereby killing all VirtualThreads that run on the VirtualProcessor.

You cannot simply restart the game logic with spawning a new AI thread, as all stacks and execution frames of all VirtualThreads are lost.

It's like... calling java.lang.Thread.stop() (as that's actually what happens), you leave the application in undefined state. Finally blocks won't get executed, referenced objects can be left in corrupt state (only N out of M fields are updated) - in short, you're pretty likely to leave your application in a state that you don't even want it to recover from.

Hi, appreciate more people! Σ ♥ = ¾
Learn how to award medals... and work your way up the social rankings
Offline VeaR

Junior Devvie





« Reply #56 - Posted 2013-02-20 18:42:21 »

I really like this, and i intend to use it too. I remember some years ago i was working on AI bots, and i had to write my own scheduler for them. It would have been much better if i could write code which doesn't have to go trough the complete bot logic at each iteration.

What about using this for handling players too? Put a certain number of players onto a single native thread and make a VirtualThread for each of the players. I'm evaluating Netty.IO for networking right now, and seems to me that it handles incoming UDP differently than TCP. TCP connection can be delegated out to threads, so each native thread can handle certain number of connections. But UDP packets sent to a single listening port just get delivered to a single thread/channel/pipeline, no matter from where they came. So its the UDP handlers task to sort them out. What if players first got to connect to a specific UDP port, and after authentication they were redirected to resume their traffic with another port? So the server would listen on certain UDP ports, and the players would be distributed over those. At each UDP port there would be a native thread with a handler, and the packets would be delivered to VirtualThreads. I really want to avoid having a single thread for forwarding data to players, since that would mean that all the traffic would have to pass trough one specific queue. (I know this belongs to networking. I was just thinking about how this could be combined with that.)
Offline xsvenson
« Reply #57 - Posted 2013-02-20 18:45:09 »

This is very neat.
Lots of props to You, Sir.

“The First Rule of Program Optimization: Don't do it. The Second Rule of Program Optimization (for experts only!): Don't do it yet.” - Michael A. Jackson
Offline Nate

« JGO Bitwise Duke »


Medals: 158
Projects: 4
Exp: 14 years


Esoteric Software


« Reply #58 - Posted 2013-02-27 00:03:49 »

Could it be compiled for Java 6? I'd just pull in the source but it's in JARs mixed with class files...
1  
2  
3  
javap -verbose VirtualThread.class | grep version
 minor version: 0
 major version: 51

Offline Riven
« League of Dukes »

« JGO Overlord »


Medals: 835
Projects: 4
Exp: 16 years


Hand over your head.


« Reply #59 - Posted 2013-02-27 00:54:12 »

I created a jar with the source for you:


That's the most I can do at this time of day Smiley

Hi, appreciate more people! Σ ♥ = ¾
Learn how to award medals... and work your way up the social rankings
Pages: 1 [2] 3
  ignore  |  Print  
 
 
You cannot reply to this message, because it is very, very old.

 

Add your game by posting it in the WIP section,
or publish it in Showcase.

The first screenshot will be displayed as a thumbnail.

trollwarrior1 (29 views)
2014-11-22 12:13:56

xFryIx (71 views)
2014-11-13 12:34:49

digdugdiggy (50 views)
2014-11-12 21:11:50

digdugdiggy (44 views)
2014-11-12 21:10:15

digdugdiggy (38 views)
2014-11-12 21:09:33

kovacsa (62 views)
2014-11-07 19:57:14

TehJavaDev (67 views)
2014-11-03 22:04:50

BurntPizza (65 views)
2014-11-03 18:54:52

moogie (80 views)
2014-11-03 06:22:04

CopyableCougar4 (80 views)
2014-11-01 23:36:41
Understanding relations between setOrigin, setScale and setPosition in libGdx
by mbabuskov
2014-10-09 22:35:00

Definite guide to supporting multiple device resolutions on Android (2014)
by mbabuskov
2014-10-02 22:36:02

List of Learning Resources
by Longor1996
2014-08-16 10:40:00

List of Learning Resources
by SilverTiger
2014-08-05 19:33:27

Resources for WIP games
by CogWheelz
2014-08-01 16:20:17

Resources for WIP games
by CogWheelz
2014-08-01 16:19:50

List of Learning Resources
by SilverTiger
2014-07-31 16:29:50

List of Learning Resources
by SilverTiger
2014-07-31 16:26:06
java-gaming.org is not responsible for the content posted by its members, including references to external websites, and other references that may or may not have a relation with our primarily gaming and game production oriented community. inquiries and complaints can be sent via email to the info‑account of the company managing the website of java‑gaming.org
Powered by MySQL Powered by PHP Powered by SMF 1.1.18 | SMF © 2013, Simple Machines | Managed by Enhanced Four Valid XHTML 1.0! Valid CSS!