c41de2845803

Start working on chunks and gravity.
[view raw] [browse files]
author Steve Losh <steve@stevelosh.com>
date Thu, 04 Aug 2011 00:22:22 -0400
parents 085e63240d4f
children 669045aca6f9
branches/tags (none)
files project.clj src/clojurecraft/actions.clj src/clojurecraft/chunks.clj src/clojurecraft/core.clj src/clojurecraft/data.clj src/clojurecraft/in.clj src/clojurecraft/mappings.clj src/clojurecraft/util.clj

Changes

--- a/project.clj	Wed Aug 03 21:11:51 2011 -0400
+++ b/project.clj	Thu Aug 04 00:22:22 2011 -0400
@@ -1,4 +1,5 @@
 (defproject clojurecraft "0.0.1-SNAPSHOT"
   :description "TODO: add summary of your project"
   :dependencies [[clojure "1.2.0"]
-                 [clojure-contrib "1.2.0"]])
+                 [clojure-contrib "1.2.0"]]
+  :jvm-opts ["-Xmx1g"])
--- a/src/clojurecraft/actions.clj	Wed Aug 03 21:11:51 2011 -0400
+++ b/src/clojurecraft/actions.clj	Thu Aug 04 00:22:22 2011 -0400
@@ -12,5 +12,5 @@
                                  :z (+ z-change (:z location))
                                  :stance (+ y-change (:stance location))})]
         (alter player merge {:loc new-location}))))
-  bot)
+  nil)
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/clojurecraft/chunks.clj	Thu Aug 04 00:22:22 2011 -0400
@@ -0,0 +1,54 @@
+(ns clojurecraft.chunks
+  (:use [clojurecraft.mappings])
+  (:use [clojurecraft.util])
+  (:require [clojurecraft.data])
+  (:import [clojurecraft.data Block]))
+
+(defn coords-of-chunk-containing [x z]
+  [(bit-shift-right x 4)
+   (bit-shift-right z 4)])
+
+(defn block-index-in-chunk [x y z]
+  [(bit-and x 15)
+   (bit-and y 127)
+   (bit-and z 15)])
+
+(defn block-from-chunk [x y z chunk]
+  (let [[ix iy iz] (block-index-in-chunk x y z)
+        i (+ y (* z 128) (* x 128 16))
+        block-type (get (:types chunk) i)
+        block-meta (get (:metadata chunk) i)
+        block-light (get (:light chunk) i)
+        block-sky-light (get (:sky-light chunk) i)]
+    (Block. [x y z]
+            (block-types (int block-type))
+            block-meta
+            block-light
+            block-sky-light)))
+
+(defn chunk-containing [x z chunks]
+  (chunks (coords-of-chunk-containing x z)))
+
+(defn -block [x y z chunks]
+  (block-from-chunk x y z (chunk-containing x z chunks)))
+
+(defn block [bot x y z]
+  (-block x y z (:chunks (:world bot))))
+
+(defn block-rel [bot x y z]
+  (block bot
+         (int (+ (:x (:loc @(:player bot))) x))
+         (int (+ (:y (:loc @(:player bot))) y))
+         (int (+ (:z (:loc @(:player bot))) z))))
+
+(defn block-standing [bot]
+  (block bot
+         (int (:x (:loc @(:player bot))))
+         (int (- (:y (:loc @(:player bot))) 0))
+         (int (:z (:loc @(:player bot))))))
+
+(defn current [bot]
+  (chunk-containing
+         (int (:x (:loc @(:player bot))))
+         (int (:z (:loc @(:player bot))))
+         @(:chunks (:world bot))))
--- a/src/clojurecraft/core.clj	Wed Aug 03 21:11:51 2011 -0400
+++ b/src/clojurecraft/core.clj	Thu Aug 04 00:22:22 2011 -0400
@@ -4,6 +4,7 @@
   (:use [clojurecraft.out])
   (:use [clojurecraft.util])
   (:use [clojure.contrib.pprint :only (pprint)])
+  (:require [clojurecraft.chunks :as chunks])
   (:require [clojurecraft.actions :as act])
   (:require (clojurecraft.data))
   (:import [clojurecraft.data Location Entity Block Chunk World Bot])
@@ -51,12 +52,48 @@
       (read-packet bot)))
   (println "done"))
 
+
+; TODO: Investigate this.  I'm not convinced.
+(def G -9.8)       ; meters/second^2
+(def TICK 50/1000) ; seconds
+
+(defn apply-gravity [player]
+  (let [y        (:y      (:loc player))
+        stance   (:stance (:loc player))
+        velocity (:velocity player)
+        new-y        (+ y      (* velocity TICK))
+        new-stance   (+ stance (* velocity TICK))
+        new-velocity (max -4.0 (+ velocity (* G TICK)))]
+    [new-y        ; TODO: More research on terminal velocity.
+     new-stance
+     new-velocity]))
+
+(defn should-apply-gravity? [bot]
+  (non-solid-blocks (l :type (chunks/block-standing bot))))
+
+(defn update-location [bot]
+  (when (chunks/current bot)
+    (dosync
+      (let [player (:player bot)]
+        (if (should-apply-gravity? bot)
+          (let [[new-y new-stance new-velocity] (apply-gravity @player)]
+            (alter player assoc :velocity new-velocity)
+            (alter player assoc-in [:loc :y] new-y)
+            (alter player assoc-in [:loc :stance] new-stance)
+            (alter player assoc-in [:loc :onground] false))
+          (do
+            (alter player assoc :velocity 0.0)
+            (alter player assoc-in [:loc :onground] true)))))))
+
 (defn location-handler [bot]
   (let [conn (:connection bot)
         outqueue (:outqueue bot)]
     (while (nil? (:exit @conn))
-      (let [location (:loc @(:player bot))]
-        (.put outqueue [:playerpositionlook location])
+      (let [player (:player bot)
+            location (:loc @player)]
+        (when (not (nil? location))
+          (.put outqueue [:playerpositionlook location])
+          (update-location bot))
         (Thread/sleep 50)))))
 
 (defn output-handler [bot]
@@ -83,7 +120,7 @@
     ; We need to log in to find out our bot's entity ID, so we delay creation of the
     ; player until then.
     (let [player-id (:eid (login bot username))
-          player (ref (Entity. player-id STARTING-LOC false))
+          player (ref (Entity. player-id nil false 0.0))
           bot (assoc bot :player player)]
 
       ; Theoretically another connected bot could fill in the player's entity entry
--- a/src/clojurecraft/data.clj	Wed Aug 03 21:11:51 2011 -0400
+++ b/src/clojurecraft/data.clj	Thu Aug 04 00:22:22 2011 -0400
@@ -27,7 +27,7 @@
 ;   something has changed, since otherwise there would be no way to tell
 ;   (despawning would simply remove the object from the entity list
 ;   without modifying it).
-(defrecord Entity [eid loc despawned])
+(defrecord Entity [eid loc despawned velocity])
 
 ; Block
 ;
@@ -38,15 +38,21 @@
 ;   A simple vector of three coordinates, NOT a Location (for performance).
 ;
 ; kind -> TODO
-(defrecord Block [loc kind])
+(defrecord Block [loc type meta light sky-light])
 
 ; Chunk
 ;
 ; A single chunk in the world.
 ;
-; blocks -> [block ...]
-;   A vector of the blocks in this chunk.
-(defrecord Chunk [blocks])
+; You should never have to use these directly.  clojurecraft.chunks contains helper
+; functions that should give you the block data you need.
+;
+; types     -> [int ...]
+; metadata  -> byte-array
+; light     -> byte-array
+; sky-light -> byte-array
+;
+(defrecord Chunk [types metadata light sky-light])
 
 ; World
 ;
--- a/src/clojurecraft/in.clj	Wed Aug 03 21:11:51 2011 -0400
+++ b/src/clojurecraft/in.clj	Thu Aug 04 00:22:22 2011 -0400
@@ -3,7 +3,7 @@
   (:use [clojurecraft.mappings])
   (:use [clojurecraft.chunks])
   (:require [clojurecraft.data])
-  (:import [clojurecraft.data Location Entity])
+  (:import [clojurecraft.data Location Entity Chunk])
   (:import (java.util.zip Inflater)))
 
 ; Bytes ----------------------------------------------------------------------------
@@ -299,7 +299,7 @@
             entities (:entities (:world bot))
             entity (@entities eid)]
         (when-not entity
-          (alter entities assoc eid (Entity. eid nil false)))))
+          (alter entities assoc eid (Entity. eid nil false 0.0)))))
     payload))
 
 (defn- read-packet-entityrelativemove [bot conn]
@@ -376,8 +376,7 @@
     (let [[block-metadata data] (-parse-nibbles len data)
           [block-light data] (-parse-nibbles len data)
           [sky-light data] (-parse-nibbles len data)]
-      (map #({:blocktype %1 :blockmeta %2 :blocklight %3 :skylight %4})
-           block-types block-metadata block-light sky-light))))
+      [block-types block-metadata block-light sky-light])))
 
 (defn- -read-packet-mapchunk-chunkdata [conn predata]
   (let [raw-data (-read-bytearray conn (:compressedsize predata))
@@ -400,8 +399,16 @@
                        :sizey (+ 1 (-read-byte conn))
                        :sizez (+ 1 (-read-byte conn))
                        :compressedsize (-read-int conn))]
-    (let [decompressed-data (-read-packet-mapchunk-chunkdata conn predata)]
-      (assoc predata :data (-read-packet-mapchunk-decode predata decompressed-data)))))
+    (let [decompressed-data (-read-packet-mapchunk-chunkdata conn predata)
+          decoded-data (-read-packet-mapchunk-decode predata decompressed-data)]
+      (when (and (= (:sizex predata) 16) ; TODO: Handle partial chunks at some point.
+                 (= (:sizey predata) 128)
+                 (= (:sizez predata) 16))
+        (let [[types meta light sky] decoded-data
+              chunk (Chunk. types meta light sky)
+              chunk-coords (coords-of-chunk-containing (:x predata) (:z predata))]
+          (dosync (alter (:chunks (:world bot)) assoc chunk-coords chunk))))
+      (assoc predata :data decompressed-data))))
 
 
 (defn- read-packet-multiblockchange [bot conn]
--- a/src/clojurecraft/mappings.clj	Wed Aug 03 21:11:51 2011 -0400
+++ b/src/clojurecraft/mappings.clj	Thu Aug 04 00:22:22 2011 -0400
@@ -67,7 +67,7 @@
   -1   nil
   0x00 :air
   0x01 :stone
-  0x02 :grass
+  0x02 :dirt-grassy
   0x03 :dirt
   0x04 :cobblestone
   0x05 :planks
@@ -162,6 +162,7 @@
   0x60 :hatch
 })
 (def block-ids (invert block-types))
+(def non-solid-blocks #{ :air :sign-wall })
 
 (def item-types {
   -1    nil
--- a/src/clojurecraft/util.clj	Wed Aug 03 21:11:51 2011 -0400
+++ b/src/clojurecraft/util.clj	Thu Aug 04 00:22:22 2011 -0400
@@ -5,5 +5,11 @@
      (println result#)
      result#))
 
+(defmacro lc [& body]
+  `(let [result# (~@body)]
+     (println result#)
+     (println (class result#))
+     result#))
+
 (defn invert [m]
   (apply assoc {} (mapcat reverse m)))