Hedgeroid: Frantic scrabbling toward the deadline
- Added activities for weapon/scheme editors (unfinished)
- Completed tablet version of netroom activity
- Added map preview
- Fixed default team files having the wrong names
- Restructuring
- Updated frontlib JNA bindings to respect the latest frontlib changes
--- a/hedgewars/hwLibrary.pas Sat Aug 18 00:22:33 2012 +0200
+++ b/hedgewars/hwLibrary.pas Sat Aug 18 00:47:51 2012 +0200
@@ -99,10 +99,14 @@
JNI_HW_versionInfoVersion := envderef^.NewStringUTF(env, PChar(cVersionString));
end;
-function JNI_HW_GenLandPreview(env: PJNIEnv; c: JClass; port: JInt):JInt; cdecl;
+procedure JNI_HW_GenLandPreview(env: PJNIEnv; c: JClass; port: JInt); cdecl;
begin
GenLandPreview(port);
- JNI_HW_GenLandPreview := port;
+end;
+
+procedure JNI_HW_Terminate(env: PJNIEnv; c: JClass); cdecl;
+begin
+ HW_terminate(false);
end;
exports
@@ -112,7 +116,7 @@
HW_getNumberOfweapons name Java_Prefix + 'HWgetNumberOfWeapons',
HW_getMaxNumberOfHogs name Java_Prefix + 'HWgetMaxNumberOfHogs',
HW_getMaxNumberOfTeams name Java_Prefix + 'HWgetMaxNumberOfTeams',
- HW_terminate name Java_Prefix + 'HWterminate',
+ JNI_HW_Terminate name Java_Prefix + 'HWterminate',
Game;
{$ELSE}
exports
--- a/project_files/Android-build/SDL-android-project/AndroidManifest.xml Sat Aug 18 00:22:33 2012 +0200
+++ b/project_files/Android-build/SDL-android-project/AndroidManifest.xml Sat Aug 18 00:47:51 2012 +0200
@@ -67,16 +67,40 @@
android:windowSoftInputMode="stateUnchanged" >
</activity>
<activity
- android:name=".netplay.LobbyActivity"
+ android:name=".LobbyActivity"
android:label="@string/title_activity_lobby"
android:screenOrientation="landscape"
android:windowSoftInputMode="adjustPan" >
</activity>
<activity
- android:name=".netplay.RoomActivity"
+ android:name=".RoomActivity"
android:label="@string/title_activity_room"
android:screenOrientation="landscape"
android:windowSoftInputMode="adjustPan" >
</activity>
+ <activity
+ android:name=".WeaponsetListActivity"
+ android:label="@string/title_activity_weaponset_list"
+ android:screenOrientation="landscape"
+ android:windowSoftInputMode="adjustPan" >
+ </activity>
+ <activity
+ android:name=".WeaponsetCreatorActivity"
+ android:label="@string/title_activity_weaponset_creator"
+ android:screenOrientation="landscape"
+ android:windowSoftInputMode="adjustPan" >
+ </activity>
+ <activity
+ android:name=".SchemeListActivity"
+ android:label="@string/title_activity_scheme_list"
+ android:screenOrientation="landscape"
+ android:windowSoftInputMode="adjustPan" >
+ </activity>
+ <activity
+ android:name=".SchemeCreatorActivity"
+ android:label="@string/title_activity_scheme_creator"
+ android:screenOrientation="landscape"
+ android:windowSoftInputMode="adjustPan" >
+ </activity>
</application>
</manifest>
\ No newline at end of file
--- a/project_files/Android-build/SDL-android-project/assets/Data/metasettings.ini Sat Aug 18 00:22:33 2012 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,234 +0,0 @@
-[mod0]
-name=fortsmode
-bitmaskindex=12
-
-[mod1]
-name=divteams
-bitmaskindex=4
-
-[mod2]
-name=solidland
-bitmaskindex=2
-
-[mod3]
-name=border
-bitmaskindex=3
-
-[mod4]
-name=lowgrav
-bitmaskindex=5
-
-[mod5]
-name=laser
-bitmaskindex=6
-
-[mod6]
-name=invulnerability
-bitmaskindex=7
-
-[mod7]
-name=resethealth
-bitmaskindex=8
-
-[mod8]
-name=vampiric
-bitmaskindex=9
-
-[mod9]
-name=karma
-bitmaskindex=10
-
-[mod10]
-name=artillery
-bitmaskindex=11
-
-[mod11]
-name=randomorder
-bitmaskindex=13
-
-[mod12]
-name=king
-bitmaskindex=14
-
-[mod13]
-name=placehog
-bitmaskindex=15
-
-[mod14]
-name=sharedammo
-bitmaskindex=16
-
-[mod15]
-name=disablegirders
-bitmaskindex=17
-
-[mod16]
-name=disablelandobjects
-bitmaskindex=18
-
-[mod17]
-name=aisurvival
-bitmaskindex=19
-
-[mod18]
-name=infattack
-bitmaskindex=20
-
-[mod19]
-name=resetweps
-bitmaskindex=21
-
-[mod20]
-name=perhogammo
-bitmaskindex=22
-
-[mod21]
-name=disablewind
-bitmaskindex=23
-
-[mod22]
-name=morewind
-bitmaskindex=24
-
-[mod23]
-name=tagteam
-bitmaskindex=25
-
-[mod24]
-name=bottomborder
-bitmaskindex=26
-
-
-[setting0]
-name=damagefactor
-times1000=false
-command=e$damagepct
-maxmeansinfinity=false
-min=10
-max=300
-default=100
-
-[setting1]
-name=turntime
-times1000=true
-command=e$turntime
-maxmeansinfinity=true
-min=1
-max=9999
-default=45
-
-[setting2]
-name=health
-times1000=false
-maxmeansinfinity=false
-min=50
-max=200
-default=100
-
-[setting3]
-name=suddendeath
-times1000=false
-command=e$sd_turns
-maxmeansinfinity=true
-min=0
-max=50
-default=15
-
-[setting4]
-name=caseprobability
-times1000=false
-command=e$casefreq
-maxmeansinfinity=false
-min=0
-max=9
-default=5
-
-[setting5]
-name=minestime
-times1000=true
-command=e$minestime
-maxmeansinfinity=false
-min=-1
-max=5
-default=3
-
-[setting6]
-name=minesnum
-times1000=false
-command=e$minesnum
-maxmeansinfinity=false
-min=0
-max=80
-default=4
-
-[setting7]
-name=minedudpct
-times1000=false
-command=e$minedudpct
-maxmeansinfinity=false
-min=0
-max=100
-default=0
-
-[setting8]
-name=explosives
-times1000=false
-command=e$explosives
-maxmeansinfinity=false
-min=0
-max=40
-default=2
-
-[setting9]
-name=healthprobability
-times1000=false
-command=e$healthprob
-maxmeansinfinity=false
-min=0
-max=100
-default=35
-
-[setting10]
-name=healthcaseamount
-times1000=false
-command=e$hcaseamount
-maxmeansinfinity=false
-min=0
-max=200
-default=25
-
-[setting11]
-name=waterrise
-times1000=false
-command=e$waterrise
-maxmeansinfinity=false
-min=0
-max=100
-default=47
-
-[setting12]
-name=healthdecrease
-times1000=false
-command=e$healthdec
-maxmeansinfinity=false
-min=0
-max=100
-default=5
-
-[setting13]
-name=ropepct
-times1000=false
-command=e$ropepct
-maxmeansinfinity=false
-min=25
-max=999
-default=100
-
-[setting14]
-name=getawaytime
-times1000=false
-command=e$getawaytime
-maxmeansinfinity=false
-min=0
-max=999
-default=100
--- a/project_files/Android-build/SDL-android-project/assets/assetsversion.txt Sat Aug 18 00:22:33 2012 +0200
+++ b/project_files/Android-build/SDL-android-project/assets/assetsversion.txt Sat Aug 18 00:47:51 2012 +0200
@@ -1,1 +1,1 @@
-5
\ No newline at end of file
+7
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/res/drawable-mdpi/hogcount.xml Sat Aug 18 00:47:51 2012 +0200
@@ -0,0 +1,10 @@
+ <level-list xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:maxLevel="1" android:drawable="@drawable/hogcount1" />
+ <item android:maxLevel="2" android:drawable="@drawable/hogcount2" />
+ <item android:maxLevel="3" android:drawable="@drawable/hogcount3" />
+ <item android:maxLevel="4" android:drawable="@drawable/hogcount4" />
+ <item android:maxLevel="5" android:drawable="@drawable/hogcount5" />
+ <item android:maxLevel="6" android:drawable="@drawable/hogcount6" />
+ <item android:maxLevel="7" android:drawable="@drawable/hogcount7" />
+ <item android:maxLevel="8" android:drawable="@drawable/hogcount8" />
+ </level-list>
\ No newline at end of file
Binary file project_files/Android-build/SDL-android-project/res/drawable-mdpi/hogcount1.png has changed
Binary file project_files/Android-build/SDL-android-project/res/drawable-mdpi/hogcount2.png has changed
Binary file project_files/Android-build/SDL-android-project/res/drawable-mdpi/hogcount3.png has changed
Binary file project_files/Android-build/SDL-android-project/res/drawable-mdpi/hogcount4.png has changed
Binary file project_files/Android-build/SDL-android-project/res/drawable-mdpi/hogcount5.png has changed
Binary file project_files/Android-build/SDL-android-project/res/drawable-mdpi/hogcount6.png has changed
Binary file project_files/Android-build/SDL-android-project/res/drawable-mdpi/hogcount7.png has changed
Binary file project_files/Android-build/SDL-android-project/res/drawable-mdpi/hogcount8.png has changed
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/res/drawable-mdpi/team_local_by_level.xml Sat Aug 18 00:47:51 2012 +0200
@@ -0,0 +1,8 @@
+<level-list xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:maxLevel="0" android:drawable="@drawable/human" />
+ <item android:maxLevel="1" android:drawable="@drawable/bot5" />
+ <item android:maxLevel="2" android:drawable="@drawable/bot4" />
+ <item android:maxLevel="3" android:drawable="@drawable/bot3" />
+ <item android:maxLevel="4" android:drawable="@drawable/bot2" />
+ <item android:maxLevel="5" android:drawable="@drawable/bot1" />
+</level-list>
\ No newline at end of file
Binary file project_files/Android-build/SDL-android-project/res/drawable-mdpi/team_net_bot1.png has changed
Binary file project_files/Android-build/SDL-android-project/res/drawable-mdpi/team_net_bot2.png has changed
Binary file project_files/Android-build/SDL-android-project/res/drawable-mdpi/team_net_bot3.png has changed
Binary file project_files/Android-build/SDL-android-project/res/drawable-mdpi/team_net_bot4.png has changed
Binary file project_files/Android-build/SDL-android-project/res/drawable-mdpi/team_net_bot5.png has changed
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/res/drawable-mdpi/team_net_by_level.xml Sat Aug 18 00:47:51 2012 +0200
@@ -0,0 +1,8 @@
+<level-list xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:maxLevel="0" android:drawable="@drawable/team_net_human" />
+ <item android:maxLevel="1" android:drawable="@drawable/team_net_bot5" />
+ <item android:maxLevel="2" android:drawable="@drawable/team_net_bot4" />
+ <item android:maxLevel="3" android:drawable="@drawable/team_net_bot3" />
+ <item android:maxLevel="4" android:drawable="@drawable/team_net_bot2" />
+ <item android:maxLevel="5" android:drawable="@drawable/team_net_bot1" />
+</level-list>
\ No newline at end of file
Binary file project_files/Android-build/SDL-android-project/res/drawable-mdpi/team_net_human.png has changed
--- a/project_files/Android-build/SDL-android-project/res/drawable-mdpi/teamcount.xml Sat Aug 18 00:22:33 2012 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,12 +0,0 @@
- <level-list xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:maxLevel="0" android:drawable="@drawable/teams_number0" />
- <item android:maxLevel="1" android:drawable="@drawable/teams_number1" />
- <item android:maxLevel="2" android:drawable="@drawable/teams_number2" />
- <item android:maxLevel="3" android:drawable="@drawable/teams_number3" />
- <item android:maxLevel="4" android:drawable="@drawable/teams_number4" />
- <item android:maxLevel="5" android:drawable="@drawable/teams_number5" />
- <item android:maxLevel="6" android:drawable="@drawable/teams_number6" />
- <item android:maxLevel="7" android:drawable="@drawable/teams_number7" />
- <item android:maxLevel="8" android:drawable="@drawable/teams_number8" />
- <item android:maxLevel="9" android:drawable="@drawable/teams_number9" />
- </level-list>
\ No newline at end of file
Binary file project_files/Android-build/SDL-android-project/res/drawable-mdpi/teamcount0.png has changed
Binary file project_files/Android-build/SDL-android-project/res/drawable-mdpi/teamcount1.png has changed
Binary file project_files/Android-build/SDL-android-project/res/drawable-mdpi/teamcount2.png has changed
Binary file project_files/Android-build/SDL-android-project/res/drawable-mdpi/teamcount3.png has changed
Binary file project_files/Android-build/SDL-android-project/res/drawable-mdpi/teamcount4.png has changed
Binary file project_files/Android-build/SDL-android-project/res/drawable-mdpi/teamcount5.png has changed
Binary file project_files/Android-build/SDL-android-project/res/drawable-mdpi/teamcount6.png has changed
Binary file project_files/Android-build/SDL-android-project/res/drawable-mdpi/teamcount7.png has changed
Binary file project_files/Android-build/SDL-android-project/res/drawable-mdpi/teamcount8.png has changed
Binary file project_files/Android-build/SDL-android-project/res/drawable-mdpi/teamcount9.png has changed
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/res/drawable-mdpi/teams_number.xml Sat Aug 18 00:47:51 2012 +0200
@@ -0,0 +1,12 @@
+ <level-list xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:maxLevel="0" android:drawable="@drawable/teams_number0" />
+ <item android:maxLevel="1" android:drawable="@drawable/teams_number1" />
+ <item android:maxLevel="2" android:drawable="@drawable/teams_number2" />
+ <item android:maxLevel="3" android:drawable="@drawable/teams_number3" />
+ <item android:maxLevel="4" android:drawable="@drawable/teams_number4" />
+ <item android:maxLevel="5" android:drawable="@drawable/teams_number5" />
+ <item android:maxLevel="6" android:drawable="@drawable/teams_number6" />
+ <item android:maxLevel="7" android:drawable="@drawable/teams_number7" />
+ <item android:maxLevel="8" android:drawable="@drawable/teams_number8" />
+ <item android:maxLevel="9" android:drawable="@drawable/teams_number9" />
+ </level-list>
\ No newline at end of file
--- a/project_files/Android-build/SDL-android-project/res/layout/activity_netroom.xml Sat Aug 18 00:22:33 2012 +0200
+++ b/project_files/Android-build/SDL-android-project/res/layout/activity_netroom.xml Sat Aug 18 00:47:51 2012 +0200
@@ -21,7 +21,7 @@
android:layout_marginBottom="10dp"
android:baselineAligned="false"
android:minHeight="200dp" >
-
+
<FrameLayout
android:id="@+id/mapFrame"
android:layout_width="0dp"
@@ -30,14 +30,12 @@
android:layout_weight="1"
android:background="@drawable/box" >
- <!--
- <fragment
+ <fragment
android:id="@+id/mapFragment"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
class="org.hedgewars.hedgeroid.netplay.MapFragment"
tools:layout="@layout/fragment_map" />
- -->
</FrameLayout>
<FrameLayout
@@ -48,14 +46,12 @@
android:layout_weight="1"
android:background="@drawable/box" >
- <!--
- <fragment
+ <fragment
android:id="@+id/settingsFragment"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
class="org.hedgewars.hedgeroid.netplay.SettingsFragment"
tools:layout="@layout/fragment_settings" />
- -->
</FrameLayout>
<FrameLayout
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/res/layout/activity_schemelist.xml Sat Aug 18 00:47:51 2012 +0200
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical" >
+
+ <ListView
+ android:id="@android:id/list"
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:layout_weight="1"
+ android:cacheColorHint="@android:color/transparent" />
+
+ <Button
+ android:id="@+id/addButton"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/schemelist_add_button_text"
+ android:background="@drawable/button" />
+
+</LinearLayout>
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/res/layout/activity_weaponsetlist.xml Sat Aug 18 00:47:51 2012 +0200
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical" >
+
+ <TextView
+ android:id="@android:id/empty"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:gravity="center"
+ android:text="@string/weaponsetlist_empty" />
+
+ <ListView
+ android:id="@android:id/list"
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:layout_weight="1"
+ android:cacheColorHint="@android:color/transparent" />
+
+ <Button
+ android:id="@+id/addButton"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:background="@drawable/button"
+ android:text="@string/weaponsetlist_add_button_text" />
+
+</LinearLayout>
\ No newline at end of file
--- a/project_files/Android-build/SDL-android-project/res/layout/fragment_map.xml Sat Aug 18 00:22:33 2012 +0200
+++ b/project_files/Android-build/SDL-android-project/res/layout/fragment_map.xml Sat Aug 18 00:47:51 2012 +0200
@@ -17,8 +17,8 @@
android:layout_centerHorizontal="true"
android:layout_margin="5dip"
android:background="@drawable/box"
- android:scaleType="fitXY"
- android:src="@drawable/backbutton" />
+ android:scaleType="fitCenter"
+ android:src="@drawable/roomlist_preparing" />
<TableLayout
android:id="@+id/gameOptions"
@@ -30,32 +30,56 @@
<TableRow>
<TextView
- android:id="@+id/txtMap"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:text="@string/map_map" />
+ android:text="@string/map_gen" />
<Spinner
- android:id="@+id/spinMaps"
+ android:id="@+id/spinMapType"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/dropdown" />
</TableRow>
- <TableRow>
-
+ <TableRow android:id="@+id/rowMapName">
<TextView
- android:id="@+id/txtType"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:text="@string/map_type" />
+ android:layout_gravity="center_vertical"
+ android:text="@string/map_name" />
<Spinner
- android:id="@+id/spinType"
- android:layout_width="wrap_content"
+ android:id="@+id/spinMapName"
+ android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="@drawable/dropdown" />
</TableRow>
+ <TableRow android:id="@+id/rowTemplateFilter">
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:text="@string/map_template" />
+
+ <Spinner
+ android:id="@+id/spinTemplateFilter"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:background="@drawable/dropdown" />
+ </TableRow>
+ <TableRow android:id="@+id/rowMazeSize">
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:text="@string/map_maze_size" />
+
+ <Spinner
+ android:id="@+id/spinMazeSize"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:background="@drawable/dropdown" />
+ </TableRow>
</TableLayout>
</RelativeLayout>
\ No newline at end of file
--- a/project_files/Android-build/SDL-android-project/res/layout/listview_item.xml Sat Aug 18 00:22:33 2012 +0200
+++ b/project_files/Android-build/SDL-android-project/res/layout/listview_item.xml Sat Aug 18 00:47:51 2012 +0200
@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@android:id/text1"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textSize="10dip"
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/res/layout/listview_team.xml Sat Aug 18 00:47:51 2012 +0200
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:paddingTop="4dp"
+ android:paddingBottom="4dp" >
+ <TextView
+ android:id="@android:id/text1"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical|left"
+ android:layout_weight="1"
+ android:gravity="center_vertical"
+ android:drawablePadding="5dp"
+ android:textAppearance="?android:attr/textAppearanceMedium" />
+
+ <ImageButton
+ android:id="@+id/colorButton"
+ android:layout_width="48dp"
+ android:layout_height="48dp"
+ android:layout_gravity="center_vertical|right"
+ android:src="#fff"
+ android:padding="8dp"
+ android:contentDescription="@string/teamlist_color_button_description" />
+
+ <ImageButton
+ android:id="@+id/hogCountButton"
+ android:layout_width="48dp"
+ android:layout_height="48dp"
+ android:layout_gravity="center_vertical|right"
+ android:src="@drawable/hogcount"
+ android:scaleType="centerCrop"
+ android:padding="0dp"
+ android:contentDescription="@string/teamlist_hogcount_button_description" />
+</LinearLayout>
\ No newline at end of file
--- a/project_files/Android-build/SDL-android-project/res/layout/starting_game.xml Sat Aug 18 00:22:33 2012 +0200
+++ b/project_files/Android-build/SDL-android-project/res/layout/starting_game.xml Sat Aug 18 00:47:51 2012 +0200
@@ -147,7 +147,7 @@
android:adjustViewBounds="true"
android:scaleType="centerInside"
android:background="@android:color/transparent"
- android:src="@drawable/teamcount"/>
+ android:src="@drawable/teams_number"/>
</LinearLayout>
--- a/project_files/Android-build/SDL-android-project/res/layout/team_selection_entry.xml Sat Aug 18 00:22:33 2012 +0200
+++ b/project_files/Android-build/SDL-android-project/res/layout/team_selection_entry.xml Sat Aug 18 00:47:51 2012 +0200
@@ -31,7 +31,7 @@
android:layout_alignBottom="@id/imgDifficulty"
android:adjustViewBounds="true"
android:scaleType="centerInside"
- android:src="@drawable/teamcount7"/>
+ android:src="@drawable/hogcount"/>
<TextView
android:id="@+id/txtName"
android:layout_height="fill_parent"
--- a/project_files/Android-build/SDL-android-project/res/menu/main_options.xml Sat Aug 18 00:22:33 2012 +0200
+++ b/project_files/Android-build/SDL-android-project/res/menu/main_options.xml Sat Aug 18 00:47:51 2012 +0200
@@ -9,4 +9,8 @@
android:title="@string/main_menu_preferences"
android:icon="@android:drawable/ic_menu_preferences"
android:showAsAction="ifRoom|withText" />
+ <item
+ android:id="@+id/edit_weaponsets"
+ android:title="@string/edit_weaponsets_menu"
+ android:showAsAction="ifRoom|withText" />
</menu>
\ No newline at end of file
--- a/project_files/Android-build/SDL-android-project/res/values/frontend_data_pointers.xml Sat Aug 18 00:22:33 2012 +0200
+++ b/project_files/Android-build/SDL-android-project/res/values/frontend_data_pointers.xml Sat Aug 18 00:47:51 2012 +0200
@@ -4,4 +4,8 @@
<item>@raw/team_one</item>
<item>@raw/team_two</item>
</array>
+<array name="teamFilenames">
+ <item>Team 1.hwt</item>
+ <item>Team 2.hwt</item>
+</array>
</resources>
--- a/project_files/Android-build/SDL-android-project/res/values/strings.xml Sat Aug 18 00:22:33 2012 +0200
+++ b/project_files/Android-build/SDL-android-project/res/values/strings.xml Sat Aug 18 00:47:51 2012 +0200
@@ -63,19 +63,49 @@
<string name="title_activity_lobby">Hedgewars Server Lobby</string>
<string name="title_activity_room">Room</string>
+ <string name="title_activity_weaponset_list">User-defined Weaponsets</string>
+ <string name="title_activity_weaponset_creator">Weaponset Editor</string>
+ <string name="title_activity_scheme_list">User-defined Schemes</string>
+ <string name="title_activity_scheme_creator">Scheme Editor</string>
<string name="chat_hint">Type here to chat</string>
<!-- Map settings -->
- <string name="map_map">Map</string>
- <string name="map_type">Type</string>
- <string name="map_seed">Change seed</string>
+ <string name="map_gen">Map</string>
+ <string name="map_name">Name</string>
+ <string name="map_template">Type</string>
+ <string name="map_maze_size">Type</string>
+ <string name="map_mission_prefix">Mission: </string>
+ <string-array name="map_types">
+ <item>Generated map</item>
+ <item>Generated maze</item>
+ <item>Hand-drawn map</item>
+ <item>Map file</item>
+ </string-array>
+ <string-array name="map_templates">
+ <item>Random</item>
+ <item>Small</item>
+ <item>Medium</item>
+ <item>Large</item>
+ <item>Cavern</item>
+ <item>Wacky</item>
+ </string-array>
+ <string-array name="map_maze_sizes">
+ <item>Small tunnels</item>
+ <item>Medium tunnels</item>
+ <item>Large tunnels</item>
+ <item>Small floating islands</item>
+ <item>Medium floating islands</item>
+ <item>Large floating islands</item>
+ </string-array>
<!-- Player list -->
<string name="no_players_in_list">No players</string>
<!-- Teamlist -->
<string name="teamlist_addteam">Add team</string>
+ <string name="teamlist_color_button_description">Team color</string>
+ <string name="teamlist_hogcount_button_description">Hog count</string>
<!-- Roomlist -->
<string name="roomlist_header_roomname">Room Name</string>
@@ -140,4 +170,11 @@
<string name="toast_disconnected">Disconnected: %1$s</string>
<string name="toast_room_abandoned">The room was closed because the owner left.</string>
<string name="toast_kicked">You were kicked from the room.</string>
+
+ <!-- Weaponset editor -->
+ <string name="weaponsetlist_add_button_text">New Weaponset</string>
+ <string name="weaponsetlist_empty">No weaponsets</string>
+ <string name="edit_weaponsets_menu">Edit Weaponsets</string>
+
+ <string name="schemelist_add_button_text">New Scheme</string>
</resources>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/ChatFragment.java Sat Aug 18 00:47:51 2012 +0200
@@ -0,0 +1,78 @@
+package org.hedgewars.hedgeroid;
+
+import org.hedgewars.hedgeroid.R;
+import org.hedgewars.hedgeroid.netplay.MessageLog;
+import org.hedgewars.hedgeroid.netplay.Netplay;
+
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.view.KeyEvent;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.EditText;
+import android.widget.ListView;
+import android.widget.TextView;
+import android.widget.TextView.OnEditorActionListener;
+
+public class ChatFragment extends Fragment {
+ public static final String ARGUMENT_INROOM = "inRoom";
+
+ private ChatlogAdapter adapter;
+ private Netplay netconn;
+ private MessageLog messageLog;
+ private boolean inRoom;
+
+ public void setInRoom(boolean inRoom) {
+ this.inRoom = inRoom;
+ }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ netconn = Netplay.getAppInstance(getActivity().getApplicationContext());
+ adapter = new ChatlogAdapter(getActivity());
+ }
+
+ @Override
+ public void onStart() {
+ super.onStart();
+ messageLog = inRoom ? netconn.roomChatlog : netconn.lobbyChatlog;
+ adapter.setLog(messageLog.getLog());
+ messageLog.registerObserver(adapter);
+ }
+
+ @Override
+ public void onStop() {
+ super.onStop();
+ messageLog.unregisterObserver(adapter);
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ View view = inflater.inflate(R.layout.fragment_chat, container, false);
+
+ ListView listView = (ListView) view.findViewById(R.id.chatConsole);
+ listView.setAdapter(adapter);
+ listView.setDivider(null);
+ listView.setDividerHeight(0);
+ listView.setVerticalFadingEdgeEnabled(true);
+
+ EditText editText = (EditText) view.findViewById(R.id.chatInput);
+ editText.setOnEditorActionListener(new ChatSendListener());
+
+ return view;
+ }
+
+ private final class ChatSendListener implements OnEditorActionListener {
+ public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
+ String text = v.getText().toString();
+ if(text.length()>0) {
+ v.setText("");
+ netconn.sendChat(text);
+ }
+ return true;
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/ChatlogAdapter.java Sat Aug 18 00:47:51 2012 +0200
@@ -0,0 +1,95 @@
+package org.hedgewars.hedgeroid;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import org.hedgewars.hedgeroid.netplay.MessageLog.Observer;
+
+import android.content.Context;
+import android.text.method.LinkMovementMethod;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.AbsListView.LayoutParams;
+import android.widget.BaseAdapter;
+import android.widget.TextView;
+
+/**
+ * Optimization: ListView is smart enough to try re-using the same view for an item
+ * with the same ID, but it still calls getView for those items when the list changes.
+ * Since lines with a given ID never change in our chatlog, we can avoid the effort
+ * of TextView.setText in many cases by checking if the view is already set up for the
+ * line with the right ID - but to do that, the view needs to remember the ID it's
+ * holding the text for. That's what the LoglineView does.
+ */
+class LoglineView extends TextView {
+ long chatlogId = -1;
+
+ public LoglineView(Context context) {
+ super(context);
+ }
+}
+
+public class ChatlogAdapter extends BaseAdapter implements Observer {
+ long idOffset = 0;
+ private List<CharSequence> log = new ArrayList<CharSequence>();
+ private Context context;
+
+ public ChatlogAdapter(Context context) {
+ this.context = context;
+ }
+
+ public int getCount() {
+ return log.size();
+ }
+
+ public Object getItem(int position) {
+ return log.get(position);
+ }
+
+ public long getItemId(int position) {
+ return position+idOffset;
+ }
+
+ public boolean hasStableIds() {
+ return true;
+ }
+
+ public void clear() {
+ idOffset += log.size();
+ log.clear();
+ notifyDataSetChanged();
+ }
+
+ public void lineAdded(CharSequence text) {
+ log.add(text);
+ notifyDataSetChanged();
+ }
+
+ public void lineRemoved() {
+ log.remove(0);
+ idOffset += 1;
+ notifyDataSetChanged();
+ }
+
+ public void setLog(Collection<CharSequence> log) {
+ idOffset += log.size();
+ this.log = new ArrayList<CharSequence>(log);
+ notifyDataSetChanged();
+ }
+
+ public View getView(int position, View convertView, ViewGroup parent) {
+ LoglineView v = (LoglineView)convertView;
+ if (v == null) {
+ v = new LoglineView(context);
+ v.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT));
+ v.setMovementMethod(LinkMovementMethod.getInstance());
+ }
+ long id = getItemId(position);
+ if(id != v.chatlogId) {
+ v.setText(log.get(position));
+ v.chatlogId = id;
+ }
+ return v;
+ }
+}
\ No newline at end of file
--- a/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/Datastructures/FrontendDataUtils.java Sat Aug 18 00:22:33 2012 +0200
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/Datastructures/FrontendDataUtils.java Sat Aug 18 00:47:51 2012 +0200
@@ -22,12 +22,11 @@
import java.io.File;
import java.io.FileNotFoundException;
import java.util.ArrayList;
-import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import org.hedgewars.hedgeroid.R;
-import org.hedgewars.hedgeroid.Utils;
+import org.hedgewars.hedgeroid.util.FileUtils;
import android.content.Context;
import android.graphics.Bitmap;
@@ -39,14 +38,13 @@
* @throws FileNotFoundException if the sdcard isn't available or the Maps directory doesn't exist
*/
public static ArrayList<MapFile> getMaps(Context c) throws FileNotFoundException {
- File[] files = Utils.getFilesFromRelativeDir(c,"Maps");
+ File[] files = FileUtils.getFilesFromRelativeDir(c,"Maps");
ArrayList<MapFile> ret = new ArrayList<MapFile>();
for(File f : files) {
- boolean isMission = Utils.hasFileWithSuffix(f, ".lua");
+ boolean isMission = FileUtils.hasFileWithSuffix(f, ".lua");
ret.add(new MapFile(f.getName(), isMission));
}
- Collections.sort(ret, MapFile.MISSIONS_FIRST_NAME_ORDER);
return ret;
}
@@ -56,7 +54,7 @@
* @throws FileNotFoundException if the sdcard isn't available or the Scripts/Multiplayer directory doesn't exist
*/
public static List<String> getGameStyles(Context c) throws FileNotFoundException {
- File[] files = Utils.getFilesFromRelativeDir(c, "Scripts/Multiplayer");
+ File[] files = FileUtils.getFilesFromRelativeDir(c, "Scripts/Multiplayer");
ArrayList<String> ret = new ArrayList<String>();
/*
* Caution: It is important that the "empty" style has this exact name, because
@@ -72,7 +70,6 @@
ret.add(name.replace('_', ' ').substring(0, name.length()-4));
}
}
- Collections.sort(ret, String.CASE_INSENSITIVE_ORDER);
return ret;
}
@@ -80,24 +77,15 @@
* @throws FileNotFoundException if the sdcard isn't available or the Themes directory doesn't exist
*/
public static List<String> getThemes(Context c) throws FileNotFoundException {
- List<String> list = Utils.getDirsWithFileSuffix(c, "Themes", "icon.png");
- Collections.sort(list, String.CASE_INSENSITIVE_ORDER);
- return list;
- }
-
- public static List<Weaponset> getWeaponsets(Context c) {
- // TODO stub, re-implement
- /*List<Weapon> list = Weapon.getWeapons(c);
- Collections.sort(list);*/
- return Collections.emptyList();
+ return FileUtils.getDirsWithFileSuffix(c, "Themes", "icon.png");
}
/**
* @throws FileNotFoundException if the sdcard isn't available or the Graphics/Graves directory doesn't exist
*/
public static ArrayList<HashMap<String, ?>> getGraves(Context c) throws FileNotFoundException {
- File gravePath = new File(new File(Utils.getDataPathFile(c), "Graphics"), "Graves");
- ArrayList<String> names = Utils.getFileNamesFromDirWithSuffix(c,"Graphics/Graves", ".png", true);
+ File gravePath = new File(new File(FileUtils.getDataPathFile(c), "Graphics"), "Graves");
+ ArrayList<String> names = FileUtils.getFileNamesFromDirWithSuffix(c,"Graphics/Graves", ".png", true);
ArrayList<HashMap<String, ?>> data = new ArrayList<HashMap<String, ?>>(names.size());
for(String s : names){
@@ -123,8 +111,8 @@
* @throws FileNotFoundException if the sdcard isn't available or the Graphics/Graves directory doesn't exist
*/
public static ArrayList<HashMap<String, ?>> getFlags(Context c) throws FileNotFoundException {
- File flagsPath = new File(new File(Utils.getDataPathFile(c), "Graphics"), "Flags");
- ArrayList<String> names = Utils.getFileNamesFromDirWithSuffix(c, "Graphics/Flags", ".png", true);
+ File flagsPath = new File(new File(FileUtils.getDataPathFile(c), "Graphics"), "Flags");
+ ArrayList<String> names = FileUtils.getFileNamesFromDirWithSuffix(c, "Graphics/Flags", ".png", true);
ArrayList<HashMap<String, ?>> data = new ArrayList<HashMap<String, ?>>(names.size());
for(String s : names){
@@ -141,7 +129,7 @@
* @throws FileNotFoundException if the sdcard isn't available or the Sounds/voices directory doesn't exist
*/
public static ArrayList<String> getVoices(Context c) throws FileNotFoundException {
- File[] files = Utils.getFilesFromRelativeDir(c, "Sounds/voices");
+ File[] files = FileUtils.getFilesFromRelativeDir(c, "Sounds/voices");
ArrayList<String> ret = new ArrayList<String>();
for(File f : files){
@@ -154,10 +142,9 @@
* @throws FileNotFoundException if the sdcard isn't available or the Forts directory doesn't exist
*/
public static ArrayList<String> getForts(Context c) throws FileNotFoundException {
- return Utils.getFileNamesFromDirWithSuffix(c,"Forts", "L.png", true);
+ return FileUtils.getFileNamesFromDirWithSuffix(c,"Forts", "L.png", true);
}
- // TODO wat
public static ArrayList<HashMap<String, ?>> getTypes(Context c){
ArrayList<HashMap<String, ?>> data = new ArrayList<HashMap<String, ?>>(6);
String[] levels = {c.getString(R.string.human), c.getString(R.string.bot5), c.getString(R.string.bot4), c.getString(R.string.bot3), c.getString(R.string.bot2), c.getString(R.string.bot1)};
@@ -167,6 +154,8 @@
HashMap<String, Object> map = new HashMap<String, Object>();
map.put("txt", levels[i]);
map.put("img", images[i]);
+ map.put("level", i);
+
data.add(map);
}
@@ -177,8 +166,8 @@
* @throws FileNotFoundException if the sdcard isn't available or the Graphics/Hats directory doesn't exist
*/
public static ArrayList<HashMap<String, ?>> getHats(Context c) throws FileNotFoundException {
- ArrayList<String> files = Utils.getFileNamesFromDirWithSuffix(c,"Graphics/Hats", ".png", true);
- File hatsPath = new File(new File(Utils.getDataPathFile(c), "Graphics"), "Hats");
+ ArrayList<String> files = FileUtils.getFileNamesFromDirWithSuffix(c,"Graphics/Hats", ".png", true);
+ File hatsPath = new File(new File(FileUtils.getDataPathFile(c), "Graphics"), "Hats");
int size = files.size();
ArrayList<HashMap<String, ?>> data = new ArrayList<HashMap<String, ?>>(size);
@@ -202,9 +191,11 @@
File[] teamFileNames = teamsDir.listFiles();
if(teamFileNames != null){
for(File file : teamFileNames){
- Team team = Team.load(file);
- if(team != null){
- ret.add(team);
+ if(file.getName().endsWith(".hwt")) {
+ Team team = Team.load(file);
+ if(team != null){
+ ret.add(team);
+ }
}
}
}
--- a/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/Datastructures/GameConfig.java Sat Aug 18 00:22:33 2012 +0200
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/Datastructures/GameConfig.java Sat Aug 18 00:47:51 2012 +0200
@@ -37,6 +37,7 @@
public static final String DEFAULT_STYLE = "Normal";
public static final String DEFAULT_SCHEME = "Default";
public static final String DEFAULT_WEAPONSET = "Default";
+ public static final String DEFAULT_THEME = "Bamboo";
public final String style;
public final Scheme scheme;
@@ -51,4 +52,10 @@
this.teams = Collections.unmodifiableList(new ArrayList<TeamInGame>(teams));
this.weaponset = weaponset;
}
+
+ @Override
+ public String toString() {
+ return "GameConfig [style=" + style + ", scheme=" + scheme + ", map="
+ + map + ", teams=" + teams + ", weaponset=" + weaponset + "]";
+ }
}
--- a/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/Datastructures/MapFile.java Sat Aug 18 00:22:33 2012 +0200
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/Datastructures/MapFile.java Sat Aug 18 00:47:51 2012 +0200
@@ -2,18 +2,20 @@
import java.io.File;
import java.io.FileNotFoundException;
+import java.util.ArrayList;
import java.util.Comparator;
+import java.util.List;
-import org.hedgewars.hedgeroid.Utils;
+import org.hedgewars.hedgeroid.R;
+import org.hedgewars.hedgeroid.util.FileUtils;
import android.content.Context;
-import android.widget.AdapterView.OnItemSelectedListener;
+import android.content.res.Resources;
/**
* Represents a map from the data directory
*/
public final class MapFile {
- public static final String MISSION_PREFIX = "Mission: "; // TODO move text generation to UI to allow translation
public static final String MAP_DIRECTORY = "Maps";
public final String name;
@@ -28,7 +30,7 @@
* @throws FileNotFoundException if the sdcard is not available. Does NOT throw if the requested map file does not exist.
*/
public static File getFileForMapname(Context ctx, String mapname) throws FileNotFoundException {
- return new File(new File(Utils.getDataPathFile(ctx), MAP_DIRECTORY), mapname);
+ return new File(new File(FileUtils.getDataPathFile(ctx), MAP_DIRECTORY), mapname);
}
public static final Comparator<MapFile> MISSIONS_FIRST_NAME_ORDER = new Comparator<MapFile>() {
@@ -43,10 +45,23 @@
@Override
public String toString() {
- return (isMission ? MISSION_PREFIX : "") + name;
+ return "MapFile [name=" + name + ", isMission=" + isMission + "]";
}
public File getPreviewFile(Context c) throws FileNotFoundException {
- return new File(new File(new File(Utils.getDataPathFile(c), MAP_DIRECTORY), name), "preview.png");
- };
+ return getPreviewFile(c, name);
+ }
+
+ public static File getPreviewFile(Context c, String mapName) throws FileNotFoundException {
+ return new File(FileUtils.getDataPathFile(c), MAP_DIRECTORY + "/" + mapName + "/" + "preview.png");
+ }
+
+ public static List<String> toDisplayNameList(List<MapFile> mapFiles, Resources res) {
+ String missionPrefix = res.getString(R.string.map_mission_prefix);
+ List<String> result = new ArrayList<String>();
+ for(MapFile mapFile : mapFiles) {
+ result.add((mapFile.isMission ? missionPrefix : "") + mapFile.name);
+ }
+ return result;
+ }
}
--- a/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/Datastructures/MapRecipe.java Sat Aug 18 00:22:33 2012 +0200
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/Datastructures/MapRecipe.java Sat Aug 18 00:47:51 2012 +0200
@@ -18,6 +18,9 @@
package org.hedgewars.hedgeroid.Datastructures;
+import java.util.Arrays;
+import java.util.UUID;
+
import org.hedgewars.hedgeroid.R;
import org.hedgewars.hedgeroid.frontlib.Frontlib;
@@ -65,6 +68,34 @@
return drawData==null ? null : drawData.clone();
}
+ public MapRecipe withMapgen(int mapgen) {
+ return new MapRecipe(mapgen, templateFilter, mazeSize, name, seed, theme, drawData);
+ }
+
+ public MapRecipe withTemplateFilter(int templateFilter) {
+ return new MapRecipe(mapgen, templateFilter, mazeSize, name, seed, theme, drawData);
+ }
+
+ public MapRecipe withMazeSize(int mazeSize) {
+ return new MapRecipe(mapgen, templateFilter, mazeSize, name, seed, theme, drawData);
+ }
+
+ public MapRecipe withName(String name) {
+ return new MapRecipe(mapgen, templateFilter, mazeSize, name, seed, theme, drawData);
+ }
+
+ public MapRecipe withSeed(String seed) {
+ return new MapRecipe(mapgen, templateFilter, mazeSize, name, seed, theme, drawData);
+ }
+
+ public MapRecipe withTheme(String theme) {
+ return new MapRecipe(mapgen, templateFilter, mazeSize, name, seed, theme, drawData);
+ }
+
+ public MapRecipe withDrawData(byte[] drawData) {
+ return new MapRecipe(mapgen, templateFilter, mazeSize, name, seed, theme, drawData);
+ }
+
public static String formatMapName(Resources res, String map) {
if(map.charAt(0)=='+') {
if(map.equals(MAPNAME_REGULAR)) {
@@ -77,4 +108,95 @@
}
return map;
}
+
+ /**
+ * Returns the mapname corresponding to the map generator (e.g. "+rnd+" for regular maps)
+ * If the mapgen does not have a unique name (MAPGEN_NAMED) or is not known, the def
+ * value is returned.
+ */
+ public static String mapnameForGenerator(int mapgen, String def) {
+ switch(mapgen) {
+ case Frontlib.MAPGEN_REGULAR: return MAPNAME_REGULAR;
+ case Frontlib.MAPGEN_MAZE: return MAPNAME_MAZE;
+ case Frontlib.MAPGEN_DRAWN: return MAPNAME_DRAWN;
+ default: return def;
+ }
+ }
+
+ /**
+ * In a sense this is the inverse of mapnameForGenerator. Returns the mapgen that uses
+ * mapName as special identifier, or MAPGEN_NAMED if there is none.
+ */
+ public static int generatorForMapname(String mapName) {
+ if(MapRecipe.MAPNAME_REGULAR.equals(mapName)) {
+ return Frontlib.MAPGEN_REGULAR;
+ } else if(MapRecipe.MAPNAME_MAZE.equals(mapName)) {
+ return Frontlib.MAPGEN_MAZE;
+ } else if(MapRecipe.MAPNAME_DRAWN.equals(mapName)) {
+ return Frontlib.MAPGEN_DRAWN;
+ } else {
+ return Frontlib.MAPGEN_NAMED;
+ }
+ }
+
+ @Override
+ public String toString() {
+ return "MapRecipe [mapgen=" + mapgen + ", templateFilter="
+ + templateFilter + ", mazeSize=" + mazeSize + ", name=" + name
+ + ", seed=" + seed + ", theme=" + theme + ", drawData="
+ + Arrays.toString(drawData) + "]";
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + Arrays.hashCode(drawData);
+ result = prime * result + mapgen;
+ result = prime * result + mazeSize;
+ result = prime * result + ((name == null) ? 0 : name.hashCode());
+ result = prime * result + ((seed == null) ? 0 : seed.hashCode());
+ result = prime * result + templateFilter;
+ result = prime * result + ((theme == null) ? 0 : theme.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ MapRecipe other = (MapRecipe) obj;
+ if (!Arrays.equals(drawData, other.drawData))
+ return false;
+ if (mapgen != other.mapgen)
+ return false;
+ if (mazeSize != other.mazeSize)
+ return false;
+ if (name == null) {
+ if (other.name != null)
+ return false;
+ } else if (!name.equals(other.name))
+ return false;
+ if (seed == null) {
+ if (other.seed != null)
+ return false;
+ } else if (!seed.equals(other.seed))
+ return false;
+ if (templateFilter != other.templateFilter)
+ return false;
+ if (theme == null) {
+ if (other.theme != null)
+ return false;
+ } else if (!theme.equals(other.theme))
+ return false;
+ return true;
+ }
+
+ public static String makeRandomSeed() {
+ return "{"+UUID.randomUUID().toString()+"}";
+ }
}
--- a/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/Datastructures/MetaScheme.java Sat Aug 18 00:22:33 2012 +0200
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/Datastructures/MetaScheme.java Sat Aug 18 00:47:51 2012 +0200
@@ -4,7 +4,11 @@
import java.util.Collections;
import java.util.List;
+import org.hedgewars.hedgeroid.frontlib.Flib;
+
public final class MetaScheme {
+ public static final MetaScheme INSTANCE = Flib.INSTANCE.flib_get_metascheme().deref();
+
public static final class Mod {
public final String name;
public final int bitmaskIndex;
--- a/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/Datastructures/Player.java Sat Aug 18 00:22:33 2012 +0200
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/Datastructures/Player.java Sat Aug 18 00:47:51 2012 +0200
@@ -1,14 +1,29 @@
package org.hedgewars.hedgeroid.Datastructures;
+import java.util.Comparator;
+
+/**
+ * Basic information about a player on a server.
+ */
public final class Player {
public final String name;
+ public final boolean registered, admin;
- public Player(String name) {
+ public Player(String name, boolean registered, boolean admin) {
this.name = name;
+ this.registered = registered;
+ this.admin = admin;
}
@Override
public String toString() {
- return "Player [name=" + name + "]";
+ return "Player [name=" + name + ", registered=" + registered
+ + ", admin=" + admin + "]";
}
+
+ public static Comparator<Player> NAME_ORDER = new Comparator<Player>() {
+ public int compare(Player lhs, Player rhs) {
+ return lhs.name.compareToIgnoreCase(rhs.name);
+ }
+ };
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/Datastructures/PlayerInRoom.java Sat Aug 18 00:47:51 2012 +0200
@@ -0,0 +1,16 @@
+package org.hedgewars.hedgeroid.Datastructures;
+
+public final class PlayerInRoom {
+ public final Player player;
+ public final boolean ready;
+
+ public PlayerInRoom(Player player, boolean ready) {
+ this.player = player;
+ this.ready = ready;
+ }
+
+ @Override
+ public String toString() {
+ return "PlayerInRoom [player=" + player + ", ready=" + ready + "]";
+ }
+}
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/Datastructures/Room.java Sat Aug 18 00:47:51 2012 +0200
@@ -0,0 +1,36 @@
+package org.hedgewars.hedgeroid.Datastructures;
+
+import android.content.res.Resources;
+
+/**
+ * A room as presented in the roomlist in a server lobby.
+ */
+public final class Room {
+ public final String name, map, scheme, weapons, owner;
+ public final int playerCount, teamCount;
+ public final boolean inProgress;
+
+ public Room(String name, String map, String scheme, String weapons,
+ String owner, int playerCount, int teamCount, boolean inProgress) {
+ this.name = name;
+ this.map = map;
+ this.scheme = scheme;
+ this.weapons = weapons;
+ this.owner = owner;
+ this.playerCount = playerCount;
+ this.teamCount = teamCount;
+ this.inProgress = inProgress;
+ }
+
+ public String formatMapName(Resources res) {
+ return MapRecipe.formatMapName(res, map);
+ }
+
+ @Override
+ public String toString() {
+ return "RoomlistRoom [name=" + name + ", map=" + map + ", scheme="
+ + scheme + ", weapons=" + weapons + ", owner=" + owner
+ + ", playerCount=" + playerCount + ", teamCount=" + teamCount
+ + ", inProgress=" + inProgress + "]";
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/Datastructures/RoomWithId.java Sat Aug 18 00:47:51 2012 +0200
@@ -0,0 +1,24 @@
+package org.hedgewars.hedgeroid.Datastructures;
+
+import java.util.Comparator;
+
+public final class RoomWithId {
+ public final Room room;
+ public final long id;
+
+ public RoomWithId(Room room, long id) {
+ this.room = room;
+ this.id = id;
+ }
+
+ @Override
+ public String toString() {
+ return "RoomWithId [room=" + room + ", id=" + id + "]";
+ }
+
+ public static final Comparator<RoomWithId> NEWEST_FIRST_ORDER = new Comparator<RoomWithId>() {
+ public int compare(RoomWithId lhs, RoomWithId rhs) {
+ return rhs.id<lhs.id ? -1 : rhs.id>lhs.id ? 1 : 0;
+ }
+ };
+}
\ No newline at end of file
--- a/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/Datastructures/RoomlistRoom.java Sat Aug 18 00:22:33 2012 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,33 +0,0 @@
-package org.hedgewars.hedgeroid.Datastructures;
-
-import android.content.res.Resources;
-
-public final class RoomlistRoom {
- public final String name, map, scheme, weapons, owner;
- public final int playerCount, teamCount;
- public final boolean inProgress;
-
- public RoomlistRoom(String name, String map, String scheme, String weapons,
- String owner, int playerCount, int teamCount, boolean inProgress) {
- this.name = name;
- this.map = map;
- this.scheme = scheme;
- this.weapons = weapons;
- this.owner = owner;
- this.playerCount = playerCount;
- this.teamCount = teamCount;
- this.inProgress = inProgress;
- }
-
- public String formatMapName(Resources res) {
- return MapRecipe.formatMapName(res, map);
- }
-
- @Override
- public String toString() {
- return "RoomlistRoom [name=" + name + ", map=" + map + ", scheme="
- + scheme + ", weapons=" + weapons + ", owner=" + owner
- + ", playerCount=" + playerCount + ", teamCount=" + teamCount
- + ", inProgress=" + inProgress + "]";
- }
-}
--- a/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/Datastructures/Scheme.java Sat Aug 18 00:22:33 2012 +0200
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/Datastructures/Scheme.java Sat Aug 18 00:47:51 2012 +0200
@@ -23,15 +23,14 @@
import java.util.Comparator;
import java.util.HashMap;
import java.util.Map;
+import java.util.TreeMap;
public final class Scheme {
- public final MetaScheme metascheme;
public final String name;
public final Map<String, Integer> settings;
public final Map<String, Boolean> mods;
- public Scheme(MetaScheme metascheme, String name, Map<String, Integer> settings, Map<String, Boolean> mods) {
- this.metascheme = metascheme;
+ public Scheme(String name, Map<String, Integer> settings, Map<String, Boolean> mods) {
this.name = name;
this.settings = Collections.unmodifiableMap(new HashMap<String, Integer>(settings));
this.mods = Collections.unmodifiableMap(new HashMap<String, Boolean>(mods));
@@ -42,20 +41,66 @@
return health==null ? 100 : health.intValue();
}
- /*@Override
- public String toString() {
- return "Scheme [metascheme=" + metascheme + ", name=" + name
- + ", settings=" + settings + ", mods=" + mods + "]";
- }*/
+ public static Scheme createDefaultScheme(MetaScheme meta) {
+ String name = GameConfig.DEFAULT_SCHEME;
+ Map<String, Integer> settings = new TreeMap<String, Integer>();
+ Map<String, Boolean> mods = new TreeMap<String, Boolean>();
+ for(MetaScheme.Setting setting : meta.settings) {
+ settings.put(setting.name, setting.def);
+ }
+ for(MetaScheme.Mod mod : meta.mods) {
+ mods.put(mod.name, Boolean.FALSE);
+ }
+ return new Scheme(name, settings, mods);
+ }
@Override
public String toString() {
- return name; // TODO change back once StartGameActivity does not need this anymore
+ return "Scheme [name=" + name + ", settings=" + settings + ", mods="
+ + mods + "]";
}
- public static final Comparator<Scheme> caseInsensitiveNameComparator = new Comparator<Scheme>() {
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((name == null) ? 0 : name.hashCode());
+ result = prime * result + ((mods == null) ? 0 : mods.hashCode());
+ result = prime * result
+ + ((settings == null) ? 0 : settings.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ Scheme other = (Scheme) obj;
+ if (name == null) {
+ if (other.name != null)
+ return false;
+ } else if (!name.equals(other.name))
+ return false;
+ if (mods == null) {
+ if (other.mods != null)
+ return false;
+ } else if (!mods.equals(other.mods))
+ return false;
+ if (settings == null) {
+ if (other.settings != null)
+ return false;
+ } else if (!settings.equals(other.settings))
+ return false;
+ return true;
+ }
+
+ public static final Comparator<Scheme> NAME_ORDER = new Comparator<Scheme>() {
public int compare(Scheme lhs, Scheme rhs) {
- return lhs.name.compareToIgnoreCase(rhs.name);
+ return String.CASE_INSENSITIVE_ORDER.compare(lhs.name, rhs.name);
}
};
}
\ No newline at end of file
--- a/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/Datastructures/Schemes.java Sat Aug 18 00:22:33 2012 +0200
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/Datastructures/Schemes.java Sat Aug 18 00:47:51 2012 +0200
@@ -3,14 +3,9 @@
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
-import java.util.Collections;
import java.util.List;
-import java.util.Map;
-import java.util.TreeMap;
-import org.hedgewars.hedgeroid.Utils;
import org.hedgewars.hedgeroid.frontlib.Flib;
-import org.hedgewars.hedgeroid.frontlib.Frontlib.MetaschemePtr;
import org.hedgewars.hedgeroid.frontlib.Frontlib.SchemelistPtr;
import android.content.Context;
@@ -32,57 +27,49 @@
return new File(c.getFilesDir(), "schemes_builtin.ini");
}
- public static Map<String, Scheme> loadAllSchemes(Context c) throws IOException {
- Map<String, Scheme> result = loadUserSchemes(c);
- result.putAll(loadBuiltinSchemes(c));
+ public static List<Scheme> loadAllSchemes(Context c) throws IOException {
+ List<Scheme> result = loadBuiltinSchemes(c);
+ result.addAll(loadUserSchemes(c));
return result;
}
- public static Map<String, Scheme> loadUserSchemes(Context c) throws IOException {
+ public static List<Scheme> loadUserSchemes(Context c) throws IOException {
return loadSchemes(c, getUserSchemesFile(c));
}
- public static Map<String, Scheme> loadBuiltinSchemes(Context c) throws IOException {
+ public static List<Scheme> loadBuiltinSchemes(Context c) throws IOException {
return loadSchemes(c, getBuiltinSchemesFile(c));
}
- public static Map<String, Scheme> loadSchemes(Context c, File schemeFile) throws IOException {
- Map<String, Scheme> result = new TreeMap<String, Scheme>();
- String metaschemePath = new File(Utils.getDataPathFile(c), "metasettings.ini").getAbsolutePath();
+ public static List<Scheme> loadSchemes(Context c, File schemeFile) throws IOException {
if(!schemeFile.isFile()) {
// No schemes file == no schemes, no error
- return new TreeMap<String, Scheme>();
+ return new ArrayList<Scheme>();
}
- MetaschemePtr meta = null;
SchemelistPtr schemeListPtr = null;
try {
- meta = Flib.INSTANCE.flib_metascheme_from_ini(metaschemePath);
- if(meta==null) {
- throw new IOException("Unable to read metascheme");
- }
- schemeListPtr = Flib.INSTANCE.flib_schemelist_from_ini(meta, schemeFile.getAbsolutePath());
+ schemeListPtr = Flib.INSTANCE.flib_schemelist_from_ini(schemeFile.getAbsolutePath());
if(schemeListPtr == null) {
throw new IOException("Unable to read schemelist");
}
- List<Scheme> schemeList = schemeListPtr.deref();
- for(Scheme scheme : schemeList) {
- result.put(scheme.name, scheme);
- }
- return result;
+ return schemeListPtr.deref();
} finally {
if(schemeListPtr != null) {
Flib.INSTANCE.flib_schemelist_destroy(schemeListPtr);
}
- if(meta != null) {
- Flib.INSTANCE.flib_metascheme_release(meta);
- }
}
}
- public static void saveUserSchemes(Context c, Map<String, Scheme> schemes) throws IOException {
- List<Scheme> schemeList = new ArrayList<Scheme>(schemes.values());
- Collections.sort(schemeList, Scheme.caseInsensitiveNameComparator);
- SchemelistPtr ptr = SchemelistPtr.createJavaOwned(schemeList);
+ public static void saveUserSchemes(Context c, List<Scheme> schemes) throws IOException {
+ SchemelistPtr ptr = SchemelistPtr.createJavaOwned(schemes);
Flib.INSTANCE.flib_schemelist_to_ini(getUserSchemesFile(c).getAbsolutePath(), ptr);
}
+
+ public static List<String> toNameList(List<Scheme> schemes) {
+ List<String> result = new ArrayList<String>();
+ for(Scheme scheme : schemes) {
+ result.add(scheme.name);
+ }
+ return result;
+ }
}
--- a/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/Datastructures/Team.java Sat Aug 18 00:22:33 2012 +0200
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/Datastructures/Team.java Sat Aug 18 00:47:51 2012 +0200
@@ -25,10 +25,10 @@
import java.util.Comparator;
import java.util.List;
-import org.hedgewars.hedgeroid.Utils;
import org.hedgewars.hedgeroid.EngineProtocol.PascalExports;
import org.hedgewars.hedgeroid.frontlib.Flib;
import org.hedgewars.hedgeroid.frontlib.Frontlib.TeamPtr;
+import org.hedgewars.hedgeroid.util.FileUtils;
import android.content.Context;
@@ -72,7 +72,7 @@
}
public static File getTeamfileByName(Context c, String teamName) {
- return new File(new File(c.getFilesDir(), DIRECTORY_TEAMS), Utils.replaceBadChars(teamName)+".hwt");
+ return new File(new File(c.getFilesDir(), DIRECTORY_TEAMS), FileUtils.replaceBadChars(teamName)+".hwt");
}
@Override
--- a/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/Datastructures/TeamInGame.java Sat Aug 18 00:22:33 2012 +0200
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/Datastructures/TeamInGame.java Sat Aug 18 00:47:51 2012 +0200
@@ -1,5 +1,8 @@
package org.hedgewars.hedgeroid.Datastructures;
+import java.util.Collection;
+import java.util.Comparator;
+
/**
* A team with per-game configuration. This is similar to the frontlib "team" structure,
* except that it does not include weaponset and initial health, which are handled on a
@@ -17,4 +20,20 @@
public TeamInGame withAttribs(TeamIngameAttributes attribs) {
return new TeamInGame(team, attribs);
}
+
+ public static int getUnusedOrRandomColorIndex(Collection<TeamInGame> teams) {
+ int[] illegalColors = new int[teams.size()];
+ int i=0;
+ for(TeamInGame team : teams) {
+ illegalColors[i] = team.ingameAttribs.colorIndex;
+ i++;
+ }
+ return TeamIngameAttributes.randomColorIndex(illegalColors);
+ }
+
+ public static Comparator<TeamInGame> NAME_ORDER = new Comparator<TeamInGame>() {
+ public int compare(TeamInGame lhs, TeamInGame rhs) {
+ return Team.NAME_ORDER.compare(lhs.team, rhs.team);
+ }
+ };
}
--- a/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/Datastructures/TeamIngameAttributes.java Sat Aug 18 00:22:33 2012 +0200
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/Datastructures/TeamIngameAttributes.java Sat Aug 18 00:47:51 2012 +0200
@@ -28,7 +28,7 @@
this.remoteDriven = remoteDriven;
}
- public static int randomColorIndex(int[] illegalColors){
+ public static int randomColorIndex(int[] illegalColors) {
Random rnd = new Random();
ArrayList<Integer> legalcolors = new ArrayList<Integer>();
for(int i=0; i<TEAM_COLORS.length; i++) {
--- a/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/Datastructures/Weaponset.java Sat Aug 18 00:22:33 2012 +0200
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/Datastructures/Weaponset.java Sat Aug 18 00:47:51 2012 +0200
@@ -1,5 +1,7 @@
package org.hedgewars.hedgeroid.Datastructures;
+import java.util.Comparator;
+
import org.hedgewars.hedgeroid.frontlib.Flib;
public final class Weaponset {
@@ -17,6 +19,65 @@
@Override
public String toString() {
- return name; // TODO use the generated one once StartGameActivity doesn't need this anymore
+ return "Weaponset [name=" + name + ", loadout=" + loadout
+ + ", crateProb=" + crateProb + ", crateAmmo=" + crateAmmo
+ + ", delay=" + delay + "]";
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result
+ + ((crateAmmo == null) ? 0 : crateAmmo.hashCode());
+ result = prime * result
+ + ((crateProb == null) ? 0 : crateProb.hashCode());
+ result = prime * result + ((delay == null) ? 0 : delay.hashCode());
+ result = prime * result + ((loadout == null) ? 0 : loadout.hashCode());
+ result = prime * result + ((name == null) ? 0 : name.hashCode());
+ return result;
}
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ Weaponset other = (Weaponset) obj;
+ if (crateAmmo == null) {
+ if (other.crateAmmo != null)
+ return false;
+ } else if (!crateAmmo.equals(other.crateAmmo))
+ return false;
+ if (crateProb == null) {
+ if (other.crateProb != null)
+ return false;
+ } else if (!crateProb.equals(other.crateProb))
+ return false;
+ if (delay == null) {
+ if (other.delay != null)
+ return false;
+ } else if (!delay.equals(other.delay))
+ return false;
+ if (loadout == null) {
+ if (other.loadout != null)
+ return false;
+ } else if (!loadout.equals(other.loadout))
+ return false;
+ if (name == null) {
+ if (other.name != null)
+ return false;
+ } else if (!name.equals(other.name))
+ return false;
+ return true;
+ }
+
+ public static Comparator<Weaponset> NAME_ORDER = new Comparator<Weaponset>() {
+ public int compare(Weaponset lhs, Weaponset rhs) {
+ return String.CASE_INSENSITIVE_ORDER.compare(lhs.name, rhs.name);
+ }
+ };
}
--- a/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/Datastructures/Weaponsets.java Sat Aug 18 00:22:33 2012 +0200
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/Datastructures/Weaponsets.java Sat Aug 18 00:47:51 2012 +0200
@@ -3,6 +3,7 @@
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
+import java.util.Iterator;
import java.util.List;
import org.hedgewars.hedgeroid.frontlib.Flib;
@@ -60,4 +61,24 @@
WeaponsetListPtr ptr = WeaponsetListPtr.createJavaOwned(weaponsets);
Flib.INSTANCE.flib_weaponsetlist_to_ini(getUserWeaponsetsFile(c).getAbsolutePath(), ptr);
}
+
+ public static void deleteUserWeaponset(Context c, String setToDelete) throws IOException {
+ List<Weaponset> userWeaponsets = loadUserWeaponsets(c);
+ for(Iterator<Weaponset> iter = userWeaponsets.iterator(); iter.hasNext();) {
+ Weaponset set = iter.next();
+ if(set.name.equals(setToDelete)) {
+ iter.remove();
+ break;
+ }
+ }
+ saveUserWeaponsets(c, userWeaponsets);
+ }
+
+ public static List<String> toNameList(List<Weaponset> weaponsets) {
+ List<String> result = new ArrayList<String>();
+ for(Weaponset weaponset : weaponsets) {
+ result.add(weaponset.name);
+ }
+ return result;
+ }
}
--- a/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/Downloader/DownloadAssets.java Sat Aug 18 00:22:33 2012 +0200
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/Downloader/DownloadAssets.java Sat Aug 18 00:47:51 2012 +0200
@@ -6,10 +6,10 @@
import org.hedgewars.hedgeroid.MainActivity;
import org.hedgewars.hedgeroid.R;
-import org.hedgewars.hedgeroid.Utils;
import org.hedgewars.hedgeroid.Datastructures.Schemes;
import org.hedgewars.hedgeroid.Datastructures.Team;
import org.hedgewars.hedgeroid.Datastructures.Weaponsets;
+import org.hedgewars.hedgeroid.util.FileUtils;
import android.content.res.AssetManager;
import android.os.AsyncTask;
@@ -25,7 +25,7 @@
private void copyFileOrDir(AssetManager assetManager, File target, String assetPath) throws IOException {
try {
- Utils.writeStreamToFile(assetManager.open(assetPath), target);
+ FileUtils.writeStreamToFile(assetManager.open(assetPath), target);
} catch(FileNotFoundException e) {
/*
* I can't find a better way to figure out whether an asset entry is
@@ -44,11 +44,11 @@
@Override
protected Boolean doInBackground(Object... params) {
try {
- Utils.writeStreamToFile(act.getResources().openRawResource(R.raw.schemes_builtin), Schemes.getBuiltinSchemesFile(act));
- Utils.writeStreamToFile(act.getResources().openRawResource(R.raw.weapons_builtin), Weaponsets.getBuiltinWeaponsetsFile(act));
- Utils.resRawToFilesDir(act, R.array.teams, Team.DIRECTORY_TEAMS);
- copyFileOrDir(act.getAssets(), Utils.getDataPathFile(act), "Data");
- copyFileOrDir(act.getAssets(), new File(Utils.getCachePath(act), VERSION_FILENAME), VERSION_FILENAME);
+ FileUtils.writeStreamToFile(act.getResources().openRawResource(R.raw.schemes_builtin), Schemes.getBuiltinSchemesFile(act));
+ FileUtils.writeStreamToFile(act.getResources().openRawResource(R.raw.weapons_builtin), Weaponsets.getBuiltinWeaponsetsFile(act));
+ FileUtils.resRawToFilesDir(act, R.array.teams, R.array.teamFilenames, Team.DIRECTORY_TEAMS);
+ copyFileOrDir(act.getAssets(), FileUtils.getDataPathFile(act), "Data");
+ copyFileOrDir(act.getAssets(), new File(FileUtils.getCachePath(act), VERSION_FILENAME), VERSION_FILENAME);
return Boolean.TRUE;
} catch(IOException e) {
Log.e("DownloadAssets", e.getMessage(), e);
--- a/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/Downloader/DownloadPackage.java Sat Aug 18 00:22:33 2012 +0200
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/Downloader/DownloadPackage.java Sat Aug 18 00:47:51 2012 +0200
@@ -20,7 +20,7 @@
import java.io.IOException;
-import org.hedgewars.hedgeroid.Utils;
+import org.hedgewars.hedgeroid.util.FileUtils;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -136,7 +136,7 @@
version = -1;
}
}else if(name.equals("path")){
- path = Utils.getDataPath(c) + text;
+ path = FileUtils.getDataPath(c) + text;
}else if(name.equals("representation")){
representation = text;
}else if(name.equals("description")){
--- a/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/EngineProtocol/PascalExports.java Sat Aug 18 00:22:33 2012 +0200
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/EngineProtocol/PascalExports.java Sat Aug 18 00:47:51 2012 +0200
@@ -32,5 +32,8 @@
}
public static native int HWgetMaxNumberOfTeams();
- public static native int HWterminate(boolean b);
+ public static native int HWterminate(boolean b);
+ public static native int HWGenLandPreview(int port);
+
+ public static Object engineMutex = new Object();
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/GameConnection.java Sat Aug 18 00:47:51 2012 +0200
@@ -0,0 +1,214 @@
+package org.hedgewars.hedgeroid;
+
+import org.hedgewars.hedgeroid.Datastructures.GameConfig;
+import org.hedgewars.hedgeroid.frontlib.Flib;
+import org.hedgewars.hedgeroid.frontlib.Frontlib;
+import org.hedgewars.hedgeroid.frontlib.Frontlib.BytesCallback;
+import org.hedgewars.hedgeroid.frontlib.Frontlib.GameSetupPtr;
+import org.hedgewars.hedgeroid.frontlib.Frontlib.GameconnPtr;
+import org.hedgewars.hedgeroid.frontlib.Frontlib.IntCallback;
+import org.hedgewars.hedgeroid.frontlib.Frontlib.StrBoolCallback;
+import org.hedgewars.hedgeroid.frontlib.Frontlib.StrCallback;
+import org.hedgewars.hedgeroid.frontlib.Frontlib.VoidCallback;
+import org.hedgewars.hedgeroid.netplay.GameMessageListener;
+import org.hedgewars.hedgeroid.netplay.Netplay;
+import org.hedgewars.hedgeroid.util.TickHandler;
+
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Looper;
+import android.util.Log;
+
+import com.sun.jna.Memory;
+import com.sun.jna.NativeLong;
+import com.sun.jna.Pointer;
+
+public final class GameConnection {
+ private static final Handler mainHandler = new Handler(Looper.getMainLooper());
+
+ private final HandlerThread thread;
+ private final Handler handler;
+ private final TickHandler tickHandler;
+ private final Netplay netplay; // ==null if not a netgame
+ private GameconnPtr conn;
+
+ /**
+ * The actual connection has to be set up on a separate thread because networking
+ * is not allowed on the UI thread, so the port can't be queried immediately after
+ * creating the GameConnection object. Instead, one of these interface methods is
+ * called once we know which port we are listening on (or once we fail to set this up).
+ * Methods will be called on the UI thread.
+ */
+ public static interface Listener {
+ /**
+ * We are listening for the engine at $port, go start the engine.
+ */
+ void gameConnectionReady(int port);
+
+ /**
+ * The connection has stopped, either because the game has ended or was interrupted,
+ * or maybe we failed to create the connection at all (in that case gameConnectionReady wasn't called).
+ */
+ void gameConnectionDisconnected(int reason);
+ }
+
+ private GameConnection(Netplay netplay) {
+ this.netplay = netplay;
+ thread = new HandlerThread("IPCThread");
+ thread.start();
+ handler = new Handler(thread.getLooper());
+ tickHandler = new TickHandler(thread.getLooper(), 50, new Runnable() {
+ public void run() {
+ if(conn != null) {
+ Flib.INSTANCE.flib_gameconn_tick(conn);
+ }
+ }
+ });
+ tickHandler.start();
+ }
+
+ public static GameConnection forNetgame(final GameConfig config, Netplay netplay, final Listener listener) {
+ final GameConnection result = new GameConnection(netplay);
+ final String playerName = netplay.getPlayerName();
+ result.handler.post(new Runnable() {
+ public void run() {
+ GameconnPtr conn = Flib.INSTANCE.flib_gameconn_create(playerName, GameSetupPtr.createJavaOwned(config), true);
+ result.setupConnection(conn, true, listener);
+ }
+ });
+ return result;
+ }
+
+ public static GameConnection forLocalGame(final GameConfig config, final Listener listener) {
+ final GameConnection result = new GameConnection(null);
+ result.handler.post(new Runnable() {
+ public void run() {
+ GameconnPtr conn = Flib.INSTANCE.flib_gameconn_create("Player", GameSetupPtr.createJavaOwned(config), false);
+ result.setupConnection(conn, false, listener);
+ }
+ });
+ return result;
+ }
+
+ // runs on the IPCThread
+ private void setupConnection(GameconnPtr conn, final boolean netgame, final Listener listener) {
+ if(conn == null) {
+ mainHandler.post(new Runnable() {
+ public void run() { listener.gameConnectionDisconnected(Frontlib.GAME_END_ERROR); }
+ });
+ shutdown();
+ } else {
+ this.conn = conn;
+ final int port = Flib.INSTANCE.flib_gameconn_getport(conn);
+ mainHandler.post(new Runnable() {
+ public void run() {
+ listener.gameConnectionReady(port);
+ if(netgame) {
+ netplay.registerGameMessageListener(gameMessageListener);
+ }
+ }
+ });
+ Flib.INSTANCE.flib_gameconn_onConnect(conn, connectCb, null);
+ Flib.INSTANCE.flib_gameconn_onDisconnect(conn, disconnectCb, null);
+ Flib.INSTANCE.flib_gameconn_onErrorMessage(conn, errorMessageCb, null);
+ if(netgame) {
+ Flib.INSTANCE.flib_gameconn_onChat(conn, chatCb, null);
+ Flib.INSTANCE.flib_gameconn_onEngineMessage(conn, engineMessageCb, null);
+ }
+ }
+ }
+
+ // runs on the IPCThread
+ private void shutdown() {
+ tickHandler.stop();
+ thread.quit();
+ Flib.INSTANCE.flib_gameconn_destroy(conn);
+ if(netplay != null) {
+ mainHandler.post(new Runnable() {
+ public void run() {
+ netplay.unregisterGameMessageListener(gameMessageListener);
+ }
+ });
+ }
+ }
+
+ // runs on the IPCThread
+ private final StrBoolCallback chatCb = new StrBoolCallback() {
+ public void callback(Pointer context, String message, boolean teamChat) {
+ if(teamChat) {
+ netplay.sendTeamChat(message);
+ } else {
+ netplay.sendChat(message);
+ }
+ }
+ };
+
+ // runs on the IPCThread
+ private final VoidCallback connectCb = new VoidCallback() {
+ public void callback(Pointer context) {
+ Log.i("GameConnection", "Connected");
+ }
+ };
+
+ // runs on the IPCThread
+ private final IntCallback disconnectCb = new IntCallback() {
+ public void callback(Pointer context, int reason) {
+ if(netplay != null) {
+ netplay.sendRoundFinished(reason==Frontlib.GAME_END_FINISHED);
+ }
+ shutdown();
+ }
+ };
+
+ // runs on the IPCThread
+ private final BytesCallback engineMessageCb = new BytesCallback() {
+ public void callback(Pointer context, Pointer buffer, NativeLong size) {
+ netplay.sendEngineMessage(buffer.getByteArray(0, size.intValue()));
+ }
+ };
+
+ // runs on the IPCThread
+ private final StrCallback errorMessageCb = new StrCallback() {
+ public void callback(Pointer context, String message) {
+ Log.e("GameConnection", message);
+ }
+ };
+
+ // runs on any thread
+ private final GameMessageListener gameMessageListener = new GameMessageListener() {
+ public void onNetDisconnected() {
+ handler.post(new Runnable() {
+ public void run() {
+ shutdown();
+ }
+ });
+ }
+
+ public void onMessage(final int type, final String message) {
+ handler.post(new Runnable() {
+ public void run() {
+ Flib.INSTANCE.flib_gameconn_send_textmsg(conn, type, message);
+ }
+ });
+ }
+
+ public void onEngineMessage(final byte[] em) {
+ handler.post(new Runnable() {
+ public void run() {
+ Memory mem = new Memory(em.length);
+ mem.write(0, em, 0, em.length);
+ Flib.INSTANCE.flib_gameconn_send_enginemsg(conn, mem, new NativeLong(em.length));
+ }
+ });
+
+ }
+
+ public void onChatMessage(final String nick, final String message) {
+ handler.post(new Runnable() {
+ public void run() {
+ Flib.INSTANCE.flib_gameconn_send_chatmsg(conn, nick, message);
+ }
+ });
+ }
+ };
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/LobbyActivity.java Sat Aug 18 00:47:51 2012 +0200
@@ -0,0 +1,140 @@
+package org.hedgewars.hedgeroid;
+
+import org.hedgewars.hedgeroid.R;
+import org.hedgewars.hedgeroid.NetplayStateFragment.NetplayStateListener;
+import org.hedgewars.hedgeroid.netplay.Netplay;
+import org.hedgewars.hedgeroid.netplay.Netplay.State;
+import org.hedgewars.hedgeroid.util.TextInputDialog;
+import org.hedgewars.hedgeroid.util.TextInputDialog.TextInputDialogListener;
+
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.drawable.Drawable;
+import android.os.Bundle;
+import android.support.v4.app.FragmentActivity;
+import android.support.v4.app.FragmentTransaction;
+import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.View;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.TabHost;
+import android.widget.TextView;
+
+public class LobbyActivity extends FragmentActivity implements TextInputDialogListener, NetplayStateListener {
+ private static final int DIALOG_CREATE_ROOM = 0;
+
+ private TabHost tabHost;
+ private Netplay netplay;
+
+ @Override
+ protected void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+
+ setContentView(R.layout.activity_lobby);
+ ChatFragment chatFragment = (ChatFragment)getSupportFragmentManager().findFragmentById(R.id.chatFragment);
+ chatFragment.setInRoom(false);
+
+ FragmentTransaction trans = getSupportFragmentManager().beginTransaction();
+ trans.add(new NetplayStateFragment(), "netplayFragment");
+ trans.commit();
+
+ netplay = Netplay.getAppInstance(getApplicationContext());
+
+ tabHost = (TabHost)findViewById(android.R.id.tabhost);
+ if(tabHost != null) {
+ tabHost.setup();
+ tabHost.getTabWidget().setOrientation(LinearLayout.VERTICAL);
+
+ tabHost.addTab(tabHost.newTabSpec("rooms").setIndicator(createIndicatorView(tabHost, R.string.lobby_tab_rooms, getResources().getDrawable(R.drawable.roomlist_ingame))).setContent(R.id.roomListFragment));
+ tabHost.addTab(tabHost.newTabSpec("chat").setIndicator(createIndicatorView(tabHost, R.string.lobby_tab_chat, getResources().getDrawable(R.drawable.edit))).setContent(R.id.chatFragment));
+ tabHost.addTab(tabHost.newTabSpec("players").setIndicator(createIndicatorView(tabHost, R.string.lobby_tab_players, getResources().getDrawable(R.drawable.human))).setContent(R.id.playerListFragment));
+
+ if (icicle != null) {
+ tabHost.setCurrentTabByTag(icicle.getString("currentTab"));
+ }
+ }
+ }
+
+ private View createIndicatorView(TabHost tabHost, int label, Drawable icon) {
+ LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+
+ View tabIndicator = inflater.inflate(R.layout.tab_indicator,
+ tabHost.getTabWidget(), // tab widget is the parent
+ false); // no inflate params
+
+ final TextView tv = (TextView) tabIndicator.findViewById(R.id.title);
+ tv.setText(label);
+
+ if(icon != null) {
+ final ImageView iconView = (ImageView) tabIndicator.findViewById(R.id.icon);
+ iconView.setImageDrawable(icon);
+ }
+
+ return tabIndicator;
+ }
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ super.onCreateOptionsMenu(menu);
+ getMenuInflater().inflate(R.menu.lobby_options, menu);
+ return true;
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ switch(item.getItemId()) {
+ case R.id.room_create:
+ TextInputDialog dialog = new TextInputDialog(DIALOG_CREATE_ROOM, R.string.dialog_create_room_title, 0, R.string.dialog_create_room_hint);
+ dialog.show(getSupportFragmentManager(), "create_room_dialog");
+ return true;
+ case R.id.disconnect:
+ netplay.disconnect();
+ return true;
+ default:
+ return super.onOptionsItemSelected(item);
+ }
+ }
+
+ @Override
+ public void onBackPressed() {
+ super.onBackPressed();
+ netplay.disconnect();
+ }
+
+ @Override
+ protected void onSaveInstanceState(Bundle icicle) {
+ super.onSaveInstanceState(icicle);
+ if(tabHost != null) {
+ icicle.putString("currentTab", tabHost.getCurrentTabTag());
+ }
+ }
+
+ public void onTextInputDialogSubmitted(int dialogId, String text) {
+ if(text != null && text.length()>0) {
+ netplay.sendCreateRoom(text);
+ }
+ }
+
+ public void onTextInputDialogCancelled(int dialogId) {
+ }
+
+ public void onNetplayStateChanged(State newState) {
+ switch(newState) {
+ case CONNECTING:
+ case NOT_CONNECTED:
+ finish();
+ break;
+ case ROOM:
+ case INGAME:
+ startActivity(new Intent(getApplicationContext(), RoomActivity.class));
+ break;
+ case LOBBY:
+ // Do nothing
+ break;
+ default:
+ throw new IllegalStateException("Unknown connection state: "+newState);
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/LobbyPlayerlistAdapter.java Sat Aug 18 00:47:51 2012 +0200
@@ -0,0 +1,32 @@
+package org.hedgewars.hedgeroid;
+
+import java.util.Comparator;
+
+import org.hedgewars.hedgeroid.R;
+import org.hedgewars.hedgeroid.Datastructures.Player;
+import org.hedgewars.hedgeroid.util.ObservableTreeMapAdapter;
+
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+public class LobbyPlayerlistAdapter extends ObservableTreeMapAdapter<String, Player> {
+ @Override
+ protected Comparator<Player> getEntryOrder() {
+ return Player.NAME_ORDER;
+ }
+
+ public View getView(int position, View convertView, ViewGroup parent) {
+ View v = convertView;
+ if (v == null) {
+ LayoutInflater vi = LayoutInflater.from(parent.getContext());
+ v = vi.inflate(R.layout.listview_player, null);
+ }
+
+ String player = getItem(position).name;
+ TextView username = (TextView) v.findViewById(android.R.id.text1);
+ username.setText(player);
+ return v;
+ }
+}
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/LobbyPlayerlistFragment.java Sat Aug 18 00:47:51 2012 +0200
@@ -0,0 +1,75 @@
+package org.hedgewars.hedgeroid;
+
+import org.hedgewars.hedgeroid.R;
+import org.hedgewars.hedgeroid.Datastructures.Player;
+import org.hedgewars.hedgeroid.netplay.Netplay;
+
+import android.os.Bundle;
+import android.support.v4.app.ListFragment;
+import android.view.ContextMenu;
+import android.view.ContextMenu.ContextMenuInfo;
+import android.view.LayoutInflater;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.AdapterView.AdapterContextMenuInfo;
+
+public class LobbyPlayerlistFragment extends ListFragment {
+ private Netplay netplay;
+ private LobbyPlayerlistAdapter adapter;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ netplay = Netplay.getAppInstance(getActivity().getApplicationContext());
+ adapter = new LobbyPlayerlistAdapter();
+ adapter.setSource(netplay.lobbyPlayerlist);
+ setListAdapter(adapter);
+ }
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ adapter.invalidate();
+ }
+
+ @Override
+ public void onActivityCreated(Bundle savedInstanceState) {
+ super.onActivityCreated(savedInstanceState);
+ registerForContextMenu(getListView());
+ }
+
+ @Override
+ public void onCreateContextMenu(ContextMenu menu, View v,
+ ContextMenuInfo menuInfo) {
+ super.onCreateContextMenu(menu, v, menuInfo);
+ AdapterContextMenuInfo info = (AdapterContextMenuInfo)menuInfo;
+ MenuInflater inflater = getActivity().getMenuInflater();
+ inflater.inflate(R.menu.lobby_playerlist_context, menu);
+ menu.setHeaderIcon(R.drawable.human);
+ menu.setHeaderTitle(adapter.getItem(info.position).name);
+ }
+
+ @Override
+ public boolean onContextItemSelected(MenuItem item) {
+ AdapterContextMenuInfo info = (AdapterContextMenuInfo)item.getMenuInfo();
+ Player player = adapter.getItem(info.position);
+ switch(item.getItemId()) {
+ case R.id.player_info:
+ netplay.sendPlayerInfoQuery(player.name);
+ return true;
+ case R.id.player_follow:
+ netplay.sendFollowPlayer(player.name);
+ return true;
+ default:
+ return super.onContextItemSelected(item);
+ }
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ return inflater.inflate(R.layout.fragment_playerlist, container, false);
+ }
+}
--- a/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/MainActivity.java Sat Aug 18 00:22:33 2012 +0200
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/MainActivity.java Sat Aug 18 00:47:51 2012 +0200
@@ -25,9 +25,9 @@
import org.hedgewars.hedgeroid.Downloader.DownloadAssets;
import org.hedgewars.hedgeroid.Downloader.DownloadListActivity;
import org.hedgewars.hedgeroid.frontlib.Flib;
-import org.hedgewars.hedgeroid.netplay.LobbyActivity;
import org.hedgewars.hedgeroid.netplay.Netplay;
import org.hedgewars.hedgeroid.netplay.Netplay.State;
+import org.hedgewars.hedgeroid.util.FileUtils;
import android.app.AlertDialog;
import android.app.Dialog;
@@ -65,19 +65,19 @@
startLocalGame.setOnClickListener(startGameListener);
startNetGame.setOnClickListener(startNetGameListener);
- if(!Utils.isDataPathAvailable()){
+ if(!FileUtils.isDataPathAvailable()){
showDialog(DIALOG_NO_SDCARD);
} else {
String existingVersion = "";
try {
- File versionFile = new File(Utils.getCachePath(this), "assetsversion.txt");
- existingVersion = Utils.readToString(new FileInputStream(versionFile));
+ File versionFile = new File(FileUtils.getCachePath(this), "assetsversion.txt");
+ existingVersion = FileUtils.readToString(new FileInputStream(versionFile));
} catch(IOException e) {
}
String newVersion = "";
try {
- newVersion = Utils.readToString(getAssets().open("assetsversion.txt"));
+ newVersion = FileUtils.readToString(getAssets().open("assetsversion.txt"));
} catch(IOException e) {
}
@@ -125,23 +125,14 @@
case R.id.preferences:
Toast.makeText(this, R.string.not_implemented_yet, Toast.LENGTH_SHORT).show();
return true;
+ case R.id.edit_weaponsets:
+ startActivity(new Intent(getApplicationContext(), WeaponsetListActivity.class));
+ return true;
default:
return super.onOptionsItemSelected(item);
}
}
- @Override
- protected void onStart() {
- super.onStart();
- Netplay.getAppInstance(getApplicationContext()).requestFastTicks();
- }
-
- @Override
- protected void onStop() {
- super.onStop();
- Netplay.getAppInstance(getApplicationContext()).unrequestFastTicks();
- }
-
public Dialog onCreateDialog(int id, Bundle args){
switch(id) {
case DIALOG_NO_SDCARD:
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/MapFragment.java Sat Aug 18 00:47:51 2012 +0200
@@ -0,0 +1,279 @@
+package org.hedgewars.hedgeroid;
+
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Random;
+
+import org.hedgewars.hedgeroid.R;
+import org.hedgewars.hedgeroid.Datastructures.FrontendDataUtils;
+import org.hedgewars.hedgeroid.Datastructures.MapFile;
+import org.hedgewars.hedgeroid.Datastructures.MapRecipe;
+import org.hedgewars.hedgeroid.Datastructures.Scheme;
+import org.hedgewars.hedgeroid.Datastructures.Weaponset;
+import org.hedgewars.hedgeroid.frontlib.Frontlib;
+
+import android.content.Context;
+import android.graphics.drawable.Drawable;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.support.v4.app.Fragment;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.view.ViewGroup;
+import android.widget.AdapterView;
+import android.widget.AdapterView.OnItemSelectedListener;
+import android.widget.ArrayAdapter;
+import android.widget.ImageView;
+import android.widget.Spinner;
+import android.widget.TableRow;
+import android.widget.Toast;
+
+public class MapFragment extends Fragment implements RoomStateManager.Observer {
+ private Spinner mapTypeSpinner, mapNameSpinner, templateSpinner, mazeSizeSpinner;
+ private TableRow nameRow, templateRow, mazeSizeRow;
+ private ImageView mapPreview;
+ private List<MapFile> mapFiles;
+ private RoomStateManager stateManager;
+ private Random random = new Random();
+ private CalmDownHandler mapPreviewHandler;
+
+ /*
+ * Rendering the preview can take a few seconds on Android, so we want to prevent preview
+ * requests from queueing up if maps are changed quickly. So if there is already a preview
+ * being generated, we store our latest request in the newPreviewRequest variable instead.
+ * Once the current preview is finished generating it will start on that one.
+ */
+ private boolean previewGenerationInProgress;
+ private MapRecipe newPreviewRequest;
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
+ View v = inflater.inflate(R.layout.fragment_map, container, false);
+
+ final Context appContext = getActivity().getApplicationContext();
+ mapPreviewHandler = new CalmDownHandler(getActivity().getMainLooper(), new Runnable() {
+ public void run() {
+ if(!previewGenerationInProgress) {
+ mapPreview.setImageResource(R.drawable.roomlist_preparing);
+ MapPreviewGenerator.startPreviewGeneration(appContext, stateManager.getMapRecipe(), mapPreviewListener);
+ previewGenerationInProgress = true;
+ } else {
+ newPreviewRequest = stateManager.getMapRecipe();
+ }
+ }
+ }, 250);
+
+ nameRow = (TableRow) v.findViewById(R.id.rowMapName);
+ templateRow = (TableRow) v.findViewById(R.id.rowTemplateFilter);
+ mazeSizeRow = (TableRow) v.findViewById(R.id.rowMazeSize);
+ mapPreview = (ImageView) v.findViewById(R.id.mapPreview);
+ mapPreview.setImageDrawable(null);;
+ mapPreview.setOnClickListener(mapClickListener);
+
+ try {
+ mapFiles = FrontendDataUtils.getMaps(getActivity());
+ } catch (IOException e) {
+ Toast.makeText(getActivity().getApplicationContext(), R.string.error_missing_sdcard_or_files, Toast.LENGTH_LONG).show();
+ getActivity().finish();
+ }
+ Collections.sort(mapFiles, MapFile.MISSIONS_FIRST_NAME_ORDER);
+
+ List<String> mapNames = MapFile.toDisplayNameList(mapFiles, getResources());
+ mapTypeSpinner = prepareSpinner(v, R.id.spinMapType, Arrays.asList(getResources().getStringArray(R.array.map_types)), mapTypeSelectedListener);
+ mapNameSpinner = prepareSpinner(v, R.id.spinMapName, mapNames, mapNameSelectedListener);
+ templateSpinner = prepareSpinner(v, R.id.spinTemplateFilter, Arrays.asList(getResources().getStringArray(R.array.map_templates)), mapTemplateSelectedListener);
+ mazeSizeSpinner = prepareSpinner(v, R.id.spinMazeSize, Arrays.asList(getResources().getStringArray(R.array.map_maze_sizes)), mazeSizeSelectedListener);
+
+ stateManager.registerObserver(this);
+ MapRecipe map = stateManager.getMapRecipe();
+ if(map != null) {
+ updateDisplay(map);
+ }
+ setChiefState(stateManager.getChiefStatus());
+ mapPreviewHandler.activity();
+ return v;
+ }
+
+ private static Spinner prepareSpinner(View v, int id, List<String> items, OnItemSelectedListener itemSelectedListener) {
+ Spinner spinner = (Spinner)v.findViewById(id);
+ ArrayAdapter<String> adapter = new ArrayAdapter<String>(v.getContext(), R.layout.listview_item, items);
+ adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+ spinner.setAdapter(adapter);
+ spinner.setOnItemSelectedListener(itemSelectedListener);
+ return spinner;
+ }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ try {
+ stateManager = ((RoomStateManager.Provider)getActivity()).getRoomStateManager();
+ } catch(ClassCastException e) {
+ throw new RuntimeException("Hosting activity must implement RoomStateManager.Provider.", e);
+ }
+ }
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ mapPreviewHandler.stop();
+ stateManager.unregisterObserver(this);
+ }
+
+ private void setChiefState(boolean chiefState) {
+ mapTypeSpinner.setEnabled(chiefState);
+ mapNameSpinner.setEnabled(chiefState);
+ templateSpinner.setEnabled(chiefState);
+ mazeSizeSpinner.setEnabled(chiefState);
+ mapPreview.setEnabled(chiefState);
+
+ if(chiefState) {
+ sendMapnameAndGenerator();
+ stateManager.changeMapTemplate(templateSpinner.getSelectedItemPosition());
+ stateManager.changeMazeSize(mazeSizeSpinner.getSelectedItemPosition());
+ }
+ }
+
+ private void updateDisplay(MapRecipe map) {
+ nameRow.setVisibility(map.mapgen == Frontlib.MAPGEN_NAMED ? View.VISIBLE : View.GONE);
+ templateRow.setVisibility(map.mapgen == Frontlib.MAPGEN_REGULAR ? View.VISIBLE : View.GONE);
+ mazeSizeRow.setVisibility(map.mapgen == Frontlib.MAPGEN_MAZE ? View.VISIBLE : View.GONE);
+
+ mapTypeSpinner.setSelection(map.mapgen);
+ int mapPosition = findMapPosition(mapFiles, map.name);
+ if(mapPosition >= 0) {
+ mapNameSpinner.setSelection(mapPosition);
+ }
+ templateSpinner.setSelection(map.templateFilter);
+ mazeSizeSpinner.setSelection(map.mazeSize);
+ }
+
+ private static int findMapPosition(List<MapFile> mapFiles, String mapName) {
+ for(int i=0; i<mapFiles.size(); i++) {
+ if(mapName.equals(mapFiles.get(i).name)) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ private void sendMapnameAndGenerator() {
+ int mapType = mapTypeSpinner.getSelectedItemPosition();
+ String mapName = mapFiles.get(mapNameSpinner.getSelectedItemPosition()).name;
+ stateManager.changeMapNameAndGenerator(MapRecipe.mapnameForGenerator(mapType, mapName));
+ }
+
+ private final OnItemSelectedListener mapTypeSelectedListener = new OnItemSelectedListener() {
+ public void onItemSelected(AdapterView<?> adapter, View v, int position, long arg3) {
+ sendMapnameAndGenerator();
+ }
+ public void onNothingSelected(AdapterView<?> arg0) {}
+ };
+
+ private final OnItemSelectedListener mapNameSelectedListener = new OnItemSelectedListener() {
+ public void onItemSelected(AdapterView<?> adapter, View v, int position, long arg3) {
+ sendMapnameAndGenerator();
+ }
+ public void onNothingSelected(AdapterView<?> arg0) {}
+ };
+
+ private final OnItemSelectedListener mapTemplateSelectedListener = new OnItemSelectedListener() {
+ public void onItemSelected(AdapterView<?> adapter, View v, int position, long arg3) {
+ stateManager.changeMapTemplate(position);
+ }
+ public void onNothingSelected(AdapterView<?> arg0) {}
+ };
+
+ private final OnItemSelectedListener mazeSizeSelectedListener = new OnItemSelectedListener() {
+ public void onItemSelected(AdapterView<?> adapter, View v, int position, long arg3) {
+ stateManager.changeMazeSize(position);
+ }
+ public void onNothingSelected(AdapterView<?> arg0) {}
+ };
+
+ private final OnClickListener mapClickListener = new OnClickListener() {
+ public void onClick(View v) {
+ stateManager.changeMapSeed(MapRecipe.makeRandomSeed());
+ switch(mapTypeSpinner.getSelectedItemPosition()) {
+ case Frontlib.MAPGEN_NAMED:
+ mapNameSpinner.setSelection(random.nextInt(mapNameSpinner.getCount()));
+ break;
+ case Frontlib.MAPGEN_REGULAR:
+ templateSpinner.setSelection(Frontlib.TEMPLATEFILTER_ALL);
+ break;
+ case Frontlib.MAPGEN_MAZE:
+ mazeSizeSpinner.setSelection(random.nextInt(mazeSizeSpinner.getCount()));
+ break;
+ }
+ }
+ };
+
+ public void onChiefStatusChanged(boolean isChief) {
+ setChiefState(isChief);
+ }
+
+ public void onMapChanged(MapRecipe recipe) {
+ updateDisplay(recipe);
+ mapPreviewHandler.activity();
+ }
+
+ public void onGameStyleChanged(String gameStyle) { }
+ public void onSchemeChanged(Scheme scheme) { }
+ public void onWeaponsetChanged(Weaponset weaponset) { }
+
+ private MapPreviewGenerator.Listener mapPreviewListener = new MapPreviewGenerator.Listener() {
+ public void onMapPreviewResult(Drawable preview) {
+ if(newPreviewRequest != null) {
+ MapPreviewGenerator.startPreviewGeneration(getActivity().getApplicationContext(), newPreviewRequest, mapPreviewListener);
+ newPreviewRequest = null;
+ } else {
+ if(mapPreview != null) {
+ mapPreview.setImageDrawable(preview);
+ }
+ previewGenerationInProgress = false;
+ }
+ }
+ };
+
+ /**
+ * This class allows you to define a runnable that is called when there has been no activity
+ * for a set amount of time, where activity is determined by calls to the activity() method
+ * of the handler. It is used here to update the map preview when there have been no updates
+ * to the relevant map information for a time, to prevent triggering several updates at once
+ * when different parts of the information change.
+ */
+ private static final class CalmDownHandler extends Handler {
+ int runningMessagesCounter = 0;
+ final Runnable inactivityRunnable;
+ final long inactivityMs;
+ boolean stopped;
+
+ public CalmDownHandler(Looper looper, Runnable runnable, long inactivityMs) {
+ super(looper);
+ this.inactivityRunnable = runnable;
+ this.inactivityMs = inactivityMs;
+ }
+
+ public void activity() {
+ runningMessagesCounter++;
+ sendMessageDelayed(obtainMessage(), inactivityMs);
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ runningMessagesCounter--;
+ if(runningMessagesCounter==0 && !stopped) {
+ inactivityRunnable.run();
+ }
+ }
+
+ public void stop() {
+ stopped = true;
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/MapPreviewGenerator.java Sat Aug 18 00:47:51 2012 +0200
@@ -0,0 +1,200 @@
+package org.hedgewars.hedgeroid;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+
+import org.hedgewars.hedgeroid.Datastructures.MapFile;
+import org.hedgewars.hedgeroid.Datastructures.MapRecipe;
+import org.hedgewars.hedgeroid.EngineProtocol.PascalExports;
+import org.hedgewars.hedgeroid.frontlib.Flib;
+import org.hedgewars.hedgeroid.frontlib.Frontlib;
+import org.hedgewars.hedgeroid.frontlib.Frontlib.MapRecipePtr;
+import org.hedgewars.hedgeroid.frontlib.Frontlib.MapconnPtr;
+import org.hedgewars.hedgeroid.frontlib.Frontlib.MapimageCallback;
+import org.hedgewars.hedgeroid.frontlib.Frontlib.StrCallback;
+import org.hedgewars.hedgeroid.util.FileUtils;
+
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.Bitmap.Config;
+import android.graphics.Color;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.os.Handler;
+import android.os.Looper;
+import android.util.Log;
+
+import com.sun.jna.Pointer;
+
+/**
+ * A class that asynchronously generates a map preview from a MapRecipe.
+ *
+ * For named maps, this will load the preview image from the filesystem. For others,
+ * it will call the engine to generate a preview image.
+ */
+public final class MapPreviewGenerator implements Runnable {
+ private static final String TAG = MapPreviewGenerator.class.getSimpleName();
+ private static final Handler mainHandler = new Handler(Looper.getMainLooper());
+
+ private final Context appContext;
+ private final MapRecipe map;
+ private final Listener listener;
+
+ private boolean resultAvailable;
+ private Drawable result;
+
+ public static interface Listener {
+ /**
+ * This is called on the UI thread once the preview is ready or failed.
+ * In case of failure, null is passed.
+ */
+ void onMapPreviewResult(Drawable preview);
+ }
+
+ private MapPreviewGenerator(Context appContext, MapRecipe map, Listener listener) {
+ this.appContext = appContext;
+ this.map = map;
+ this.listener = listener;
+ }
+
+ public void run() {
+ if (map.mapgen == Frontlib.MAPGEN_NAMED) {
+ postToListener(loadPreviewFromFile(appContext, map.name));
+ } else {
+ resultAvailable = false;
+ result = null;
+ MapconnPtr conn = Flib.INSTANCE.flib_mapconn_create(MapRecipePtr.createJavaOwned(map));
+ if (conn == null) {
+ postToListener(null);
+ return;
+ }
+ try {
+ int port = Flib.INSTANCE.flib_mapconn_getport(conn);
+ Flib.INSTANCE.flib_mapconn_onSuccess(conn, successCb, null);
+ Flib.INSTANCE.flib_mapconn_onFailure(conn, failureCb, null);
+
+ String configPath;
+ try {
+ configPath = FileUtils.getCachePath(appContext).getAbsolutePath();
+ } catch(FileNotFoundException e) {
+ return;
+ }
+
+ startEngine(configPath, port);
+ long startTime = System.nanoTime();
+ do {
+ Flib.INSTANCE.flib_mapconn_tick(conn);
+ try {
+ Thread.sleep(50);
+ } catch (InterruptedException e) {
+ // ignore
+ }
+ } while(!resultAvailable && System.nanoTime()-startTime < 15000000000l); // 15 seconds timeout
+ } finally {
+ Flib.INSTANCE.flib_mapconn_destroy(conn);
+ postToListener(result);
+ }
+ }
+ }
+
+ public static void startPreviewGeneration(Context appContext, MapRecipe map, Listener listener) {
+ new Thread(new MapPreviewGenerator(appContext, map, listener)).start();
+ }
+
+ private static Drawable loadPreviewFromFile(Context appContext, String mapName) {
+ if(!mapName.startsWith("+")) {
+ try {
+ File previewFile = MapFile.getPreviewFile(appContext, mapName);
+ return Drawable.createFromPath(previewFile.getAbsolutePath());
+ } catch (FileNotFoundException e) {
+ Log.w("MapPreviewGenerator", "Preview for map "+mapName+" not found.");
+ }
+ }
+ return null;
+ }
+
+ private static void startEngine(final String configPath, final int port) {
+ new Thread(new Runnable() {
+ public void run() {
+ Log.d(TAG, "Starting engine "+port);
+ synchronized(PascalExports.engineMutex) {
+ PascalExports.HWGenLandPreview(port);
+ }
+ Log.d(TAG, "Engine finished");
+ }
+ }).start();
+ }
+
+ private void postToListener(final Drawable result) {
+ mainHandler.post(new Runnable() {
+ public void run() {
+ listener.onMapPreviewResult(result);
+ }
+ });
+ }
+
+ /**
+ * Let's be extra nice here and clip off the left and right sides, so the preview is centered...
+ * Since the image is present in bytes, we can save some effort by checking entire byte-columns first.
+ */
+ private final MapimageCallback successCb = new MapimageCallback() {
+ public void callback(Pointer context, Pointer buffer, int hedgehogCount) {
+ Log.d(TAG, "Running success handler");
+ byte[] mapdata = buffer.getByteArray(0, Frontlib.MAPIMAGE_BYTES);
+
+ int leftmostPixel = Frontlib.MAPIMAGE_WIDTH;
+ int rightmostPixel = -1;
+ int bytesPerLine = Frontlib.MAPIMAGE_WIDTH/8;
+
+ // Find the leftmost pixel
+ for(int xbyte=0; xbyte<bytesPerLine; xbyte++) {
+ for(int y=0; y<Frontlib.MAPIMAGE_HEIGHT; y++) {
+ int b = 0xff&mapdata[xbyte+y*bytesPerLine];
+ if(b != 0) {
+ leftmostPixel = Math.min(leftmostPixel, Integer.numberOfLeadingZeros(b)-24+xbyte*8);
+ }
+ }
+ if(leftmostPixel!=Frontlib.MAPIMAGE_WIDTH) break;
+ }
+
+ // Find the rightmost pixel
+ for(int xbyte=bytesPerLine-1; xbyte>=0; xbyte--) {
+ for(int y=0; y<Frontlib.MAPIMAGE_HEIGHT; y++) {
+ int b = mapdata[xbyte+y*bytesPerLine];
+ if(b != 0) {
+ rightmostPixel = Math.max(rightmostPixel, xbyte*8+7-Integer.numberOfTrailingZeros(b));
+ }
+ }
+ if(rightmostPixel!=-1) break;
+ }
+
+ // No pixel was set at all -> use default width
+ if(rightmostPixel==-1) {
+ leftmostPixel = 0;
+ rightmostPixel = Frontlib.MAPIMAGE_WIDTH-1;
+ }
+
+ Bitmap bitmap = Bitmap.createBitmap(rightmostPixel-leftmostPixel+1, Frontlib.MAPIMAGE_HEIGHT, Config.ARGB_8888);
+ for(int y=0; y<Frontlib.MAPIMAGE_HEIGHT; y++) {
+ for(int x=0; x<bitmap.getWidth(); x++) {
+ bitmap.setPixel(x, y, isPixelSet(mapdata, x+leftmostPixel, y) ? Color.YELLOW : Color.TRANSPARENT);
+ }
+ }
+ result = new BitmapDrawable(bitmap);
+ resultAvailable = true;
+ }
+ };
+
+ private static boolean isPixelSet(byte[] imgdata, int x, int y) {
+ int pixelnum = x+Frontlib.MAPIMAGE_WIDTH*y;
+ return (imgdata[pixelnum>>3] & (128>>(pixelnum&7))) != 0;
+ }
+
+ private final StrCallback failureCb = new StrCallback() {
+ public void callback(Pointer context, String reason) {
+ Log.e(TAG, "Error generating map preview: "+reason);
+ result = null;
+ resultAvailable = true;
+ }
+ };
+}
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/NetplayStateFragment.java Sat Aug 18 00:47:51 2012 +0200
@@ -0,0 +1,120 @@
+package org.hedgewars.hedgeroid;
+
+import org.hedgewars.hedgeroid.R;
+import org.hedgewars.hedgeroid.frontlib.Frontlib;
+import org.hedgewars.hedgeroid.netplay.Netplay;
+import org.hedgewars.hedgeroid.netplay.Netplay.State;
+
+import android.app.Activity;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.support.v4.content.LocalBroadcastManager;
+import android.widget.Toast;
+
+/**
+ * Fragment for use by an activity that depends on the state of the network
+ * connection. The activity must implement the NetplayStateListener interface.
+ *
+ * This fragment manages a few aspects of the netplay connection: Requesting
+ * the network system loop to run at high frequency while the activity is in
+ * the foreground, and reacting to changes in the networking state by calling
+ * a callback method on the activity.
+ */
+public class NetplayStateFragment extends Fragment {
+ private Netplay netplay;
+ private Context appContext;
+ private LocalBroadcastManager broadcastManager;
+ private NetplayStateListener listener;
+ private State knownState;
+
+ interface NetplayStateListener {
+ /**
+ * This is called while the activity is running, and every time during resume, if
+ * a change in the networking state is detected. It is also called once
+ * with the initial state (which could be called a change from the "unknown" state).
+ */
+ void onNetplayStateChanged(State newState);
+ }
+
+ @Override
+ public void onAttach(Activity activity) {
+ super.onAttach(activity);
+ try {
+ listener = (NetplayStateListener) activity;
+ } catch(ClassCastException e) {
+ throw new ClassCastException("Activity " + activity + " must implement NetplayStateListener to use NetplayStateFragment.");
+ }
+ }
+
+ @Override
+ public void onDetach() {
+ super.onDetach();
+ listener = null;
+ }
+
+ @Override
+ public void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+ appContext = getActivity().getApplicationContext();
+ broadcastManager = LocalBroadcastManager.getInstance(appContext);
+ netplay = Netplay.getAppInstance(appContext);
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ broadcastManager.registerReceiver(disconnectReceiver, new IntentFilter(Netplay.ACTION_DISCONNECTED));
+ broadcastManager.registerReceiver(leaveRoomReceiver, new IntentFilter(Netplay.ACTION_LEFT_ROOM));
+ broadcastManager.registerReceiver(stateChangeReceiver, new IntentFilter(Netplay.ACTION_STATE_CHANGED));
+
+ State newState = netplay.getState();
+ if(knownState != newState) {
+ listener.onNetplayStateChanged(newState);
+ knownState = newState;
+ }
+ }
+
+ @Override
+ public void onPause() {
+ super.onPause();
+ broadcastManager.unregisterReceiver(disconnectReceiver);
+ broadcastManager.unregisterReceiver(leaveRoomReceiver);
+ broadcastManager.unregisterReceiver(stateChangeReceiver);
+ }
+
+ private final BroadcastReceiver disconnectReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if(intent.getBooleanExtra(Netplay.EXTRA_HAS_ERROR, true)) {
+ String message = intent.getStringExtra(Netplay.EXTRA_MESSAGE);
+ String toastText = getString(R.string.toast_disconnected, message);
+ Toast.makeText(appContext, toastText, Toast.LENGTH_LONG).show();
+ }
+ }
+ };
+
+ private final BroadcastReceiver leaveRoomReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ int reason = intent.getIntExtra(Netplay.EXTRA_REASON, -1);
+ if(reason == Frontlib.NETCONN_ROOMLEAVE_ABANDONED) {
+ Toast.makeText(appContext, R.string.toast_room_abandoned, Toast.LENGTH_LONG).show();
+ } else if(reason == Frontlib.NETCONN_ROOMLEAVE_KICKED) {
+ Toast.makeText(appContext, R.string.toast_kicked, Toast.LENGTH_LONG).show();
+ }
+ }
+ };
+
+ private final BroadcastReceiver stateChangeReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ State newState = netplay.getState();
+ listener.onNetplayStateChanged(newState);
+ knownState = newState;
+ }
+ };
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/RoomActivity.java Sat Aug 18 00:47:51 2012 +0200
@@ -0,0 +1,85 @@
+package org.hedgewars.hedgeroid;
+
+import org.hedgewars.hedgeroid.R;
+import org.hedgewars.hedgeroid.Datastructures.Team;
+import org.hedgewars.hedgeroid.NetplayStateFragment.NetplayStateListener;
+import org.hedgewars.hedgeroid.netplay.Netplay;
+import org.hedgewars.hedgeroid.netplay.Netplay.State;
+
+import android.os.Bundle;
+import android.support.v4.app.FragmentActivity;
+import android.support.v4.app.FragmentTransaction;
+import android.widget.TabHost;
+import android.widget.Toast;
+
+public class RoomActivity extends FragmentActivity implements NetplayStateListener, TeamAddDialog.Listener, RoomStateManager.Provider {
+ private TabHost tabHost;
+ private Netplay netplay;
+
+ @Override
+ protected void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+ netplay = Netplay.getAppInstance(getApplicationContext());
+
+ setContentView(R.layout.activity_netroom);
+ ChatFragment chatFragment = (ChatFragment)getSupportFragmentManager().findFragmentById(R.id.chatFragment);
+ chatFragment.setInRoom(true);
+
+ FragmentTransaction trans = getSupportFragmentManager().beginTransaction();
+ trans.add(new NetplayStateFragment(), "netplayFragment");
+ trans.commit();
+
+ /*tabHost = (TabHost)findViewById(android.R.id.tabhost);
+ if(tabHost != null) {
+ tabHost.setup();
+ tabHost.getTabWidget().setOrientation(LinearLayout.VERTICAL);
+
+ //tabHost.addTab(tabHost.newTabSpec("chat").setIndicator(createIndicatorView(tabHost, R.string.lobby_tab_chat, getResources().getDrawable(R.drawable.edit))).setContent(R.id.chatFragment));
+ //tabHost.addTab(tabHost.newTabSpec("players").setIndicator(createIndicatorView(tabHost, R.string.lobby_tab_players, getResources().getDrawable(R.drawable.human))).setContent(R.id.playerListFragment));
+
+ if (icicle != null) {
+ tabHost.setCurrentTabByTag(icicle.getString("currentTab"));
+ }
+ }*/
+ }
+
+ @Override
+ public void onBackPressed() {
+ netplay.sendLeaveRoom(null);
+ }
+
+ @Override
+ protected void onSaveInstanceState(Bundle icicle) {
+ super.onSaveInstanceState(icicle);
+ if(tabHost != null) {
+ icicle.putString("currentTab", tabHost.getCurrentTabTag());
+ }
+ }
+
+ public void onNetplayStateChanged(State newState) {
+ switch(newState) {
+ case NOT_CONNECTED:
+ case CONNECTING:
+ case LOBBY:
+ finish();
+ break;
+ case ROOM:
+ // Do nothing
+ break;
+ case INGAME:
+ //startActivity(new Intent(getApplicationContext(), RoomActivity.class));
+ Toast.makeText(getApplicationContext(), R.string.not_implemented_yet, Toast.LENGTH_SHORT).show();
+ break;
+ default:
+ throw new IllegalStateException("Unknown connection state: "+newState);
+ }
+ }
+
+ public void onTeamAddDialogSubmitted(Team newTeam) {
+ netplay.sendAddTeam(newTeam);
+ }
+
+ public RoomStateManager getRoomStateManager() {
+ return netplay.getRoomStateManager();
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/RoomPlayerlistAdapter.java Sat Aug 18 00:47:51 2012 +0200
@@ -0,0 +1,41 @@
+package org.hedgewars.hedgeroid;
+
+import java.util.Comparator;
+
+import org.hedgewars.hedgeroid.R;
+import org.hedgewars.hedgeroid.Datastructures.PlayerInRoom;
+import org.hedgewars.hedgeroid.util.ObservableTreeMapAdapter;
+
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+public class RoomPlayerlistAdapter extends ObservableTreeMapAdapter<String, PlayerInRoom> {
+ @Override
+ protected Comparator<PlayerInRoom> getEntryOrder() {
+ return AlphabeticalOrderComparator.INSTANCE;
+ }
+
+ public View getView(int position, View convertView, ViewGroup parent) {
+ View v = convertView;
+ if (v == null) {
+ LayoutInflater vi = LayoutInflater.from(parent.getContext());
+ v = vi.inflate(R.layout.listview_player, null);
+ }
+
+ PlayerInRoom player = getItem(position);
+ TextView username = (TextView) v.findViewById(android.R.id.text1);
+ username.setText(player.player.name);
+ int readyDrawable = player.ready ? R.drawable.lightbulb_on : R.drawable.lightbulb_off;
+ username.setCompoundDrawablesWithIntrinsicBounds(readyDrawable, 0, 0, 0);
+ return v;
+ }
+
+ private static final class AlphabeticalOrderComparator implements Comparator<PlayerInRoom> {
+ public static final AlphabeticalOrderComparator INSTANCE = new AlphabeticalOrderComparator();
+ public int compare(PlayerInRoom lhs, PlayerInRoom rhs) {
+ return lhs.player.name.compareToIgnoreCase(rhs.player.name);
+ };
+ }
+}
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/RoomPlayerlistFragment.java Sat Aug 18 00:47:51 2012 +0200
@@ -0,0 +1,103 @@
+package org.hedgewars.hedgeroid;
+
+import org.hedgewars.hedgeroid.R;
+import org.hedgewars.hedgeroid.Datastructures.GameConfig;
+import org.hedgewars.hedgeroid.Datastructures.Player;
+import org.hedgewars.hedgeroid.Datastructures.PlayerInRoom;
+import org.hedgewars.hedgeroid.netplay.Netplay;
+import org.hedgewars.hedgeroid.netplay.RunGameListener;
+
+import android.content.Intent;
+import android.os.Bundle;
+import android.support.v4.app.ListFragment;
+import android.view.ContextMenu;
+import android.view.ContextMenu.ContextMenuInfo;
+import android.view.LayoutInflater;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.AdapterView;
+import android.widget.AdapterView.AdapterContextMenuInfo;
+import android.widget.AdapterView.OnItemClickListener;
+
+public class RoomPlayerlistFragment extends ListFragment implements OnItemClickListener, RunGameListener {
+ private Netplay netplay;
+ private RoomPlayerlistAdapter adapter;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ netplay = Netplay.getAppInstance(getActivity().getApplicationContext());
+ netplay.registerRunGameListener(this);
+ adapter = new RoomPlayerlistAdapter();
+ adapter.setSource(netplay.roomPlayerlist);
+ setListAdapter(adapter);
+ }
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ adapter.invalidate();
+ netplay.unregisterRunGameListener(this);
+ }
+
+ @Override
+ public void onActivityCreated(Bundle savedInstanceState) {
+ super.onActivityCreated(savedInstanceState);
+ registerForContextMenu(getListView());
+ getListView().setOnItemClickListener(this);
+ }
+
+ @Override
+ public void onCreateContextMenu(ContextMenu menu, View v,
+ ContextMenuInfo menuInfo) {
+ super.onCreateContextMenu(menu, v, menuInfo);
+ AdapterContextMenuInfo info = (AdapterContextMenuInfo)menuInfo;
+ String playerName = adapter.getItem(info.position).player.name;
+
+ MenuInflater inflater = getActivity().getMenuInflater();
+ inflater.inflate(R.menu.room_playerlist_context, menu);
+ if(netplay.isChief() && !playerName.equals(netplay.getPlayerName())) {
+ inflater.inflate(R.menu.room_playerlist_chief_context, menu);
+ }
+ menu.setHeaderIcon(R.drawable.human);
+ menu.setHeaderTitle(playerName);
+ }
+
+ @Override
+ public boolean onContextItemSelected(MenuItem item) {
+ AdapterContextMenuInfo info = (AdapterContextMenuInfo)item.getMenuInfo();
+ PlayerInRoom player = adapter.getItem(info.position);
+ switch(item.getItemId()) {
+ case R.id.player_info:
+ netplay.sendPlayerInfoQuery(player.player.name);
+ return true;
+ case R.id.player_kick:
+ netplay.sendKick(player.player.name);
+ return true;
+ default:
+ return super.onContextItemSelected(item);
+ }
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ return inflater.inflate(R.layout.fragment_playerlist, container, false);
+ }
+
+ public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
+ Player player = adapter.getItem(position).player;
+ if(player.name.equals(netplay.getPlayerName())) {
+ netplay.sendToggleReady();
+ }
+ }
+
+ // TODO this is really the wrong place for this...
+ public void runGame(GameConfig config) {
+ SDLActivity.startConfig = config;
+ SDLActivity.startNetgame = true;
+ startActivity(new Intent(getActivity().getApplicationContext(), SDLActivity.class));
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/RoomStateManager.java Sat Aug 18 00:47:51 2012 +0200
@@ -0,0 +1,70 @@
+package org.hedgewars.hedgeroid;
+
+import org.hedgewars.hedgeroid.Datastructures.MapRecipe;
+import org.hedgewars.hedgeroid.Datastructures.Scheme;
+import org.hedgewars.hedgeroid.Datastructures.Weaponset;
+
+/**
+ * This interface is supposed to abstract the handling of room state for several fragments
+ * that can display and manipulate it. The purpose of this is to allow using these fragments
+ * both for setting up networked and local games, despite the fact that for local games
+ * the settings can be changed immediately in memory, while they have to be sent out to the
+ * server for networked games.
+ *
+ * If/when the state changes as result of calling one of the "changeX" functions, that will
+ * also trigger the corresponding change listener method. There is no guarantee that calling
+ * a changeX method will actually change the setting (e.g. if you're not room chief).
+ *
+ * For local games, getChiefStatus is always true.
+ *
+ * Implementations of this interface are probably not thread safe and should only be used on
+ * the UI thread.
+ */
+public interface RoomStateManager {
+ // Query current state
+ MapRecipe getMapRecipe();
+ boolean getChiefStatus();
+ Scheme getScheme();
+ String getGameStyle();
+ Weaponset getWeaponset();
+
+ // Manipulate state
+ void changeMapRecipe(MapRecipe map);
+ void changeMapTheme(String theme);
+
+ /**
+ * This function sets both the map's name and generator. There is no function
+ * to change them independendly since e.g. the QtFrontend relies on them being
+ * consistent.
+ *
+ * If the name parameter is equal to one of the MapRecipe.MAPNAME_REGULAR, MAPNAME_MAZE
+ * or MAPNAME_DRAWN constants, the map generator is set accordingly. Otherwise, the
+ * map generator is set to represent a mapfile. The map's name is always set to
+ * the parameter.
+ */
+ void changeMapNameAndGenerator(String mapName);
+ void changeMapTemplate(int template);
+ void changeMazeSize(int mazeSize);
+ void changeMapSeed(String seed);
+ void changeMapDrawdata(byte[] drawdata);
+
+ void changeScheme(Scheme scheme);
+ void changeGameStyle(String style);
+ void changeWeaponset(Weaponset weaponset);
+
+ // Observe state
+ void registerObserver(Observer observer);
+ void unregisterObserver(Observer observer);
+
+ public interface Observer {
+ void onMapChanged(MapRecipe recipe);
+ void onChiefStatusChanged(boolean isChief);
+ void onSchemeChanged(Scheme scheme);
+ void onGameStyleChanged(String gameStyle);
+ void onWeaponsetChanged(Weaponset weaponset);
+ }
+
+ public interface Provider {
+ RoomStateManager getRoomStateManager();
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/RoomlistAdapter.java Sat Aug 18 00:47:51 2012 +0200
@@ -0,0 +1,91 @@
+package org.hedgewars.hedgeroid;
+
+import java.util.Comparator;
+
+import org.hedgewars.hedgeroid.R;
+import org.hedgewars.hedgeroid.Datastructures.Room;
+import org.hedgewars.hedgeroid.Datastructures.RoomWithId;
+import org.hedgewars.hedgeroid.util.ObservableTreeMapAdapter;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+public class RoomlistAdapter extends ObservableTreeMapAdapter<String, RoomWithId> {
+ private Context context;
+
+ public RoomlistAdapter(Context context) {
+ this.context = context;
+ }
+
+ @Override
+ protected Comparator<RoomWithId> getEntryOrder() {
+ return RoomWithId.NEWEST_FIRST_ORDER;
+ }
+
+ @Override
+ public long getItemId(int position) {
+ return getItem(position).id;
+ }
+
+ @Override
+ public boolean hasStableIds() {
+ return true;
+ }
+
+ private static CharSequence formatExtra(Resources res, Room room) {
+ String ownermsg = res.getString(R.string.roomlist_owner, room.owner);
+ String mapmsg = res.getString(R.string.roomlist_map, room.formatMapName(res));
+ String scheme = room.scheme.equals(room.weapons) ? room.scheme : room.scheme + " / " + room.weapons;
+ String schememsg = res.getString(R.string.roomlist_scheme, scheme);
+ return ownermsg + ". " + mapmsg + ", " + schememsg;
+ }
+
+ public View getView(int position, View convertView, ViewGroup parent) {
+ View v = convertView;
+ if (v == null) {
+ LayoutInflater vi = LayoutInflater.from(context);
+ v = vi.inflate(R.layout.listview_room, null);
+ }
+
+ Room room = getItem(position).room;
+ int iconRes = room.inProgress ? R.drawable.roomlist_ingame : R.drawable.roomlist_preparing;
+
+ if(v.findViewById(android.R.id.text1) == null) {
+ // Tabular room list
+ TextView roomnameView = (TextView)v.findViewById(R.id.roomname);
+ TextView playerCountView = (TextView)v.findViewById(R.id.playercount);
+ TextView teamCountView = (TextView)v.findViewById(R.id.teamcount);
+ TextView ownerView = (TextView)v.findViewById(R.id.owner);
+ TextView mapView = (TextView)v.findViewById(R.id.map);
+ TextView schemeView = (TextView)v.findViewById(R.id.scheme);
+ TextView weaponView = (TextView)v.findViewById(R.id.weapons);
+
+ roomnameView.setCompoundDrawablesWithIntrinsicBounds(iconRes, 0, 0, 0);
+ roomnameView.setText(room.name);
+ if(playerCountView != null) {
+ playerCountView.setText(String.valueOf(room.playerCount));
+ }
+ if(teamCountView != null) {
+ teamCountView.setText(String.valueOf(room.teamCount));
+ }
+ ownerView.setText(room.owner);
+ mapView.setText(room.formatMapName(context.getResources()));
+ schemeView.setText(room.scheme);
+ weaponView.setText(room.weapons);
+ } else {
+ // Small room list
+ TextView v1 = (TextView)v.findViewById(android.R.id.text1);
+ TextView v2 = (TextView)v.findViewById(android.R.id.text2);
+
+ v1.setCompoundDrawablesWithIntrinsicBounds(iconRes, 0, 0, 0);
+ v1.setText(room.name);
+ v2.setText(formatExtra(context.getResources(), room));
+ }
+
+ return v;
+ }
+}
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/RoomlistFragment.java Sat Aug 18 00:47:51 2012 +0200
@@ -0,0 +1,72 @@
+package org.hedgewars.hedgeroid;
+
+import org.hedgewars.hedgeroid.R;
+import org.hedgewars.hedgeroid.netplay.Netplay;
+
+import android.os.Bundle;
+import android.os.CountDownTimer;
+import android.support.v4.app.ListFragment;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.AdapterView;
+import android.widget.AdapterView.OnItemClickListener;
+
+public class RoomlistFragment extends ListFragment implements OnItemClickListener {
+ private static final int AUTO_REFRESH_INTERVAL_MS = 15000;
+
+ private Netplay netplay;
+ private RoomlistAdapter adapter;
+ private CountDownTimer autoRefreshTimer = new CountDownTimer(Long.MAX_VALUE, AUTO_REFRESH_INTERVAL_MS) {
+ @Override
+ public void onTick(long millisUntilFinished) {
+ netplay.sendRoomlistRequest();
+ }
+
+ @Override
+ public void onFinish() { }
+ };
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ netplay = Netplay.getAppInstance(getActivity().getApplicationContext());
+ adapter = new RoomlistAdapter(getActivity());
+ adapter.setSource(netplay.roomList);
+ setListAdapter(adapter);
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ return inflater.inflate(R.layout.lobby_rooms_fragment, container, false);
+ }
+
+ @Override
+ public void onActivityCreated(Bundle savedInstanceState) {
+ super.onActivityCreated(savedInstanceState);
+ getListView().setOnItemClickListener(this);
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ autoRefreshTimer.start();
+ }
+
+ @Override
+ public void onPause() {
+ super.onPause();
+ autoRefreshTimer.cancel();
+ }
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ adapter.invalidate();
+ }
+
+ public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
+ netplay.sendJoinRoom(adapter.getItem(position).room.name);
+ }
+}
--- a/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/SDLActivity.java Sat Aug 18 00:22:33 2012 +0200
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/SDLActivity.java Sat Aug 18 00:47:51 2012 +0200
@@ -1,5 +1,8 @@
package org.hedgewars.hedgeroid;
+import java.io.UnsupportedEncodingException;
+import java.util.concurrent.atomic.AtomicBoolean;
+
import javax.microedition.khronos.egl.EGL10;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.egl.EGLContext;
@@ -12,7 +15,9 @@
import org.hedgewars.hedgeroid.frontlib.Frontlib.GameSetupPtr;
import org.hedgewars.hedgeroid.frontlib.Frontlib.GameconnPtr;
import org.hedgewars.hedgeroid.frontlib.Frontlib.IntCallback;
-import org.hedgewars.hedgeroid.netplay.TickHandler;
+import org.hedgewars.hedgeroid.netplay.Netplay;
+import org.hedgewars.hedgeroid.util.FileUtils;
+import org.hedgewars.hedgeroid.util.TickHandler;
import com.sun.jna.Pointer;
@@ -31,6 +36,7 @@
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Message;
+import android.util.Base64;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.KeyEvent;
@@ -50,6 +56,7 @@
* way to do this (http://developer.android.com/guide/faq/framework.html#3)
*/
public static volatile GameConfig startConfig;
+ public static volatile boolean startNetgame;
// Main components
public static SDLActivity mSingleton;
@@ -87,7 +94,7 @@
mSingleton = this;
// Set up the surface
- mSurface = new SDLSurface(getApplication(), startConfig);
+ mSurface = new SDLSurface(getApplication(), startConfig, startNetgame);
setContentView(mSurface);
}
@@ -150,8 +157,14 @@
commandHandler.sendMessage(msg);
}
+ public static void synchronizedNativeInit(String...args) {
+ synchronized(PascalExports.engineMutex) {
+ nativeInit(args);
+ }
+ }
+
// C functions we call
- public static native void nativeInit(String...args);
+ private static native void nativeInit(String...args);
public static native void nativeQuit();
public static native void nativePause();
public static native void nativeResume();
@@ -184,12 +197,29 @@
return mSingleton;
}
- public static void startApp(int width, int height, GameConfig config) {
+ public static void startApp(final int width, final int height, GameConfig config, boolean netgame) {
synchronized(SDLActivity.class) {
- // Start up the C app thread
+ // Start up the C app thread TODO this is silly code
if (mSDLThread == null) {
- mSDLThread = new Thread(new SDLMain(width, height, config), "SDLThread");
- mSDLThread.start();
+ final AtomicBoolean gameconnStartDone = new AtomicBoolean(false);
+ GameConnection.Listener listener = new GameConnection.Listener() {
+ public void gameConnectionReady(int port) {
+ mSDLThread = new Thread(new SDLMain(width, height, port, "Medo"));
+ mSDLThread.start();
+ gameconnStartDone.set(true);
+ }
+
+ public void gameConnectionDisconnected(int reason) {
+ Log.e("startApp", "disconnected: "+reason);
+ gameconnStartDone.set(true);
+ }
+ };
+ if(netgame) {
+ Netplay netplay = Netplay.getAppInstance(mSingleton.getApplicationContext());
+ GameConnection.forNetgame(config, netplay, listener);
+ } else {
+ GameConnection.forLocalGame(config, listener);
+ }
} else {
SDLActivity.nativeResume();
}
@@ -426,61 +456,32 @@
class SDLMain implements Runnable {
private final int surfaceWidth, surfaceHeight;
- private final GameConfig config;
- private GameconnPtr conn;
+ private final int port;
+ private final String playerName;
HandlerThread thread = new HandlerThread("IPC thread");
- private final IntCallback dccb = new IntCallback() {
- public void callback(Pointer context, int arg1) {
- Log.d("SDLMain", "Disconnected: "+arg1);
- Flib.INSTANCE.flib_gameconn_destroy(conn);
- conn = null;
- thread.quit();
- }
- };
-
- public SDLMain(int width, int height, GameConfig _config) {
- config = _config;
+ public SDLMain(int width, int height, int port, String playerName) {
surfaceWidth = width;
surfaceHeight = height;
+ this.port = port;
+ this.playerName = playerName;
}
public void run() {
//Set up the IPC socket server to communicate with the engine
-
- final GameconnPtr conn = Flib.INSTANCE.flib_gameconn_create("Xeli", GameSetupPtr.createJavaOwned(config), false);
- if(conn == null) {
- throw new AssertionError();
- }
- Flib.INSTANCE.flib_gameconn_onDisconnect(conn, dccb, null);
- int port = Flib.INSTANCE.flib_gameconn_getport(conn);
-
- String path = Utils.getDataPath(SDLActivity.mSingleton);//This represents the data directory
+ String path = FileUtils.getDataPath(SDLActivity.mSingleton);//This represents the data directory
path = path.substring(0, path.length()-1);//remove the trailing '/'
- thread.start(); // TODO ensure it gets stopped
- new TickHandler(thread.getLooper(), 500, new Runnable() {
- public void run() {
- Log.d("SDLMain", "pre-tick");
- Flib.INSTANCE.flib_gameconn_tick(conn);
- Log.d("SDLMain", "post-tick");
- }
- }).start();
-
Log.d("SDLMain", "Starting engine");
// Runs SDL_main() with added parameters
- SDLActivity.nativeInit(new String[] { String.valueOf(port),
- String.valueOf(surfaceWidth), String.valueOf(surfaceHeight),
- "0", "en.txt", "xeli", "1", "1", "1", path, "" });
+ try {
+ SDLActivity.synchronizedNativeInit(new String[] { String.valueOf(port),
+ String.valueOf(surfaceWidth), String.valueOf(surfaceHeight),
+ "0", "en.txt", Base64.encodeToString(playerName.getBytes("UTF-8"), 0), "1", "1", "1", path, "" });
+ } catch (UnsupportedEncodingException e) {
+ throw new AssertionError(e); // never happens
+ }
Log.d("SDLMain", "Engine stopped");
- try {
- thread.join();
- } catch (InterruptedException e) {
- throw new AssertionError();
- }
- Log.v("SDLMain", "thread joined");
- Flib.INSTANCE.flib_gameconn_destroy(conn);
- Log.v("SDLMain", "SDL thread terminated");
}
}
@@ -495,12 +496,13 @@
View.OnKeyListener, View.OnTouchListener, SensorEventListener {
private GameConfig config;
-
+ private boolean netgame;
+
// Sensors
private static SensorManager mSensorManager;
// Startup
- public SDLSurface(Context context, GameConfig _config) {
+ public SDLSurface(Context context, GameConfig _config, boolean netgame) {
super(context);
getHolder().addCallback(this);
@@ -512,6 +514,7 @@
mSensorManager = (SensorManager)context.getSystemService("sensor");
config = _config;
+ this.netgame = netgame;
}
// Called when we have a valid drawing surface
@@ -581,7 +584,7 @@
SDLActivity.onNativeResize(width, height, sdlFormat);
Log.v("SDL", "Window size:" + width + "x"+height);
- SDLActivity.startApp(width, height, config);
+ SDLActivity.startApp(width, height, config, netgame);
}
// unused
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/SchemeCreatorActivity.java Sat Aug 18 00:47:51 2012 +0200
@@ -0,0 +1,7 @@
+package org.hedgewars.hedgeroid;
+
+import android.app.Activity;
+
+public class SchemeCreatorActivity extends Activity {
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/SchemeListActivity.java Sat Aug 18 00:47:51 2012 +0200
@@ -0,0 +1,8 @@
+package org.hedgewars.hedgeroid;
+
+import android.app.Activity;
+
+// TODO
+public class SchemeListActivity extends Activity {
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/SettingsFragment.java Sat Aug 18 00:47:51 2012 +0200
@@ -0,0 +1,201 @@
+package org.hedgewars.hedgeroid;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.util.Collections;
+import java.util.List;
+
+import org.hedgewars.hedgeroid.R;
+import org.hedgewars.hedgeroid.Datastructures.FrontendDataUtils;
+import org.hedgewars.hedgeroid.Datastructures.MapRecipe;
+import org.hedgewars.hedgeroid.Datastructures.Scheme;
+import org.hedgewars.hedgeroid.Datastructures.Schemes;
+import org.hedgewars.hedgeroid.Datastructures.Weaponset;
+import org.hedgewars.hedgeroid.Datastructures.Weaponsets;
+import org.hedgewars.hedgeroid.util.FileUtils;
+
+import android.graphics.drawable.Drawable;
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.AdapterView;
+import android.widget.AdapterView.OnItemSelectedListener;
+import android.widget.ArrayAdapter;
+import android.widget.ImageView;
+import android.widget.Spinner;
+import android.widget.Toast;
+
+public class SettingsFragment extends Fragment implements RoomStateManager.Observer {
+ private Spinner styleSpinner, schemeSpinner, weaponsetSpinner, themeSpinner;
+ private ImageView themeIcon;
+
+ private List<String> styles;
+ private List<Scheme> schemes;
+ private List<Weaponset> weaponsets;
+ private List<String> themes;
+
+ private RoomStateManager stateManager;
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ View v = inflater.inflate(R.layout.fragment_settings, container, false);
+ themeIcon = (ImageView)v.findViewById(R.id.imgTheme);
+
+ try {
+ styles = FrontendDataUtils.getGameStyles(getActivity());
+ schemes = Schemes.loadAllSchemes(getActivity());
+ weaponsets = Weaponsets.loadAllWeaponsets(getActivity());
+ themes = FrontendDataUtils.getThemes(getActivity());
+ } catch (IOException e) {
+ Toast.makeText(getActivity().getApplicationContext(), R.string.error_missing_sdcard_or_files, Toast.LENGTH_LONG).show();
+ getActivity().finish();
+ }
+
+ Collections.sort(styles, String.CASE_INSENSITIVE_ORDER);
+ Collections.sort(schemes, Scheme.NAME_ORDER);
+ Collections.sort(weaponsets, Weaponset.NAME_ORDER);
+ Collections.sort(themes, String.CASE_INSENSITIVE_ORDER);
+
+ styleSpinner = prepareSpinner(v, R.id.spinGameplay, styles, styleSelectedListener);
+ schemeSpinner = prepareSpinner(v, R.id.spinGamescheme, Schemes.toNameList(schemes), schemeSelectedListener);
+ weaponsetSpinner = prepareSpinner(v, R.id.spinweapons, Weaponsets.toNameList(weaponsets), weaponsetSelectedListener);
+ themeSpinner = prepareSpinner(v, R.id.spinTheme, themes, themeSelectedListener);
+
+ stateManager.registerObserver(this);
+
+ if(stateManager.getGameStyle() != null) {
+ styleSpinner.setSelection(styles.indexOf(stateManager.getGameStyle()), false);
+ }
+ if(stateManager.getScheme() != null) {
+ schemeSpinner.setSelection(getSchemePosition(schemes, stateManager.getScheme().name), false);
+ }
+ if(stateManager.getWeaponset() != null) {
+ weaponsetSpinner.setSelection(getWeaponsetPosition(weaponsets, stateManager.getWeaponset().name), false);
+ }
+ if(stateManager.getMapRecipe() != null) {
+ themeSpinner.setSelection(themes.indexOf(stateManager.getMapRecipe().theme), false);
+ }
+
+ setChiefState(stateManager.getChiefStatus());
+
+ return v;
+ }
+
+ private static Spinner prepareSpinner(View v, int id, List<String> items, OnItemSelectedListener itemSelectedListener) {
+ Spinner spinner = (Spinner)v.findViewById(id);
+ ArrayAdapter<String> adapter = new ArrayAdapter<String>(v.getContext(), R.layout.listview_item, items);
+ adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+ spinner.setAdapter(adapter);
+ spinner.setOnItemSelectedListener(itemSelectedListener);
+ return spinner;
+ }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ try {
+ stateManager = ((RoomStateManager.Provider)getActivity()).getRoomStateManager();
+ } catch(ClassCastException e) {
+ throw new RuntimeException("Hosting activity must implement RoomStateManager.Provider.", e);
+ }
+ }
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ stateManager.unregisterObserver(this);
+ }
+
+ private static int getSchemePosition(List<Scheme> schemes, String scheme) {
+ for(int i=0; i<schemes.size(); i++) {
+ if(schemes.get(i).name.equals(scheme)) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ private static int getWeaponsetPosition(List<Weaponset> weaponsets, String weaponset) {
+ for(int i=0; i<weaponsets.size(); i++) {
+ if(weaponsets.get(i).name.equals(weaponset)) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ private void setChiefState(boolean chiefState) {
+ styleSpinner.setEnabled(chiefState);
+ schemeSpinner.setEnabled(chiefState);
+ weaponsetSpinner.setEnabled(chiefState);
+ themeSpinner.setEnabled(chiefState);
+
+ if(chiefState) {
+ stateManager.changeGameStyle(styles.get(styleSpinner.getSelectedItemPosition()));
+ stateManager.changeScheme(schemes.get(schemeSpinner.getSelectedItemPosition()));
+ stateManager.changeWeaponset(weaponsets.get(weaponsetSpinner.getSelectedItemPosition()));
+ stateManager.changeMapTheme(themes.get(themeSpinner.getSelectedItemPosition()));
+ }
+ }
+
+ private final OnItemSelectedListener styleSelectedListener = new OnItemSelectedListener() {
+ public void onItemSelected(AdapterView<?> adapter, View v, int position, long arg3) {
+ stateManager.changeGameStyle(styles.get(position));
+ }
+ public void onNothingSelected(AdapterView<?> arg0) {}
+ };
+
+ private final OnItemSelectedListener schemeSelectedListener = new OnItemSelectedListener() {
+ public void onItemSelected(AdapterView<?> adapter, View v, int position, long arg3) {
+ stateManager.changeScheme(schemes.get(position));
+ }
+ public void onNothingSelected(AdapterView<?> arg0) {}
+ };
+
+ private final OnItemSelectedListener weaponsetSelectedListener = new OnItemSelectedListener() {
+ public void onItemSelected(AdapterView<?> adapter, View v, int position, long arg3) {
+ stateManager.changeWeaponset(weaponsets.get(position));
+ }
+ public void onNothingSelected(AdapterView<?> arg0) {}
+ };
+
+ private final OnItemSelectedListener themeSelectedListener = new OnItemSelectedListener() {
+ public void onItemSelected(AdapterView<?> adapter, View v, int position, long arg3) {
+ stateManager.changeMapTheme(themes.get(position));
+ String theme = themes.get(position);
+ try {
+ File iconFile = new File(FileUtils.getDataPathFile(getActivity()), "Themes/" + theme + "/icon@2X.png");
+ Drawable themeIconDrawable = Drawable.createFromPath(iconFile.getAbsolutePath());
+ themeIcon.setImageDrawable(themeIconDrawable);
+ } catch (FileNotFoundException e) {
+ Log.e("SettingsFragment", "Unable to find preview for theme "+theme, e);
+ }
+ };
+ public void onNothingSelected(AdapterView<?> arg0) {};
+ };
+
+ public void onChiefStatusChanged(boolean isChief) {
+ setChiefState(isChief);
+ }
+
+ public void onGameStyleChanged(String gameStyle) {
+ styleSpinner.setSelection(styles.indexOf(gameStyle));
+ }
+
+ public void onMapChanged(MapRecipe recipe) {
+ themeSpinner.setSelection(themes.indexOf(recipe.theme));
+ }
+
+ public void onSchemeChanged(Scheme scheme) {
+ schemeSpinner.setSelection(getSchemePosition(schemes, scheme.name));
+ }
+
+ public void onWeaponsetChanged(Weaponset weaponset) {
+ weaponsetSpinner.setSelection(getWeaponsetPosition(weaponsets, weaponset.name));
+ }
+}
--- a/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/StartGameActivity.java Sat Aug 18 00:22:33 2012 +0200
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/StartGameActivity.java Sat Aug 18 00:47:51 2012 +0200
@@ -36,12 +36,12 @@
import org.hedgewars.hedgeroid.Datastructures.TeamInGame;
import org.hedgewars.hedgeroid.Datastructures.Weaponset;
import org.hedgewars.hedgeroid.Datastructures.Weaponsets;
+import org.hedgewars.hedgeroid.util.FileUtils;
import android.app.Activity;
import android.content.Intent;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
-import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.AdapterView;
@@ -56,8 +56,14 @@
public static final int ACTIVITY_TEAM_SELECTOR = 0;
private ImageButton start, back, team;
- private Spinner maps, gameplay, gamescheme, weapons, themes;
+ private Spinner mapSpinner, styleSpinner, schemeSpinner, weaponsetSpinner, themeSpinner;
private ImageView themeIcon, mapPreview, teamCount;
+
+ private List<MapFile> mapFiles;
+ private List<String> styles;
+ private List<Scheme> schemes;
+ private List<Weaponset> weaponsets;
+ private List<String> themes;
private List<TeamInGame> teams = new ArrayList<TeamInGame>();
@@ -70,12 +76,6 @@
team = (ImageButton) findViewById(R.id.btnTeams);
start = (ImageButton) findViewById(R.id.btnStart);
- maps = (Spinner) findViewById(R.id.spinMaps);
- gameplay = (Spinner) findViewById(R.id.spinGameplay);
- gamescheme = (Spinner) findViewById(R.id.spinGamescheme);
- weapons = (Spinner) findViewById(R.id.spinweapons);
- themes = (Spinner) findViewById(R.id.spinTheme);
-
themeIcon = (ImageView) findViewById(R.id.imgTheme);
mapPreview = (ImageView) findViewById(R.id.mapPreview);
teamCount = (ImageView) findViewById(R.id.imgTeamsCount);
@@ -84,90 +84,55 @@
back.setOnClickListener(backClicker);
team.setOnClickListener(teamClicker);
- List<MapFile> mapFiles;
try {
mapFiles = FrontendDataUtils.getMaps(this);
- } catch (FileNotFoundException e) {
- Log.e("StartGameActivity", e.getMessage(), e);
- mapFiles = Collections.emptyList();
- }
- ArrayAdapter<?> adapter = new ArrayAdapter<MapFile>(this, R.layout.listview_item, mapFiles);
- adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
- maps.setAdapter(adapter);
- maps.setOnItemSelectedListener(mapsClicker);
- //set to first nonmission
- for(int i = 0; i < adapter.getCount(); i++){
- if(!((MapFile)adapter.getItem(i)).isMission){
- maps.setSelection(i, false);
- break;
- }
+ styles = FrontendDataUtils.getGameStyles(this);
+ schemes = Schemes.loadAllSchemes(this);
+ weaponsets = Weaponsets.loadAllWeaponsets(this);
+ themes = FrontendDataUtils.getThemes(this);
+ } catch (IOException e) {
+ Toast.makeText(getApplicationContext(), R.string.error_missing_sdcard_or_files, Toast.LENGTH_LONG).show();
+ finish();
}
-
- List<String> gameStyles;
- try {
- gameStyles = FrontendDataUtils.getGameStyles(this);
- } catch (FileNotFoundException e) {
- Log.e("StartGameActivity", e.getMessage(), e);
- gameStyles = Collections.emptyList();
- }
- adapter = new ArrayAdapter<String>(this, R.layout.listview_item, gameStyles);
- adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
- gameplay.setAdapter(adapter);
- //set to first nonmap
- for(int i = 0; i < adapter.getCount(); i++){
- if(((String)adapter.getItem(i)).equals("None")){
- gameplay.setSelection(i, false);
+
+ Collections.sort(mapFiles, MapFile.MISSIONS_FIRST_NAME_ORDER);
+ Collections.sort(styles, String.CASE_INSENSITIVE_ORDER);
+ Collections.sort(schemes, Scheme.NAME_ORDER);
+ Collections.sort(weaponsets, Weaponset.NAME_ORDER);
+ Collections.sort(themes, String.CASE_INSENSITIVE_ORDER);
+
+ List<String> mapNames = MapFile.toDisplayNameList(mapFiles, getResources());
+ List<String> schemeNames = Schemes.toNameList(schemes);
+ List<String> weaponsetNames = Weaponsets.toNameList(weaponsets);
+ View rootView = findViewById(android.R.id.content);
+ mapSpinner = prepareSpinner(rootView, R.id.spinMaps, mapNames, mapsClicker);
+ styleSpinner = prepareSpinner(rootView, R.id.spinGameplay, styles, null);
+ schemeSpinner = prepareSpinner(rootView, R.id.spinGamescheme, schemeNames, null);
+ weaponsetSpinner = prepareSpinner(rootView, R.id.spinweapons, weaponsetNames, null);
+ themeSpinner = prepareSpinner(rootView, R.id.spinTheme, themes, themesClicker);
+
+ // set map to first nonmission
+ for(int i = 0; i < mapFiles.size(); i++){
+ if(!mapFiles.get(i).isMission){
+ mapSpinner.setSelection(i, false);
break;
}
}
-
- List<Scheme> schemes;
- try {
- schemes = new ArrayList<Scheme>(Schemes.loadAllSchemes(this).values());
- } catch (IOException e) {
- Log.e("StartGameActivity", e.getMessage(), e);
- schemes = Collections.emptyList();
- }
- adapter = new ArrayAdapter<Scheme>(this, R.layout.listview_item, schemes);
- adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
- gamescheme.setAdapter(adapter);
- for(int i = 0; i < adapter.getCount(); i++){
- if(((Scheme)adapter.getItem(i)).name.equals("Default")){
- gamescheme.setSelection(i, false);
- break;
- }
- }
-
- List<Weaponset> weaponsets;
- try {
- weaponsets = Weaponsets.loadAllWeaponsets(this);
- } catch(IOException e) {
- Log.e("StartGameActivity", e.getMessage(), e);
- weaponsets = Collections.emptyList();
- }
- adapter = new ArrayAdapter<Weaponset>(this, R.layout.listview_item, weaponsets);
- adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
- weapons.setAdapter(adapter);
- for(int i = 0; i < adapter.getCount(); i++){
- if(((Weaponset)adapter.getItem(i)).name.equals("Crazy")){
- weapons.setSelection(i, false);
- break;
- }
- }
-
- List<String> themeList;
- try {
- themeList = FrontendDataUtils.getThemes(this);
- } catch(FileNotFoundException e) {
- Log.e("StartGameActivity", e.getMessage(), e);
- themeList = Collections.emptyList();
- }
- adapter = new ArrayAdapter<String>(this, R.layout.listview_item, themeList);
- adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
- themes.setAdapter(adapter);
- themes.setOnItemSelectedListener(themesClicker);
+ styleSpinner.setSelection(styles.indexOf(GameConfig.DEFAULT_STYLE), false);
+ schemeSpinner.setSelection(schemeNames.indexOf(GameConfig.DEFAULT_SCHEME), false);
+ weaponsetSpinner.setSelection(weaponsetNames.indexOf(GameConfig.DEFAULT_WEAPONSET), false);
+ themeSpinner.setSelection(themes.indexOf(GameConfig.DEFAULT_THEME), false);
}
+ private static Spinner prepareSpinner(View v, int id, List<String> items, OnItemSelectedListener itemSelectedListener) {
+ Spinner spinner = (Spinner)v.findViewById(id);
+ ArrayAdapter<String> adapter = new ArrayAdapter<String>(v.getContext(), R.layout.listview_item, items);
+ adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+ spinner.setAdapter(adapter);
+ spinner.setOnItemSelectedListener(itemSelectedListener);
+ return spinner;
+ }
+
private void startTeamsActivity(){
Intent i = new Intent(StartGameActivity.this, TeamSelectionActivity.class);
TeamSelectionActivity.activityParams = new ArrayList<TeamInGame>(teams);
@@ -190,8 +155,8 @@
private OnItemSelectedListener themesClicker = new OnItemSelectedListener(){
public void onItemSelected(AdapterView<?> arg0, View view, int position, long rowId) {
- String themeName = (String) arg0.getAdapter().getItem(position);
- Drawable themeIconDrawable = Drawable.createFromPath(Utils.getDataPath(StartGameActivity.this) + "Themes/" + themeName + "/icon@2X.png");
+ String themeName = themes.get(position);
+ Drawable themeIconDrawable = Drawable.createFromPath(FileUtils.getDataPath(StartGameActivity.this) + "Themes/" + themeName + "/icon@2X.png");
themeIcon.setImageDrawable(themeIconDrawable);
}
@@ -203,7 +168,7 @@
private OnItemSelectedListener mapsClicker = new OnItemSelectedListener(){
public void onItemSelected(AdapterView<?> arg0, View view, int position,long rowId) {
- MapFile map = (MapFile)arg0.getAdapter().getItem(position);
+ MapFile map = mapFiles.get(position);
try {
File previewFile = map.getPreviewFile(getApplicationContext());
mapPreview.setImageDrawable(Drawable.createFromPath(previewFile.getAbsolutePath()));
@@ -223,13 +188,14 @@
Toast.makeText(getApplicationContext(), R.string.not_enough_teams, Toast.LENGTH_LONG).show();
startTeamsActivity();
} else {
- String style = (String)gameplay.getSelectedItem();
- Scheme scheme = (Scheme)gamescheme.getSelectedItem();
- String mapName = ((MapFile)maps.getSelectedItem()).name;
- String theme = (String)themes.getSelectedItem();
+ String style = styles.get(styleSpinner.getSelectedItemPosition());
+ Scheme scheme = schemes.get(schemeSpinner.getSelectedItemPosition());
+ String mapName = mapFiles.get(mapSpinner.getSelectedItemPosition()).name;
+ String theme = themes.get(themeSpinner.getSelectedItemPosition());
MapRecipe map = MapRecipe.makeMap(mapName, UUID.randomUUID().toString(), theme);
- Weaponset weaponset = (Weaponset)weapons.getSelectedItem();
+ Weaponset weaponset = weaponsets.get(weaponsetSpinner.getSelectedItemPosition());
SDLActivity.startConfig = new GameConfig(style, scheme, map, teams, weaponset);
+ SDLActivity.startNetgame = false;
Intent i = new Intent(StartGameActivity.this, SDLActivity.class);
startActivity(i);
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/TeamAddDialog.java Sat Aug 18 00:47:51 2012 +0200
@@ -0,0 +1,92 @@
+package org.hedgewars.hedgeroid;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+import org.hedgewars.hedgeroid.R;
+import org.hedgewars.hedgeroid.Datastructures.FrontendDataUtils;
+import org.hedgewars.hedgeroid.Datastructures.Team;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.content.DialogInterface;
+import android.content.DialogInterface.OnClickListener;
+import android.os.Bundle;
+import android.support.v4.app.DialogFragment;
+
+public class TeamAddDialog extends DialogFragment {
+ private static final String STATE_TEAMS_ALREADY_IN_GAME = "teamAlreadyInGame";
+ private ArrayList<String> teamsAlreadyInGame;
+ private List<Team> availableTeams;
+ private Listener listener;
+
+ public static interface Listener {
+ void onTeamAddDialogSubmitted(Team newTeam);
+ }
+
+ public TeamAddDialog() {
+ // Only for reflection-based instantiation by the framework
+ }
+
+ TeamAddDialog(Collection<String> teamsAlreadyInGame) {
+ this.teamsAlreadyInGame = new ArrayList<String>(teamsAlreadyInGame);
+ }
+
+ @Override
+ public void onAttach(Activity activity) {
+ super.onAttach(activity);
+ try {
+ listener = (Listener) activity;
+ } catch(ClassCastException e) {
+ throw new ClassCastException("Activity " + activity + " must implement TeamAddDialog.Listener to use TeamAddDialog.");
+ }
+ }
+
+ @Override
+ public void onDetach() {
+ super.onDetach();
+ listener = null;
+ }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ if(savedInstanceState != null) {
+ teamsAlreadyInGame = savedInstanceState.getStringArrayList(STATE_TEAMS_ALREADY_IN_GAME);
+ }
+ availableTeams = new ArrayList<Team>();
+ List<Team> teams = FrontendDataUtils.getTeams(getActivity());
+ for(Team team : teams) {
+ if(!teamsAlreadyInGame.contains(team.name)) {
+ availableTeams.add(team);
+ }
+ }
+ Collections.sort(availableTeams, Team.NAME_ORDER);
+ }
+
+ @Override
+ public Dialog onCreateDialog(Bundle savedInstanceState) {
+ AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
+ builder.setTitle(R.string.dialog_addteam_title);
+ builder.setIcon(R.drawable.human);
+ String[] teamNames = new String[availableTeams.size()];
+ for(int i=0; i<availableTeams.size(); i++) {
+ teamNames[i] = availableTeams.get(i).name;
+ }
+ builder.setItems(teamNames, new OnClickListener() {
+ public void onClick(DialogInterface dialog, int which) {
+ listener.onTeamAddDialogSubmitted(availableTeams.get(which));
+ }
+ });
+ return builder.create();
+ }
+
+ @Override
+ public void onSaveInstanceState(Bundle outState) {
+ super.onSaveInstanceState(outState);
+ outState.putStringArrayList(STATE_TEAMS_ALREADY_IN_GAME, teamsAlreadyInGame);
+ }
+}
--- a/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/TeamCreatorActivity.java Sat Aug 18 00:22:33 2012 +0200
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/TeamCreatorActivity.java Sat Aug 18 00:47:51 2012 +0200
@@ -31,6 +31,7 @@
import org.hedgewars.hedgeroid.Datastructures.FrontendDataUtils;
import org.hedgewars.hedgeroid.Datastructures.Hog;
import org.hedgewars.hedgeroid.Datastructures.Team;
+import org.hedgewars.hedgeroid.util.FileUtils;
import android.app.Activity;
import android.graphics.Bitmap;
@@ -253,41 +254,13 @@
super.onBackPressed();
}
- private int getDifficultyLevelFromText(String text) {
- if (text.equals(getString(R.string.human))) {
- return 0;
- } else if (text.equals(getString(R.string.bot5))) {
- return 1;
- } else if (text.equals(getString(R.string.bot4))) {
- return 2;
- } else if (text.equals(getString(R.string.bot3))) {
- return 3;
- } else if (text.equals(getString(R.string.bot2))) {
- return 4;
- } else {
- return 5;
- }
- }
-
- private String getTxtFromDifficulty(int level) {
- switch(level) {
- case 0: return getString(R.string.human);
- case 1: return getString(R.string.bot5);
- case 2: return getString(R.string.bot4);
- case 3: return getString(R.string.bot3);
- case 4: return getString(R.string.bot2);
- default: return getString(R.string.bot1);
- }
- }
-
private void saveTeam() {
String teamName = name.getText().toString();
String teamFlag = (String)((Map<String, Object>) flag.getSelectedItem()).get("txt");
String teamFort = fort.getSelectedItem().toString();
String teamGrave = (String)((Map<String, Object>) grave.getSelectedItem()).get("txt");
String teamVoice = voice.getSelectedItem().toString();
- String levelString = (String)((Map<String, Object>) difficulty.getSelectedItem()).get("txt");
- int levelInt = getDifficultyLevelFromText(levelString);
+ int levelInt = (Integer)((Map<String, Object>) difficulty.getSelectedItem()).get("level");
List<Hog> hogs = new ArrayList<Hog>();
for (int i = 0; i < hogName.size(); i++) {
@@ -307,7 +280,6 @@
}
try {
team.save(newFile);
- Toast.makeText(TeamCreatorActivity.this, R.string.saved, Toast.LENGTH_SHORT).show();
// If the team was renamed, delete the old file.
if(oldFile != null && oldFile.isFile() && !oldFile.equals(newFile)) {
oldFile.delete();
@@ -322,7 +294,7 @@
public void onItemSelected(AdapterView<?> arg0, View arg1,
int position, long arg3) {
String fortName = (String) arg0.getAdapter().getItem(position);
- Drawable fortIconDrawable = Drawable.createFromPath(Utils
+ Drawable fortIconDrawable = Drawable.createFromPath(FileUtils
.getDataPath(TeamCreatorActivity.this)
+ "Forts/"
+ fortName + "L.png");
@@ -343,7 +315,7 @@
public void onClick(View v) {
try {
File dir = new File(String.format("%sSounds/voices/%s",
- Utils.getDataPath(TeamCreatorActivity.this),
+ FileUtils.getDataPath(TeamCreatorActivity.this),
voice.getSelectedItem()));
String file = "";
File[] dirs = dir.listFiles();
@@ -378,12 +350,12 @@
name.setText(t.name);
voice.setSelection(findPosition((ArrayAdapter<String>) voice.getAdapter(), t.voice));
fort.setSelection(findPosition((ArrayAdapter<String>) fort.getAdapter(), t.fort));
- difficulty.setSelection(findPosition(typesData, getTxtFromDifficulty(t.hogs.get(0).level))); // TODO store actual difficulty int in typesData
- grave.setSelection(findPosition(gravesData, t.grave));
- flag.setSelection(findPosition(flagsData, t.flag));
+ difficulty.setSelection(findPosition(typesData, "level", Integer.valueOf(t.hogs.get(0).level)));
+ grave.setSelection(findPosition(gravesData, "txt", t.grave));
+ flag.setSelection(findPosition(flagsData, "txt", t.flag));
for (int i = 0; i < Team.HEDGEHOGS_PER_TEAM; i++) {
- hogHat.get(i).setSelection(findPosition(hatsData, t.hogs.get(i).hat));
+ hogHat.get(i).setSelection(findPosition(hatsData, "txt", t.hogs.get(i).hat));
hogName.get(i).setText(t.hogs.get(i).name);
}
} catch(NoSuchElementException e) {
@@ -392,18 +364,18 @@
}
}
- int findPosition(ArrayAdapter<String> adapter, String key) throws NoSuchElementException {
- int position = adapter.getPosition(key);
+ int findPosition(ArrayAdapter<String> adapter, String value) throws NoSuchElementException {
+ int position = adapter.getPosition(value);
if(position<0) {
throw new NoSuchElementException();
}
return position;
}
- int findPosition(List<? extends Map<String, ?>> data, String txtValue) throws NoSuchElementException {
+ int findPosition(List<? extends Map<String, ?>> data, String key, Object value) throws NoSuchElementException {
int position = 0;
for (Map<String, ?> map : data) {
- if (map.get("txt").equals(txtValue)) {
+ if (map.get(key).equals(value)) {
return position;
}
position++;
--- a/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/TeamSelectionActivity.java Sat Aug 18 00:22:33 2012 +0200
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/TeamSelectionActivity.java Sat Aug 18 00:47:51 2012 +0200
@@ -125,7 +125,7 @@
setTeamColor(view, (Integer)data);
return true;
case R.id.teamCount:
- setTeamHogCount((ImageView)view, (Integer)data);
+ ((ImageView)view).getDrawable().setLevel((Integer)data);
return true;
default:
return false;
@@ -179,42 +179,6 @@
iv.setBackgroundColor(0xFF000000 + TeamIngameAttributes.TEAM_COLORS[colorIndex]);
}
- private void setTeamHogCount(ImageView iv, int count){
-
- switch(count){
- case 0:
- iv.setImageResource(R.drawable.teamcount0);
- break;
- case 1:
- iv.setImageResource(R.drawable.teamcount1);
- break;
- case 2:
- iv.setImageResource(R.drawable.teamcount2);
- break;
- case 3:
- iv.setImageResource(R.drawable.teamcount3);
- break;
- case 4:
- iv.setImageResource(R.drawable.teamcount4);
- break;
- case 5:
- iv.setImageResource(R.drawable.teamcount5);
- break;
- case 6:
- iv.setImageResource(R.drawable.teamcount6);
- break;
- case 7:
- iv.setImageResource(R.drawable.teamcount7);
- break;
- case 8:
- iv.setImageResource(R.drawable.teamcount8);
- break;
- case 9:
- iv.setImageResource(R.drawable.teamcount9);
- break;
- }
- }
-
public void onBackPressed(){
returnTeams();
super.onBackPressed();
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/TeamlistAdapter.java Sat Aug 18 00:47:51 2012 +0200
@@ -0,0 +1,112 @@
+package org.hedgewars.hedgeroid;
+
+import java.util.Comparator;
+
+import org.hedgewars.hedgeroid.R;
+import org.hedgewars.hedgeroid.Datastructures.TeamInGame;
+import org.hedgewars.hedgeroid.Datastructures.TeamIngameAttributes;
+import org.hedgewars.hedgeroid.util.ObservableTreeMapAdapter;
+
+import android.graphics.drawable.ColorDrawable;
+import android.graphics.drawable.Drawable;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.view.ViewGroup;
+import android.widget.ImageButton;
+import android.widget.TextView;
+
+public class TeamlistAdapter extends ObservableTreeMapAdapter<String, TeamInGame> {
+ private boolean colorHogcountEnabled = false;
+ private Listener listener;
+
+ @Override
+ protected Comparator<TeamInGame> getEntryOrder() {
+ return TeamInGame.NAME_ORDER;
+ }
+
+ public void setColorHogcountEnabled(boolean colorHogcountEnabled) {
+ this.colorHogcountEnabled = colorHogcountEnabled;
+ notifyDataSetChanged();
+ }
+
+ public void setListener(Listener listener) {
+ this.listener = listener;
+ }
+
+ public View getView(int position, View convertView, ViewGroup parent) {
+ View v = convertView;
+ if (v == null) {
+ LayoutInflater vi = LayoutInflater.from(parent.getContext());
+ v = vi.inflate(R.layout.listview_team, null);
+ }
+
+ TeamInGame team = getItem(position);
+ TextView teamNameView = (TextView) v.findViewById(android.R.id.text1);
+ ImageButton colorButton = (ImageButton) v.findViewById(R.id.colorButton);
+ ImageButton hogCountButton = (ImageButton) v.findViewById(R.id.hogCountButton);
+
+ teamNameView.setText(team.team.name);
+ int teamImage;
+ if(team.ingameAttribs.remoteDriven) {
+ teamImage = R.drawable.team_net_by_level;
+ } else {
+ teamImage = R.drawable.team_local_by_level;
+ }
+
+ Drawable d = parent.getContext().getResources().getDrawable(teamImage).mutate();
+ d.setLevel(team.team.hogs.get(0).level);
+ teamNameView.setCompoundDrawablesWithIntrinsicBounds(d, null, null, null);
+ hogCountButton.getDrawable().setLevel(team.ingameAttribs.hogCount);
+ colorButton.setImageDrawable(new ColorDrawable(TeamIngameAttributes.TEAM_COLORS[team.ingameAttribs.colorIndex]));
+
+ colorButton.setEnabled(colorHogcountEnabled);
+ hogCountButton.setEnabled(colorHogcountEnabled);
+
+ colorButton.setOnClickListener(new ButtonClickListener(team, Type.COLOR_BUTTON));
+ hogCountButton.setOnClickListener(new ButtonClickListener(team, Type.HOGCOUNT_BUTTON));
+
+ if(team.ingameAttribs.remoteDriven) {
+ teamNameView.setClickable(false);
+ } else {
+ teamNameView.setOnClickListener(new ButtonClickListener(team, Type.TEAM_VIEW));
+ }
+
+ return v;
+ }
+
+ private static enum Type {COLOR_BUTTON, HOGCOUNT_BUTTON, TEAM_VIEW}
+ private final class ButtonClickListener implements OnClickListener {
+ private final TeamInGame team;
+ private final Type type;
+
+ public ButtonClickListener(TeamInGame team, Type type) {
+ this.team = team;
+ this.type = type;
+ }
+
+ public void onClick(View v) {
+ if(listener != null) {
+ switch(type) {
+ case COLOR_BUTTON:
+ listener.onColorClicked(team);
+ break;
+ case HOGCOUNT_BUTTON:
+ listener.onHogcountClicked(team);
+ break;
+ case TEAM_VIEW:
+ listener.onTeamClicked(team);
+ break;
+ default:
+ throw new IllegalStateException();
+ }
+ }
+ }
+ }
+
+ public interface Listener {
+ void onTeamClicked(TeamInGame team);
+ void onColorClicked(TeamInGame team);
+ void onHogcountClicked(TeamInGame team);
+ }
+}
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/TeamlistFragment.java Sat Aug 18 00:47:51 2012 +0200
@@ -0,0 +1,122 @@
+package org.hedgewars.hedgeroid;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import org.hedgewars.hedgeroid.R;
+import org.hedgewars.hedgeroid.Datastructures.MapRecipe;
+import org.hedgewars.hedgeroid.Datastructures.Scheme;
+import org.hedgewars.hedgeroid.Datastructures.Team;
+import org.hedgewars.hedgeroid.Datastructures.TeamInGame;
+import org.hedgewars.hedgeroid.Datastructures.TeamIngameAttributes;
+import org.hedgewars.hedgeroid.Datastructures.Weaponset;
+import org.hedgewars.hedgeroid.netplay.Netplay;
+
+import android.database.DataSetObserver;
+import android.os.Bundle;
+import android.support.v4.app.ListFragment;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.view.ViewGroup;
+import android.widget.Button;
+
+/**
+ * TODO use an interface for querying and manipulating the team list, to allow re-using this fragment
+ * in local play
+ */
+public class TeamlistFragment extends ListFragment implements TeamlistAdapter.Listener, RoomStateManager.Observer {
+ private Netplay netplay;
+ private TeamlistAdapter adapter;
+ private Button addTeamButton;
+ private DataSetObserver teamlistObserver;
+ private RoomStateManager stateManager;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ try {
+ stateManager = ((RoomStateManager.Provider)getActivity()).getRoomStateManager();
+ } catch(ClassCastException e) {
+ throw new RuntimeException("Hosting activity must implement RoomStateManager.Provider.", e);
+ }
+ netplay = Netplay.getAppInstance(getActivity().getApplicationContext());
+ adapter = new TeamlistAdapter();
+ adapter.setSource(netplay.roomTeamlist);
+ adapter.setColorHogcountEnabled(stateManager.getChiefStatus());
+ adapter.setListener(this);
+ setListAdapter(adapter);
+ stateManager.registerObserver(this);
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ View v = inflater.inflate(R.layout.fragment_teamlist, container, false);
+ addTeamButton = (Button)v.findViewById(R.id.addTeamButton);
+ addTeamButton.setOnClickListener(new OnClickListener() {
+ public void onClick(View v) {
+ new TeamAddDialog(getCurrentTeamNames()).show(getFragmentManager(), "team_add_dialog");
+ }
+ });
+
+ teamlistObserver = new DataSetObserver() {
+ @Override
+ public void onChanged() {
+ addTeamButton.setEnabled(netplay.roomTeamlist.getMap().size() < Team.maxNumberOfTeams);
+ }
+ };
+ netplay.roomTeamlist.registerObserver(teamlistObserver);
+ teamlistObserver.onChanged();
+
+ return v;
+ }
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ adapter.invalidate();
+ adapter.setListener(null);
+ netplay.roomTeamlist.unregisterObserver(teamlistObserver);
+ stateManager.unregisterObserver(this);
+ }
+
+ @Override
+ public void onActivityCreated(Bundle savedInstanceState) {
+ super.onActivityCreated(savedInstanceState);
+ }
+
+ private Collection<String> getCurrentTeamNames() {
+ List<String> names = new ArrayList<String>();
+ for(TeamInGame team : netplay.roomTeamlist.getMap().values()) {
+ names.add(team.team.name);
+ }
+ return names;
+ }
+
+ public void onColorClicked(TeamInGame team) {
+ netplay.sendTeamColorIndex(team.team.name, (team.ingameAttribs.colorIndex+1)%TeamIngameAttributes.TEAM_COLORS.length);
+ }
+
+ public void onHogcountClicked(TeamInGame team) {
+ int newHogCount = team.ingameAttribs.hogCount+1;
+ if(newHogCount>Team.HEDGEHOGS_PER_TEAM) {
+ newHogCount = 1;
+ }
+ netplay.sendTeamHogCount(team.team.name, newHogCount);
+ }
+
+ public void onTeamClicked(TeamInGame team) {
+ netplay.sendRemoveTeam(team.team.name);
+ }
+
+ public void onChiefStatusChanged(boolean isChief) {
+ adapter.setColorHogcountEnabled(isChief);
+ }
+
+ public void onGameStyleChanged(String gameStyle) { }
+ public void onMapChanged(MapRecipe recipe) { }
+ public void onSchemeChanged(Scheme scheme) { }
+ public void onWeaponsetChanged(Weaponset weaponset) { }
+}
--- a/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/Utils.java Sat Aug 18 00:22:33 2012 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,273 +0,0 @@
-/*
- * Hedgewars for Android. An Android port of Hedgewars, a free turn based strategy game
- * Copyright (c) 2011-2012 Richard Deurwaarder <xeli@xelification.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
- */
-
-
-package org.hedgewars.hedgeroid;
-
-import java.io.ByteArrayOutputStream;
-import java.io.Closeable;
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.util.ArrayList;
-import java.util.List;
-
-import android.annotation.TargetApi;
-import android.content.Context;
-import android.content.res.Resources;
-import android.content.res.TypedArray;
-import android.os.Build;
-import android.os.Environment;
-import android.util.Log;
-
-public class Utils {
- private static final String ROOT_DIR = "Data";
- private static final String TAG = "org.hedgewars.hedgeroid";
-
- /**
- * @return true if the data path is currently available. However, it can vanish at any time so
- * normally you should just try to use it and rely on the exceptions.
- */
- public static boolean isDataPathAvailable() {
- return Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState());
- }
-
- /**
- * get the path to which we should download all the data files
- * @param c context
- * @return The directory
- * @throws FileNotFoundException if external storage is not available at the moment
- */
- public static File getCachePath(Context c) throws FileNotFoundException {
- File cachePath = null;
- if(Build.VERSION.SDK_INT < 8){//8 == Build.VERSION_CODES.FROYO
- cachePath = PreFroyoSDCardDir.getDownloadPath(c);
- } else {
- cachePath = FroyoSDCardDir.getDownloadPath(c);
- }
- if(cachePath==null) {
- throw new FileNotFoundException("External storage is currently unavailable");
- } else {
- return cachePath;
- }
- }
-
- public static File getDataPathFile(Context c) throws FileNotFoundException {
- return new File(getCachePath(c), ROOT_DIR);
- }
-
- // TODO Several callers are unaware that this may fail, so it throws an RTE now.
- // Should be handled better though.
- @Deprecated
- public static String getDataPath(Context c) {
- try {
- return getDataPathFile(c).getAbsolutePath()+"/";
- } catch(FileNotFoundException e) {
- throw new RuntimeException(e);
- }
- }
-
- @TargetApi(8)
- private static class FroyoSDCardDir{
- public static File getDownloadPath(Context c){
- return c.getExternalCacheDir();
- }
- }
-
- private static class PreFroyoSDCardDir{
- public static File getDownloadPath(Context c){
- if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){
- File extStorageDir = Environment.getExternalStorageDirectory();
- if(extStorageDir != null) {
- return new File(extStorageDir, "Hedgewars");
- }
- }
- return null;
- }
- }
-
- /**
- * Return a File array with all the files from dirName
- * @param c
- * @param dirName
- * @return
- * @throws FileNotFoundException If the sdcard is not available or the subdirectory "dirName" does not exist
- */
- public static File[] getFilesFromRelativeDir(Context c, String dirName) throws FileNotFoundException {
- File f = new File(getDataPathFile(c), dirName);
-
- if(f.isDirectory()) {
- return f.listFiles();
- } else {
- throw new FileNotFoundException("Directory "+dirName+" does not exist.");
- }
- }
-
- /**
- * Checks if this directory has a file with suffix suffix
- * @param f - directory
- * @return
- */
- public static boolean hasFileWithSuffix(File f, String suffix){
- if(f.isDirectory()){
- for(String s : f.list()){
- if(s.endsWith(suffix)) return true;
- }
- return false;
- }else{
- return false;
- }
- }
-
- /**
- * Gives back all dirs which contain a file with suffix fileSuffix
- * @param c
- * @param path
- * @param fileSuffix
- * @return
- * @throws FileNotFoundException If the sdcard is not available or the subdirectory "path" does not exist
- */
- public static List<String> getDirsWithFileSuffix(Context c, String path, String fileSuffix) throws FileNotFoundException{
- File[] files = getFilesFromRelativeDir(c,path);
- ArrayList<String> ret = new ArrayList<String>();
-
- for(File f : files){
- if(hasFileWithSuffix(f, fileSuffix)) ret.add(f.getName());
- }
- return ret;
- }
-
- /**
- * Get all files from directory dir which have the given suffix
- * @throws FileNotFoundException If the sdcard is not available or the subdirectory "dir" does not exist
- */
- public static ArrayList<String> getFileNamesFromDirWithSuffix(Context c, String dir, String suffix, boolean removeSuffix) throws FileNotFoundException{
- File[] files = Utils.getFilesFromRelativeDir(c, dir);
- ArrayList<String> ret = new ArrayList<String>();
- for(File file : files){
- String s = file.getName();
- if(s.endsWith(suffix)){
- if(removeSuffix) ret.add(s.substring(0, s.length()-suffix.length()));
- else ret.add(s);
- }
- }
- return ret;
- }
-
- /**
- * Close a resource (possibly null), ignoring any IOException.
- */
- public static void closeQuietly(Closeable c) {
- if(c!=null) {
- try {
- c.close();
- } catch(IOException e) {
- Log.w(TAG, e);
- }
- }
- }
-
- /**
- * Write all data from the input stream to the file, creating or overwriting it.
- * The input stream will be closed.
- *
- * @throws IOException
- */
- public static void writeStreamToFile(InputStream is, File file) throws IOException {
- OutputStream os = null;
- byte[] buffer = new byte[8192];
- try {
- os = new FileOutputStream(file);
- int size;
- while((size=is.read(buffer)) != -1) {
- os.write(buffer, 0, size);
- }
- os.close(); // Important to close this non-quietly, in case of exceptions when flushing
- } finally {
- Utils.closeQuietly(is);
- Utils.closeQuietly(os);
- }
- }
-
- /**
- * Moves resources pointed to by sourceResId (from @res/raw/) to the app's private data directory
- * @param c
- * @param sourceResId
- * @param directory
- */
- public static void resRawToFilesDir(Context c, int sourceResId, String directory) throws IOException {
- File targetDir = new File(c.getFilesDir(), directory);
- targetDir.mkdirs();
-
- //Get an array with the resource files ID
- Resources resources = c.getResources();
- TypedArray ta = resources.obtainTypedArray(sourceResId);
- for(int i = 0; i < ta.length(); i++){
- int resId = ta.getResourceId(i, 0);
- String fileName = resources.getResourceEntryName(resId);
- File f = new File(targetDir, fileName);
- writeStreamToFile(resources.openRawResource(resId), f);
- }
- }
-
- /**
- * Crashing - at least it's better than ignoring errors.
- */
- public static void assertZero(int value, String text) {
- if(value != 0) {
- throw new RuntimeException("Result is not zero: " + text);
- }
- }
-
- public static String readToString(InputStream is) throws IOException {
- try {
- ByteArrayOutputStream os = new ByteArrayOutputStream();
- byte[] buffer = new byte[8192];
- int size;
- while((size=is.read(buffer)) != -1) {
- os.write(buffer, 0, size);
- }
- return new String(os.toByteArray());
- } finally {
- closeQuietly(is);
- }
- }
-
- private static final char[] badFilenameChars = new char[] { '/', '\\', ':', '*', '?', '\"', '<', '>', '|', '.', '\0' };
-
- /**
- * Modify the given String so that it can be used as part of a filename
- * without causing problems from illegal/special characters.
- *
- * The result should be similar to the input, but isn't necessarily
- * reversible.
- */
- public static String replaceBadChars(String name) {
- if (name == null || name.trim().length()==0) {
- return "_";
- }
- name = name.trim();
- for (char badChar : badFilenameChars) {
- name = name.replace(badChar, '_');
- }
- return name;
- }
-}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/WeaponsetCreatorActivity.java Sat Aug 18 00:47:51 2012 +0200
@@ -0,0 +1,8 @@
+package org.hedgewars.hedgeroid;
+
+import android.support.v4.app.FragmentActivity;
+
+// TODO
+public class WeaponsetCreatorActivity extends FragmentActivity {
+ public static final String PARAMETER_EXISTING_WEAPONSETNAME="existingWeaponsetName";
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/WeaponsetListActivity.java Sat Aug 18 00:47:51 2012 +0200
@@ -0,0 +1,107 @@
+package org.hedgewars.hedgeroid;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+import org.hedgewars.hedgeroid.Datastructures.Weaponset;
+import org.hedgewars.hedgeroid.Datastructures.Weaponsets;
+
+import android.app.ListActivity;
+import android.content.Intent;
+import android.os.Bundle;
+import android.view.ContextMenu;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.widget.AdapterView;
+import android.widget.AdapterView.AdapterContextMenuInfo;
+import android.widget.AdapterView.OnItemClickListener;
+import android.widget.Button;
+import android.widget.ListAdapter;
+import android.widget.SimpleAdapter;
+import android.widget.Toast;
+
+public class WeaponsetListActivity extends ListActivity implements OnItemClickListener {
+ private List<Weaponset> userWeaponsets;
+ private Button addButton;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_weaponsetlist);
+ addButton = (Button)findViewById(R.id.addButton);
+ addButton.setOnClickListener(new OnClickListener() {
+ public void onClick(View v) {
+ editWeaponset(null);
+ }
+ });
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ updateList();
+ getListView().setOnItemClickListener(this);
+ registerForContextMenu(getListView());
+ }
+
+ private List<Map<String, ?>> weaponsetsToMap(List<Weaponset> weaponsets) {
+ List<Map<String, ?>> result = new ArrayList<Map<String, ?>>();
+ for(Weaponset weaponset : weaponsets) {
+ result.add(Collections.singletonMap("txt", weaponset.name));
+ }
+ return result;
+ }
+
+ public void onItemClick(AdapterView<?> adapterView, View v, int position, long arg3) {
+ editWeaponset(userWeaponsets.get(position).name);
+ }
+
+ @Override
+ public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuinfo){
+ menu.add(ContextMenu.NONE, 0, ContextMenu.NONE, R.string.edit);
+ menu.add(ContextMenu.NONE, 1, ContextMenu.NONE, R.string.delete);
+ }
+
+ @Override
+ public boolean onContextItemSelected(MenuItem item){
+ AdapterView.AdapterContextMenuInfo menuInfo = (AdapterContextMenuInfo) item.getMenuInfo();
+ int position = menuInfo.position;
+ Weaponset weaponset = userWeaponsets.get(position);
+ switch(item.getItemId()){
+ case 0:
+ editWeaponset(weaponset.name);
+ return true;
+ case 1:
+ try {
+ Weaponsets.deleteUserWeaponset(this, weaponset.name);
+ } catch (IOException e) {
+ Toast.makeText(this.getApplicationContext(), R.string.error_missing_sdcard_or_files, Toast.LENGTH_SHORT).show();
+ }
+ updateList();
+ return true;
+ }
+ return false;
+ }
+
+ private void updateList() {
+ try {
+ userWeaponsets = Weaponsets.loadUserWeaponsets(this);
+ } catch (IOException e) {
+ Toast.makeText(this, R.string.error_missing_sdcard_or_files, Toast.LENGTH_LONG).show();
+ finish();
+ }
+ Collections.sort(userWeaponsets, Weaponset.NAME_ORDER);
+ ListAdapter adapter = new SimpleAdapter(this, weaponsetsToMap(userWeaponsets), android.R.layout.simple_list_item_1, new String[]{"txt"}, new int[]{android.R.id.text1});
+ setListAdapter(adapter);
+ }
+
+ private void editWeaponset(String weaponsetName) {
+ Intent i = new Intent(this, WeaponsetCreatorActivity.class);
+ i.putExtra(WeaponsetCreatorActivity.PARAMETER_EXISTING_WEAPONSETNAME, weaponsetName);
+ startActivity(i);
+ }
+}
--- a/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/frontlib/Frontlib.java Sat Aug 18 00:22:33 2012 +0200
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/frontlib/Frontlib.java Sat Aug 18 00:47:51 2012 +0200
@@ -12,7 +12,7 @@
import org.hedgewars.hedgeroid.Datastructures.MetaScheme.Mod;
import org.hedgewars.hedgeroid.Datastructures.MetaScheme.Setting;
import org.hedgewars.hedgeroid.Datastructures.GameConfig;
-import org.hedgewars.hedgeroid.Datastructures.RoomlistRoom;
+import org.hedgewars.hedgeroid.Datastructures.Room;
import org.hedgewars.hedgeroid.Datastructures.Scheme;
import org.hedgewars.hedgeroid.Datastructures.Team;
import org.hedgewars.hedgeroid.Datastructures.TeamInGame;
@@ -26,7 +26,6 @@
import com.sun.jna.Pointer;
import com.sun.jna.PointerType;
import com.sun.jna.Structure;
-import com.sun.jna.ptr.IntByReference;
/**
* Here is an introduction to the most important aspects of the JNA code.
@@ -51,14 +50,12 @@
* representing the data (e.g. SchemePtr.deref() will give you a Scheme object).
*
* Remember that you usually have to destroy structs that you receive from the
- * library, because they are owned by the native code, not Java. For example, if
- * you obtain a {@link MetaschemePtr} metaPtr using flib_metascheme_from_ini,
- * you have to call flib_metascheme_release(metaPtr) after you are done using
- * it. The recommended pattern for most cases is to call deref() on the pointer
- * to get a Java object (that you can keep as long as you like), and then
- * immediately destroy the struct if it needs destroying. To find out whether
- * and how the struct needs to be destroyed, see the library's documentation of
- * the function that you got the struct from.
+ * library, because they are owned by the native code, not Java. The recommended
+ * pattern for most cases is to call deref() on the pointer to get a Java object
+ * (that you can keep as long as you like), and then immediately destroy the
+ * struct if it needs destroying. To find out whether and how the struct needs
+ * to be destroyed, see the library's documentation of the function that you got
+ * the struct from.
*
* To pass new structs to the library, you can use the static createJavaOwned()
* function in each PointerType, which creates a new struct from the Java object
@@ -146,13 +143,13 @@
}
public static class RoomArrayPtr extends PointerType {
- public RoomlistRoom[] getRooms(int count) {
+ public Room[] getRooms(int count) {
Pointer ptr = getPointer();
if(ptr == null) {
- return new RoomlistRoom[0];
+ return new Room[0];
}
Pointer[] untypedPtrs = ptr.getPointerArray(0, count);
- RoomlistRoom[] result = new RoomlistRoom[count];
+ Room[] result = new Room[count];
for(int i=0; i<count; i++) {
result[i] = RoomPtr.deref(untypedPtrs[i]);
}
@@ -161,11 +158,11 @@
}
public static class RoomPtr extends PointerType {
- public RoomlistRoom deref() {
+ public Room deref() {
return deref(getPointer());
}
- public static RoomlistRoom deref(Pointer p) {
+ public static Room deref(Pointer p) {
RoomStruct struct = new RoomStruct(p);
struct.read();
return struct.toRoomlistRoom();
@@ -420,13 +417,12 @@
static class WeaponsetStruct extends Structure {
public static class ByVal extends WeaponsetStruct implements Structure.ByValue {}
public static class ByRef extends WeaponsetStruct implements Structure.ByReference {}
- private static String[] FIELD_ORDER = new String[] {"_referenceCount", "loadout", "crateprob", "crateammo", "delay", "name"};
+ private static String[] FIELD_ORDER = new String[] {"loadout", "crateprob", "crateammo", "delay", "name"};
public WeaponsetStruct() { super(); setFieldOrder(FIELD_ORDER); }
public WeaponsetStruct(Pointer ptr) { super(ptr); setFieldOrder(FIELD_ORDER); }
public void fillFrom(Weaponset weaponset) {
- _referenceCount = 0;
fillWeaponInfo(loadout, weaponset.loadout);
fillWeaponInfo(crateprob, weaponset.crateProb);
fillWeaponInfo(crateammo, weaponset.crateAmmo);
@@ -453,7 +449,6 @@
}
}
- public int _referenceCount;
public byte[] loadout = new byte[Weaponset.WEAPONS_COUNT+1];
public byte[] crateprob = new byte[Weaponset.WEAPONS_COUNT+1];
public byte[] crateammo = new byte[Weaponset.WEAPONS_COUNT+1];
@@ -483,13 +478,17 @@
public void fillFrom(List<Weaponset> list) {
weaponsetCount = list.size();
- weaponsets = new WeaponsetPointerByReference();
- Structure[] structs = weaponsets.toArray(weaponsetCount);
-
- for(int i=0; i<weaponsetCount; i++) {
- WeaponsetPointerByReference pstruct = (WeaponsetPointerByReference)structs[i];
- pstruct.weaponset = new WeaponsetStruct.ByRef();
- pstruct.weaponset.fillFrom(list.get(i));
+ if(weaponsetCount<=0) {
+ weaponsets = null;
+ } else {
+ weaponsets = new WeaponsetPointerByReference();
+ Structure[] structs = weaponsets.toArray(weaponsetCount);
+
+ for(int i=0; i<weaponsetCount; i++) {
+ WeaponsetPointerByReference pstruct = (WeaponsetPointerByReference)structs[i];
+ pstruct.weaponset = new WeaponsetStruct.ByRef();
+ pstruct.weaponset.fillFrom(list.get(i));
+ }
}
}
@@ -525,8 +524,8 @@
public RoomStruct() { super(); setFieldOrder(FIELD_ORDER); }
public RoomStruct(Pointer ptr) { super(ptr); setFieldOrder(FIELD_ORDER); }
- public RoomlistRoom toRoomlistRoom() {
- return new RoomlistRoom(name, map, scheme, weapons, owner, playerCount, teamCount, inProgress);
+ public Room toRoomlistRoom() {
+ return new Room(name, map, scheme, weapons, owner, playerCount, teamCount, inProgress);
}
public boolean inProgress;
@@ -641,31 +640,11 @@
public static class ByVal extends MetaschemeStruct implements Structure.ByValue {}
public static class ByRef extends MetaschemeStruct implements Structure.ByReference {}
- private static String[] FIELD_ORDER = new String[] {"_referenceCount", "settingCount", "modCount", "settings", "mods"};
+ private static String[] FIELD_ORDER = new String[] {"settingCount", "modCount", "settings", "mods"};
public MetaschemeStruct() { super(); setFieldOrder(FIELD_ORDER); }
public MetaschemeStruct(Pointer ptr) { super(ptr); setFieldOrder(FIELD_ORDER); }
- public void fillFrom(MetaScheme metascheme) {
- settingCount = metascheme.settings.size();
- modCount = metascheme.mods.size();
-
- settings = new MetaschemeSettingStruct.ByRef();
- Structure[] settingStructs = settings.toArray(settingCount);
- mods = new MetaschemeModStruct.ByRef();
- Structure[] modStructs = mods.toArray(modCount);
-
- for(int i=0; i<settingCount; i++) {
- MetaschemeSettingStruct mss = (MetaschemeSettingStruct)settingStructs[i];
- mss.fillFrom(metascheme.settings.get(i));
- }
-
- for(int i=0; i<modCount; i++) {
- MetaschemeModStruct mms = (MetaschemeModStruct)modStructs[i];
- mms.fillFrom(metascheme.mods.get(i));
- }
- }
-
/**
* Only use on native-owned structs!
* Calling this method on a Java-owned struct could cause garbage collection of referenced
@@ -691,7 +670,6 @@
return new MetaScheme(modList, settingList);
}
- public int _referenceCount;
public int settingCount;
public int modCount;
public MetaschemeSettingStruct.ByRef settings;
@@ -701,41 +679,39 @@
static class SchemeStruct extends Structure {
public static class ByVal extends SchemeStruct implements Structure.ByValue {}
public static class ByRef extends SchemeStruct implements Structure.ByReference {}
- private static String[] FIELD_ORDER = new String[] {"meta", "name", "settings", "mod"};
+ private static String[] FIELD_ORDER = new String[] {"name", "settings", "mod"};
public SchemeStruct() { super(); setFieldOrder(FIELD_ORDER); }
public SchemeStruct(Pointer ptr) { super(ptr); setFieldOrder(FIELD_ORDER); }
public void fillFrom(Scheme scheme) {
- meta = new MetaschemeStruct.ByRef();
- meta.fillFrom(scheme.metascheme);
+ MetaScheme meta = MetaScheme.INSTANCE;
name = scheme.name;
- settings = new Memory(NATIVE_INT_SIZE * scheme.metascheme.settings.size());
- for(int i=0; i<scheme.metascheme.settings.size(); i++) {
- Integer value = scheme.settings.get(scheme.metascheme.settings.get(i).name);
+ settings = new Memory(NATIVE_INT_SIZE * meta.settings.size());
+ for(int i=0; i<meta.settings.size(); i++) {
+ Integer value = scheme.settings.get(meta.settings.get(i).name);
settings.setInt(NATIVE_INT_SIZE*i, value);
}
- mods = new Memory(NATIVE_BOOL_SIZE * scheme.metascheme.mods.size());
- for(int i=0; i<scheme.metascheme.mods.size(); i++) {
- Boolean value = scheme.mods.get(scheme.metascheme.mods.get(i).name);
+ mods = new Memory(NATIVE_BOOL_SIZE * meta.mods.size());
+ for(int i=0; i<meta.mods.size(); i++) {
+ Boolean value = scheme.mods.get(meta.mods.get(i).name);
mods.setByte(NATIVE_BOOL_SIZE*i, (byte)(value ? 1 : 0));
}
}
public Scheme toScheme() {
- MetaScheme metaScheme = meta.toMetaScheme();
Map<String, Integer> settingsMap = new HashMap<String, Integer>();
- for(int i=0; i<metaScheme.settings.size(); i++) {
- settingsMap.put(metaScheme.settings.get(i).name, settings.getInt(NATIVE_INT_SIZE*i));
+ MetaScheme meta = MetaScheme.INSTANCE;
+ for(int i=0; i<meta.settings.size(); i++) {
+ settingsMap.put(meta.settings.get(i).name, settings.getInt(NATIVE_INT_SIZE*i));
}
Map<String, Boolean> modsMap = new HashMap<String, Boolean>();
- for(int i=0; i<metaScheme.mods.size(); i++) {
- modsMap.put(metaScheme.mods.get(i).name, mods.getByte(i) != 0 ? Boolean.TRUE : Boolean.FALSE);
+ for(int i=0; i<meta.mods.size(); i++) {
+ modsMap.put(meta.mods.get(i).name, mods.getByte(i) != 0 ? Boolean.TRUE : Boolean.FALSE);
}
- return new Scheme(metaScheme, name, settingsMap, modsMap);
+ return new Scheme(name, settingsMap, modsMap);
}
- public MetaschemeStruct.ByRef meta;
public String name;
public Pointer settings;
public Pointer mods;
@@ -763,13 +739,17 @@
public void fillFrom(List<Scheme> schemeList) {
schemeCount = schemeList.size();
- schemes = new SchemePointerByReference();
- Structure[] schemePtrStructs = schemes.toArray(schemeCount);
-
- for(int i=0; i<this.schemeCount; i++) {
- SchemePointerByReference spbr = (SchemePointerByReference)schemePtrStructs[i];
- spbr.scheme = new SchemeStruct.ByRef();
- spbr.scheme.fillFrom(schemeList.get(i));
+ if(schemeCount<=0) {
+ schemes = null;
+ } else {
+ schemes = new SchemePointerByReference();
+ Structure[] schemePtrStructs = schemes.toArray(schemeCount);
+
+ for(int i=0; i<this.schemeCount; i++) {
+ SchemePointerByReference spbr = (SchemePointerByReference)schemePtrStructs[i];
+ spbr.scheme = new SchemeStruct.ByRef();
+ spbr.scheme.fillFrom(schemeList.get(i));
+ }
}
}
@@ -821,13 +801,17 @@
public void fillFrom(List<TeamInGame> teamList, WeaponsetStruct.ByRef weaponset, int initialHealth) {
teamCount = teamList.size();
- teams = new TeamPointerByReference();
- Structure[] teamPtrStructs = teams.toArray(teamCount);
-
- for(int i=0; i<this.teamCount; i++) {
- TeamPointerByReference tpbr = (TeamPointerByReference)teamPtrStructs[i];
- tpbr.team = new TeamStruct.ByRef();
- tpbr.team.fillFrom(teamList.get(i), weaponset, initialHealth);
+ if(teamCount <= 0) {
+ teams = null;
+ } else {
+ teams = new TeamPointerByReference();
+ Structure[] teamPtrStructs = teams.toArray(teamCount);
+
+ for(int i=0; i<this.teamCount; i++) {
+ TeamPointerByReference tpbr = (TeamPointerByReference)teamPtrStructs[i];
+ tpbr.team = new TeamStruct.ByRef();
+ tpbr.team.fillFrom(teamList.get(i), weaponset, initialHealth);
+ }
}
}
@@ -986,7 +970,8 @@
int flib_get_teamcolor_count();
int flib_get_hedgehogs_per_team();
int flib_get_weapons_count();
-
+ MetaschemePtr flib_get_metascheme();
+
// net/netconn.h
static final int NETCONN_STATE_CONNECTING = 0;
static final int NETCONN_STATE_LOBBY = 1;
@@ -1016,7 +1001,7 @@
static final int NETCONN_MAPCHANGE_THEME = 6;
static final int NETCONN_MAPCHANGE_SEED = 7;
- NetconnPtr flib_netconn_create(String playerName, MetaschemePtr meta, String dataDirPath, String host, int port);
+ NetconnPtr flib_netconn_create(String playerName, String dataDirPath, String host, int port);
void flib_netconn_destroy(NetconnPtr conn);
void flib_netconn_tick(NetconnPtr conn);
@@ -1036,7 +1021,7 @@
int flib_netconn_send_toggleReady(NetconnPtr conn);
int flib_netconn_send_addTeam(NetconnPtr conn, TeamPtr team);
int flib_netconn_send_removeTeam(NetconnPtr conn, String teamname);
- int flib_netconn_send_engineMessage(NetconnPtr conn, Buffer message, NativeLong size);
+ int flib_netconn_send_engineMessage(NetconnPtr conn, Pointer message, NativeLong size);
int flib_netconn_send_teamHogCount(NetconnPtr conn, String teamname, int hogcount);
int flib_netconn_send_teamColor(NetconnPtr conn, String teamname, int colorIndex);
int flib_netconn_send_weaponset(NetconnPtr conn, WeaponsetPtr weaponset);
@@ -1047,7 +1032,7 @@
int flib_netconn_send_mapMazeSize(NetconnPtr conn, int mazeSize);
int flib_netconn_send_mapSeed(NetconnPtr conn, String seed);
int flib_netconn_send_mapTheme(NetconnPtr conn, String theme);
- int flib_netconn_send_mapDrawdata(NetconnPtr conn, Buffer drawData, NativeLong size);
+ int flib_netconn_send_mapDrawdata(NetconnPtr conn, Pointer drawData, NativeLong size);
int flib_netconn_send_script(NetconnPtr conn, String scriptName);
int flib_netconn_send_scheme(NetconnPtr conn, SchemePtr scheme);
int flib_netconn_send_roundfinished(NetconnPtr conn, boolean withoutError);
@@ -1109,7 +1094,7 @@
int flib_gameconn_getport(GameconnPtr conn);
void flib_gameconn_tick(GameconnPtr conn);
- int flib_gameconn_send_enginemsg(GameconnPtr conn, Buffer data, NativeLong len);
+ int flib_gameconn_send_enginemsg(GameconnPtr conn, Pointer data, NativeLong len);
int flib_gameconn_send_textmsg(GameconnPtr conn, int msgtype, String msg);
int flib_gameconn_send_chatmsg(GameconnPtr conn, String playername, String msg);
int flib_gameconn_send_quit(GameconnPtr conn);
@@ -1122,6 +1107,10 @@
void flib_gameconn_onEngineMessage(GameconnPtr conn, BytesCallback callback, Pointer context);
// ipc/mapconn.h
+ public static final int MAPIMAGE_WIDTH = 256;
+ public static final int MAPIMAGE_HEIGHT = 128;
+ public static final int MAPIMAGE_BYTES = (MAPIMAGE_WIDTH/8*MAPIMAGE_HEIGHT);
+
MapconnPtr flib_mapconn_create(MapRecipePtr mapdesc);
void flib_mapconn_destroy(MapconnPtr conn);
int flib_mapconn_getport(MapconnPtr conn);
@@ -1149,13 +1138,8 @@
public static final int MAZE_SIZE_MEDIUM_ISLANDS = 4;
public static final int MAZE_SIZE_LARGE_ISLANDS = 5;
- // model/scheme.h
- MetaschemePtr flib_metascheme_from_ini(String filename);
- MetaschemePtr flib_metascheme_retain(MetaschemePtr metainfo);
- void flib_metascheme_release(MetaschemePtr metainfo);
-
// model/schemelist.h
- SchemelistPtr flib_schemelist_from_ini(MetaschemePtr meta, String filename);
+ SchemelistPtr flib_schemelist_from_ini(String filename);
int flib_schemelist_to_ini(String filename, SchemelistPtr list);
void flib_schemelist_destroy(SchemelistPtr list);
@@ -1169,6 +1153,9 @@
int flib_weaponsetlist_to_ini(String filename, WeaponsetListPtr weaponsets);
void flib_weaponsetlist_destroy(WeaponsetListPtr list);
+ // model/gamesetup.h
+ void flib_gamesetup_destroy(GameSetupPtr gamesetup);
+
// util/logging.h
public static final int FLIB_LOGLEVEL_ALL = -100;
public static final int FLIB_LOGLEVEL_DEBUG = -1;
--- a/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/netplay/ChatFragment.java Sat Aug 18 00:22:33 2012 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,76 +0,0 @@
-package org.hedgewars.hedgeroid.netplay;
-
-import org.hedgewars.hedgeroid.R;
-
-import android.os.Bundle;
-import android.support.v4.app.Fragment;
-import android.view.KeyEvent;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.EditText;
-import android.widget.ListView;
-import android.widget.TextView;
-import android.widget.TextView.OnEditorActionListener;
-
-public class ChatFragment extends Fragment {
- public static final String ARGUMENT_INROOM = "inRoom";
-
- private ChatlogAdapter adapter;
- private Netplay netconn;
- private MessageLog messageLog;
- private boolean inRoom;
-
- public void setInRoom(boolean inRoom) {
- this.inRoom = inRoom;
- }
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- netconn = Netplay.getAppInstance(getActivity().getApplicationContext());
- adapter = new ChatlogAdapter(getActivity());
- }
-
- @Override
- public void onStart() {
- super.onStart();
- messageLog = inRoom ? netconn.roomChatlog : netconn.lobbyChatlog;
- adapter.setLog(messageLog.getLog());
- messageLog.registerObserver(adapter);
- }
-
- @Override
- public void onStop() {
- super.onStop();
- messageLog.unregisterObserver(adapter);
- }
-
- @Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container,
- Bundle savedInstanceState) {
- View view = inflater.inflate(R.layout.fragment_chat, container, false);
-
- ListView listView = (ListView) view.findViewById(R.id.chatConsole);
- listView.setAdapter(adapter);
- listView.setDivider(null);
- listView.setDividerHeight(0);
- listView.setVerticalFadingEdgeEnabled(true);
-
- EditText editText = (EditText) view.findViewById(R.id.chatInput);
- editText.setOnEditorActionListener(new ChatSendListener());
-
- return view;
- }
-
- private final class ChatSendListener implements OnEditorActionListener {
- public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
- String text = v.getText().toString();
- if(text.length()>0) {
- v.setText("");
- netconn.sendChat(text);
- }
- return true;
- }
- }
-}
--- a/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/netplay/ChatlogAdapter.java Sat Aug 18 00:22:33 2012 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,95 +0,0 @@
-package org.hedgewars.hedgeroid.netplay;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.List;
-
-import org.hedgewars.hedgeroid.netplay.MessageLog.Observer;
-
-import android.content.Context;
-import android.text.method.LinkMovementMethod;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.AbsListView.LayoutParams;
-import android.widget.BaseAdapter;
-import android.widget.TextView;
-
-/**
- * Optimization: ListView is smart enough to try re-using the same view for an item
- * with the same ID, but it still calls getView for those items when the list changes.
- * Since lines with a given ID never change in our chatlog, we can avoid the effort
- * of TextView.setText in many cases by checking if the view is already set up for the
- * line with the right ID - but to do that, the view needs to remember the ID it's
- * holding the text for. That's what the LoglineView does.
- */
-class LoglineView extends TextView {
- long chatlogId = -1;
-
- public LoglineView(Context context) {
- super(context);
- }
-}
-
-public class ChatlogAdapter extends BaseAdapter implements Observer {
- long idOffset = 0;
- private List<CharSequence> log = new ArrayList<CharSequence>();
- private Context context;
-
- public ChatlogAdapter(Context context) {
- this.context = context;
- }
-
- public int getCount() {
- return log.size();
- }
-
- public Object getItem(int position) {
- return log.get(position);
- }
-
- public long getItemId(int position) {
- return position+idOffset;
- }
-
- public boolean hasStableIds() {
- return true;
- }
-
- public void clear() {
- idOffset += log.size();
- log.clear();
- notifyDataSetChanged();
- }
-
- public void lineAdded(CharSequence text) {
- log.add(text);
- notifyDataSetChanged();
- }
-
- public void lineRemoved() {
- log.remove(0);
- idOffset += 1;
- notifyDataSetChanged();
- }
-
- public void setLog(Collection<CharSequence> log) {
- idOffset += log.size();
- this.log = new ArrayList<CharSequence>(log);
- notifyDataSetChanged();
- }
-
- public View getView(int position, View convertView, ViewGroup parent) {
- LoglineView v = (LoglineView)convertView;
- if (v == null) {
- v = new LoglineView(context);
- v.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT));
- v.setMovementMethod(LinkMovementMethod.getInstance());
- }
- long id = getItemId(position);
- if(id != v.chatlogId) {
- v.setText(log.get(position));
- v.chatlogId = id;
- }
- return v;
- }
-}
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/netplay/GameMessageListener.java Sat Aug 18 00:47:51 2012 +0200
@@ -0,0 +1,15 @@
+package org.hedgewars.hedgeroid.netplay;
+
+/**
+ * Interface with several event callbacks that represent network messages which are interesting
+ * for a running game, e.g. because they concern the lifecycle of the game or because they contain
+ * data that needs to be passed on.
+ *
+ * These functions might be called on any thread.
+ */
+public interface GameMessageListener {
+ void onChatMessage(String nick, String message);
+ void onEngineMessage(byte[] em);
+ void onMessage(int type, String message);
+ void onNetDisconnected();
+}
--- a/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/netplay/LobbyActivity.java Sat Aug 18 00:22:33 2012 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,138 +0,0 @@
-package org.hedgewars.hedgeroid.netplay;
-
-import org.hedgewars.hedgeroid.R;
-import org.hedgewars.hedgeroid.netplay.Netplay.State;
-import org.hedgewars.hedgeroid.netplay.NetplayStateFragment.NetplayStateListener;
-import org.hedgewars.hedgeroid.netplay.TextInputDialog.TextInputDialogListener;
-
-import android.content.Context;
-import android.content.Intent;
-import android.graphics.drawable.Drawable;
-import android.os.Bundle;
-import android.support.v4.app.FragmentActivity;
-import android.support.v4.app.FragmentTransaction;
-import android.view.LayoutInflater;
-import android.view.Menu;
-import android.view.MenuItem;
-import android.view.View;
-import android.widget.ImageView;
-import android.widget.LinearLayout;
-import android.widget.TabHost;
-import android.widget.TextView;
-
-public class LobbyActivity extends FragmentActivity implements TextInputDialogListener, NetplayStateListener {
- private static final int DIALOG_CREATE_ROOM = 0;
-
- private TabHost tabHost;
- private Netplay netplay;
-
- @Override
- protected void onCreate(Bundle icicle) {
- super.onCreate(icicle);
-
- setContentView(R.layout.activity_lobby);
- ChatFragment chatFragment = (ChatFragment)getSupportFragmentManager().findFragmentById(R.id.chatFragment);
- chatFragment.setInRoom(false);
-
- FragmentTransaction trans = getSupportFragmentManager().beginTransaction();
- trans.add(new NetplayStateFragment(), "netplayFragment");
- trans.commit();
-
- netplay = Netplay.getAppInstance(getApplicationContext());
-
- tabHost = (TabHost)findViewById(android.R.id.tabhost);
- if(tabHost != null) {
- tabHost.setup();
- tabHost.getTabWidget().setOrientation(LinearLayout.VERTICAL);
-
- tabHost.addTab(tabHost.newTabSpec("rooms").setIndicator(createIndicatorView(tabHost, R.string.lobby_tab_rooms, getResources().getDrawable(R.drawable.roomlist_ingame))).setContent(R.id.roomListFragment));
- tabHost.addTab(tabHost.newTabSpec("chat").setIndicator(createIndicatorView(tabHost, R.string.lobby_tab_chat, getResources().getDrawable(R.drawable.edit))).setContent(R.id.chatFragment));
- tabHost.addTab(tabHost.newTabSpec("players").setIndicator(createIndicatorView(tabHost, R.string.lobby_tab_players, getResources().getDrawable(R.drawable.human))).setContent(R.id.playerListFragment));
-
- if (icicle != null) {
- tabHost.setCurrentTabByTag(icicle.getString("currentTab"));
- }
- }
- }
-
- private View createIndicatorView(TabHost tabHost, int label, Drawable icon) {
- LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
-
- View tabIndicator = inflater.inflate(R.layout.tab_indicator,
- tabHost.getTabWidget(), // tab widget is the parent
- false); // no inflate params
-
- final TextView tv = (TextView) tabIndicator.findViewById(R.id.title);
- tv.setText(label);
-
- if(icon != null) {
- final ImageView iconView = (ImageView) tabIndicator.findViewById(R.id.icon);
- iconView.setImageDrawable(icon);
- }
-
- return tabIndicator;
- }
-
- @Override
- public boolean onCreateOptionsMenu(Menu menu) {
- super.onCreateOptionsMenu(menu);
- getMenuInflater().inflate(R.menu.lobby_options, menu);
- return true;
- }
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- switch(item.getItemId()) {
- case R.id.room_create:
- TextInputDialog dialog = new TextInputDialog(DIALOG_CREATE_ROOM, R.string.dialog_create_room_title, 0, R.string.dialog_create_room_hint);
- dialog.show(getSupportFragmentManager(), "create_room_dialog");
- return true;
- case R.id.disconnect:
- netplay.disconnect();
- return true;
- default:
- return super.onOptionsItemSelected(item);
- }
- }
-
- @Override
- public void onBackPressed() {
- super.onBackPressed();
- netplay.disconnect();
- }
-
- @Override
- protected void onSaveInstanceState(Bundle icicle) {
- super.onSaveInstanceState(icicle);
- if(tabHost != null) {
- icicle.putString("currentTab", tabHost.getCurrentTabTag());
- }
- }
-
- public void onTextInputDialogSubmitted(int dialogId, String text) {
- if(text != null && text.length()>0) {
- netplay.sendCreateRoom(text);
- }
- }
-
- public void onTextInputDialogCancelled(int dialogId) {
- }
-
- public void onNetplayStateChanged(State newState) {
- switch(newState) {
- case CONNECTING:
- case NOT_CONNECTED:
- finish();
- break;
- case ROOM:
- case INGAME:
- startActivity(new Intent(getApplicationContext(), RoomActivity.class));
- break;
- case LOBBY:
- // Do nothing
- break;
- default:
- throw new IllegalStateException("Unknown connection state: "+newState);
- }
- }
-}
--- a/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/netplay/LobbyPlayerlist.java Sat Aug 18 00:22:33 2012 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,13 +0,0 @@
-package org.hedgewars.hedgeroid.netplay;
-
-import org.hedgewars.hedgeroid.Datastructures.Player;
-
-import android.util.Pair;
-
-public class LobbyPlayerlist extends ObservableTreeMap<String, Pair<Player, Long>> {
- private long nextId = 1;
-
- public void addPlayerWithNewId(String name) {
- put(name, Pair.create(new Player(name), nextId++));
- }
-}
--- a/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/netplay/LobbyPlayerlistAdapter.java Sat Aug 18 00:22:33 2012 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,58 +0,0 @@
-package org.hedgewars.hedgeroid.netplay;
-
-import java.util.Comparator;
-
-import org.hedgewars.hedgeroid.R;
-import org.hedgewars.hedgeroid.Datastructures.Player;
-
-import android.content.Context;
-import android.util.Pair;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.TextView;
-
-public class LobbyPlayerlistAdapter extends ObservableTreeMapAdapter<String, Pair<Player, Long>> {
- private Context context;
-
- public LobbyPlayerlistAdapter(Context context) {
- this.context = context;
- }
-
- @Override
- protected Comparator<Pair<Player, Long>> getEntryOrder() {
- return AlphabeticalOrderComparator.INSTANCE;
- }
-
- public Player getItem(int position) {
- return getEntries().get(position).first;
- }
-
- public long getItemId(int position) {
- return getEntries().get(position).second;
- }
-
- public boolean hasStableIds() {
- return true;
- }
-
- public View getView(int position, View convertView, ViewGroup parent) {
- View v = convertView;
- if (v == null) {
- LayoutInflater vi = LayoutInflater.from(context);
- v = vi.inflate(R.layout.listview_player, null);
- }
-
- String player = getItem(position).name;
- TextView username = (TextView) v.findViewById(android.R.id.text1);
- username.setText(player);
- return v;
- }
-
- private static final class AlphabeticalOrderComparator implements Comparator<Pair<Player, Long>> {
- public static final AlphabeticalOrderComparator INSTANCE = new AlphabeticalOrderComparator();
- public int compare(Pair<Player, Long> lhs, Pair<Player, Long> rhs) {
- return lhs.first.name.compareToIgnoreCase(rhs.first.name);
- };
- }
-}
\ No newline at end of file
--- a/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/netplay/LobbyPlayerlistFragment.java Sat Aug 18 00:22:33 2012 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,74 +0,0 @@
-package org.hedgewars.hedgeroid.netplay;
-
-import org.hedgewars.hedgeroid.R;
-import org.hedgewars.hedgeroid.Datastructures.Player;
-
-import android.os.Bundle;
-import android.support.v4.app.ListFragment;
-import android.view.ContextMenu;
-import android.view.ContextMenu.ContextMenuInfo;
-import android.view.LayoutInflater;
-import android.view.MenuInflater;
-import android.view.MenuItem;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.AdapterView.AdapterContextMenuInfo;
-
-public class LobbyPlayerlistFragment extends ListFragment {
- private Netplay netplay;
- private LobbyPlayerlistAdapter adapter;
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- netplay = Netplay.getAppInstance(getActivity().getApplicationContext());
- adapter = new LobbyPlayerlistAdapter(getActivity());
- adapter.setSource(netplay.lobbyPlayerlist);
- setListAdapter(adapter);
- }
-
- @Override
- public void onDestroy() {
- super.onDestroy();
- adapter.invalidate();
- }
-
- @Override
- public void onActivityCreated(Bundle savedInstanceState) {
- super.onActivityCreated(savedInstanceState);
- registerForContextMenu(getListView());
- }
-
- @Override
- public void onCreateContextMenu(ContextMenu menu, View v,
- ContextMenuInfo menuInfo) {
- super.onCreateContextMenu(menu, v, menuInfo);
- AdapterContextMenuInfo info = (AdapterContextMenuInfo)menuInfo;
- MenuInflater inflater = getActivity().getMenuInflater();
- inflater.inflate(R.menu.lobby_playerlist_context, menu);
- menu.setHeaderIcon(R.drawable.human);
- menu.setHeaderTitle(adapter.getItem(info.position).name);
- }
-
- @Override
- public boolean onContextItemSelected(MenuItem item) {
- AdapterContextMenuInfo info = (AdapterContextMenuInfo)item.getMenuInfo();
- Player player = adapter.getItem(info.position);
- switch(item.getItemId()) {
- case R.id.player_info:
- netplay.sendPlayerInfoQuery(player.name);
- return true;
- case R.id.player_follow:
- netplay.sendFollowPlayer(player.name);
- return true;
- default:
- return super.onContextItemSelected(item);
- }
- }
-
- @Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container,
- Bundle savedInstanceState) {
- return inflater.inflate(R.layout.fragment_playerlist, container, false);
- }
-}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/netplay/NetRoomState.java Sat Aug 18 00:47:51 2012 +0200
@@ -0,0 +1,207 @@
+package org.hedgewars.hedgeroid.netplay;
+
+import static org.hedgewars.hedgeroid.netplay.ThreadedNetConnection.ToNetMsgType.MSG_SEND_GAMESTYLE;
+import static org.hedgewars.hedgeroid.netplay.ThreadedNetConnection.ToNetMsgType.MSG_SEND_MAP;
+import static org.hedgewars.hedgeroid.netplay.ThreadedNetConnection.ToNetMsgType.MSG_SEND_MAP_DRAWDATA;
+import static org.hedgewars.hedgeroid.netplay.ThreadedNetConnection.ToNetMsgType.MSG_SEND_MAP_GENERATOR;
+import static org.hedgewars.hedgeroid.netplay.ThreadedNetConnection.ToNetMsgType.MSG_SEND_MAP_NAME;
+import static org.hedgewars.hedgeroid.netplay.ThreadedNetConnection.ToNetMsgType.MSG_SEND_MAP_SEED;
+import static org.hedgewars.hedgeroid.netplay.ThreadedNetConnection.ToNetMsgType.MSG_SEND_MAP_TEMPLATE;
+import static org.hedgewars.hedgeroid.netplay.ThreadedNetConnection.ToNetMsgType.MSG_SEND_MAP_THEME;
+import static org.hedgewars.hedgeroid.netplay.ThreadedNetConnection.ToNetMsgType.MSG_SEND_MAZE_SIZE;
+import static org.hedgewars.hedgeroid.netplay.ThreadedNetConnection.ToNetMsgType.MSG_SEND_SCHEME;
+import static org.hedgewars.hedgeroid.netplay.ThreadedNetConnection.ToNetMsgType.MSG_SEND_WEAPONSET;
+
+import java.util.Arrays;
+import java.util.LinkedList;
+import java.util.List;
+
+import org.hedgewars.hedgeroid.RoomStateManager;
+import org.hedgewars.hedgeroid.Datastructures.GameConfig;
+import org.hedgewars.hedgeroid.Datastructures.MapRecipe;
+import org.hedgewars.hedgeroid.Datastructures.Scheme;
+import org.hedgewars.hedgeroid.Datastructures.Weaponset;
+import org.hedgewars.hedgeroid.netplay.ThreadedNetConnection.ToNetMsgType;
+
+/**
+ * This class manages the room state in a network game.
+ */
+class NetRoomState implements RoomStateManager {
+ private List<RoomStateManager.Observer> observers = new LinkedList<RoomStateManager.Observer>();
+ private Netplay netplay;
+
+ boolean chief;
+ String gameStyle;
+ Scheme scheme;
+ MapRecipe map;
+ Weaponset weaponset;
+
+ public NetRoomState(Netplay netplay) {
+ this.netplay = netplay;
+ this.map = MapRecipe.makeRandomMap(0, "seed", GameConfig.DEFAULT_THEME);
+ }
+
+ public MapRecipe getMapRecipe() {
+ return map;
+ }
+
+ public boolean getChiefStatus() {
+ return chief;
+ }
+
+ public Scheme getScheme() {
+ return scheme;
+ }
+
+ public String getGameStyle() {
+ return gameStyle;
+ }
+
+ public Weaponset getWeaponset() {
+ return weaponset;
+ }
+
+ public void changeWeaponset(Weaponset weaponset) {
+ if(chief && !weaponset.equals(this.weaponset)) {
+ sendToNet(MSG_SEND_WEAPONSET, weaponset);
+ setWeaponset(weaponset);
+ }
+ }
+
+ public void changeMapRecipe(MapRecipe mapRecipe) {
+ if(chief && !mapRecipe.equals(this.map)) {
+ sendToNet(MSG_SEND_MAP, mapRecipe);
+ setMapRecipe(mapRecipe);
+ }
+ }
+
+ public void changeMapNameAndGenerator(String mapName) {
+ if(chief && !mapName.equals(this.map.name)) {
+ int newGenerator = MapRecipe.generatorForMapname(mapName);
+ if(newGenerator != this.map.mapgen) {
+ sendToNet(MSG_SEND_MAP_GENERATOR, newGenerator, null);
+ }
+ sendToNet(MSG_SEND_MAP_NAME, mapName);
+ setMapRecipe(map.withName(mapName).withMapgen(newGenerator));
+ }
+ }
+
+ public void changeMapTemplate(int template) {
+ if(chief && template != this.map.templateFilter) {
+ sendToNet(MSG_SEND_MAP_TEMPLATE, template, null);
+ setMapRecipe(map.withTemplateFilter(template));
+ }
+ }
+
+ public void changeMazeSize(int mazeSize) {
+ if(chief && mazeSize != this.map.mazeSize) {
+ sendToNet(MSG_SEND_MAZE_SIZE, mazeSize, 0);
+ setMapRecipe(map.withMazeSize(mazeSize));
+ }
+ }
+
+ public void changeMapSeed(String seed) {
+ if(chief && !seed.equals(this.map.seed)) {
+ sendToNet(MSG_SEND_MAP_SEED, seed);
+ setMapRecipe(map.withSeed(seed));
+ }
+ }
+
+ public void changeMapTheme(String theme) {
+ if(chief && !theme.equals(this.map.theme)) {
+ sendToNet(MSG_SEND_MAP_THEME, theme);
+ setMapRecipe(map.withTheme(theme));
+ }
+ }
+
+ public void changeMapDrawdata(byte[] drawdata) {
+ if(chief && !Arrays.equals(drawdata, this.map.getDrawData())) {
+ sendToNet(MSG_SEND_MAP_DRAWDATA, drawdata);
+ setMapRecipe(map.withDrawData(drawdata));
+ }
+ }
+
+ public void changeGameStyle(String gameStyle) {
+ if(chief && !gameStyle.equals(this.gameStyle)) {
+ sendToNet(MSG_SEND_GAMESTYLE, gameStyle);
+ setGameStyle(gameStyle);
+ }
+ }
+
+ public void changeScheme(Scheme scheme) {
+ if(chief && !scheme.equals(this.scheme)) {
+ sendToNet(MSG_SEND_SCHEME, scheme);
+ setScheme(scheme);
+ }
+ }
+
+ void setWeaponset(Weaponset weaponset) {
+ if(!weaponset.equals(this.weaponset)) {
+ this.weaponset = weaponset;
+ for(RoomStateManager.Observer observer : observers) {
+ observer.onWeaponsetChanged(weaponset);
+ }
+ }
+ }
+
+ void setMapRecipe(MapRecipe map) {
+ if(!map.equals(this.map)) {
+ this.map = map;
+ for(RoomStateManager.Observer observer : observers) {
+ observer.onMapChanged(map);
+ }
+ }
+ }
+
+ void setGameStyle(String gameStyle) {
+ if(!gameStyle.equals(this.gameStyle)) {
+ this.gameStyle = gameStyle;
+ for(RoomStateManager.Observer observer : observers) {
+ observer.onGameStyleChanged(gameStyle);
+ }
+ }
+ }
+
+ void setScheme(Scheme scheme) {
+ if(!scheme.equals(this.scheme)) {
+ this.scheme = scheme;
+ for(RoomStateManager.Observer observer : observers) {
+ observer.onSchemeChanged(scheme);
+ }
+ }
+ }
+
+ void setChief(boolean chief) {
+ if(chief != this.chief) {
+ this.chief = chief;
+ for(RoomStateManager.Observer observer : observers) {
+ observer.onChiefStatusChanged(chief);
+ }
+ }
+ }
+
+ void sendFullConfig() {
+ if(chief) {
+ sendToNet(MSG_SEND_GAMESTYLE, gameStyle);
+ sendToNet(MSG_SEND_SCHEME, scheme);
+ sendToNet(MSG_SEND_WEAPONSET, weaponset);
+ sendToNet(MSG_SEND_MAP, map);
+ }
+ }
+
+ public void registerObserver(Observer observer) {
+ observers.add(observer);
+ }
+
+ public void unregisterObserver(Observer observer) {
+ observers.remove(observer);
+ }
+
+ private boolean sendToNet(ToNetMsgType what, Object obj) {
+ return netplay.sendToNet(what, 0, obj);
+ }
+
+ private boolean sendToNet(ToNetMsgType what, int arg1, Object obj) {
+ return netplay.sendToNet(what, arg1, obj);
+ }
+}
--- a/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/netplay/Netplay.java Sat Aug 18 00:22:33 2012 +0200
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/netplay/Netplay.java Sat Aug 18 00:47:51 2012 +0200
@@ -1,48 +1,42 @@
package org.hedgewars.hedgeroid.netplay;
-import java.io.File;
-import java.io.FileNotFoundException;
+import static org.hedgewars.hedgeroid.netplay.ThreadedNetConnection.ToNetMsgType.*;
+
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
import java.util.Map;
import java.util.TreeMap;
-import org.hedgewars.hedgeroid.R;
-import org.hedgewars.hedgeroid.Utils;
-import org.hedgewars.hedgeroid.Datastructures.RoomlistRoom;
+import org.hedgewars.hedgeroid.RoomStateManager;
+import org.hedgewars.hedgeroid.Datastructures.GameConfig;
+import org.hedgewars.hedgeroid.Datastructures.MapRecipe;
+import org.hedgewars.hedgeroid.Datastructures.Player;
+import org.hedgewars.hedgeroid.Datastructures.PlayerInRoom;
+import org.hedgewars.hedgeroid.Datastructures.Room;
+import org.hedgewars.hedgeroid.Datastructures.Scheme;
+import org.hedgewars.hedgeroid.Datastructures.Schemes;
import org.hedgewars.hedgeroid.Datastructures.Team;
import org.hedgewars.hedgeroid.Datastructures.TeamInGame;
import org.hedgewars.hedgeroid.Datastructures.TeamIngameAttributes;
+import org.hedgewars.hedgeroid.Datastructures.Weaponset;
+import org.hedgewars.hedgeroid.Datastructures.Weaponsets;
import org.hedgewars.hedgeroid.frontlib.Flib;
-import org.hedgewars.hedgeroid.frontlib.Frontlib;
-import org.hedgewars.hedgeroid.frontlib.Frontlib.BoolCallback;
-import org.hedgewars.hedgeroid.frontlib.Frontlib.IntStrCallback;
-import org.hedgewars.hedgeroid.frontlib.Frontlib.MetaschemePtr;
-import org.hedgewars.hedgeroid.frontlib.Frontlib.NetconnPtr;
-import org.hedgewars.hedgeroid.frontlib.Frontlib.RoomArrayPtr;
-import org.hedgewars.hedgeroid.frontlib.Frontlib.RoomCallback;
-import org.hedgewars.hedgeroid.frontlib.Frontlib.RoomListCallback;
-import org.hedgewars.hedgeroid.frontlib.Frontlib.RoomPtr;
-import org.hedgewars.hedgeroid.frontlib.Frontlib.StrBoolCallback;
-import org.hedgewars.hedgeroid.frontlib.Frontlib.StrCallback;
-import org.hedgewars.hedgeroid.frontlib.Frontlib.StrIntCallback;
-import org.hedgewars.hedgeroid.frontlib.Frontlib.StrRoomCallback;
-import org.hedgewars.hedgeroid.frontlib.Frontlib.StrStrCallback;
-import org.hedgewars.hedgeroid.frontlib.Frontlib.TeamCallback;
-import org.hedgewars.hedgeroid.frontlib.Frontlib.TeamPtr;
-import org.hedgewars.hedgeroid.frontlib.Frontlib.VoidCallback;
+import org.hedgewars.hedgeroid.netplay.ThreadedNetConnection.ToNetMsgType;
+import org.hedgewars.hedgeroid.util.ObservableTreeMap;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.Intent;
-import android.content.res.Resources;
import android.os.Handler;
-import android.os.HandlerThread;
import android.os.Looper;
import android.os.Message;
import android.support.v4.content.LocalBroadcastManager;
import android.util.Log;
import android.util.Pair;
-import com.sun.jna.Pointer;
/**
* This class manages the application's networking state.
@@ -72,21 +66,25 @@
private final FromNetHandler fromNetHandler = new FromNetHandler();
private State state = State.NOT_CONNECTED;
- private int foregroundUsers = 0; // Reference counter of clients requesting foreground tick speed (fast ticks)
- private boolean chief; // Do we control the current room?
private String playerName;
+ // null or stale if not in room state
+ private final NetRoomState netRoomState = new NetRoomState(this);
+
// null if there is no running connection (==state is NOT_CONNECTED)
private ThreadedNetConnection connection;
- public final LobbyPlayerlist lobbyPlayerlist = new LobbyPlayerlist();
- public final RoomPlayerlist roomPlayerlist = new RoomPlayerlist();
+ public final ObservableTreeMap<String, Player> lobbyPlayerlist = new ObservableTreeMap<String, Player>();
+ public final ObservableTreeMap<String, PlayerInRoom> roomPlayerlist = new ObservableTreeMap<String, PlayerInRoom>();
public final Roomlist roomList = new Roomlist();
public final MessageLog lobbyChatlog;
public final MessageLog roomChatlog;
- public final Teamlist roomTeamlist = new Teamlist();
+ public final ObservableTreeMap<String, TeamInGame> roomTeamlist = new ObservableTreeMap<String, TeamInGame>();
private final Map<String, Team> roomRequestedTeams = new TreeMap<String, Team>();
+ private final List<GameMessageListener> gameMessageListeners = new LinkedList<GameMessageListener>();
+ private final List<RunGameListener> runGameListeners = new LinkedList<RunGameListener>();
+
public Netplay(Context appContext) {
this.appContext = appContext;
broadcastManager = LocalBroadcastManager.getInstance(appContext);
@@ -94,12 +92,52 @@
roomChatlog = new MessageLog(appContext);
}
- private void clearState() {
+ public RoomStateManager getRoomStateManager() {
+ return netRoomState;
+ }
+
+ private void clearLobbyState() {
lobbyPlayerlist.clear();
roomList.clear();
lobbyChatlog.clear();
}
+ private void initRoomState(boolean chief) {
+ roomChatlog.clear();
+ roomPlayerlist.clear();
+ roomTeamlist.clear();
+ roomRequestedTeams.clear();
+
+ try {
+ netRoomState.setChief(chief);
+ netRoomState.setGameStyle(GameConfig.DEFAULT_STYLE);
+ List<Scheme> schemes = Schemes.loadBuiltinSchemes(appContext);
+ netRoomState.setScheme(schemes.get(Schemes.toNameList(schemes).indexOf(GameConfig.DEFAULT_SCHEME)));
+ netRoomState.setMapRecipe(MapRecipe.makeRandomMap(0, MapRecipe.makeRandomSeed(), GameConfig.DEFAULT_THEME));
+ List<Weaponset> weaponsets = Weaponsets.loadBuiltinWeaponsets(appContext);
+ netRoomState.setWeaponset(weaponsets.get(Weaponsets.toNameList(weaponsets).indexOf(GameConfig.DEFAULT_WEAPONSET)));
+ netRoomState.sendFullConfig();
+ } catch(IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public void registerGameMessageListener(GameMessageListener listener) {
+ gameMessageListeners.add(listener);
+ }
+
+ public void unregisterGameMessageListener(GameMessageListener listener) {
+ gameMessageListeners.remove(listener);
+ }
+
+ public void registerRunGameListener(RunGameListener listener) {
+ runGameListeners.add(listener);
+ }
+
+ public void unregisterRunGameListener(RunGameListener listener) {
+ runGameListeners.remove(listener);
+ }
+
public void connectToDefaultServer(String playerName) {
connect(playerName, DEFAULT_SERVER, DEFAULT_PORT);
}
@@ -117,35 +155,39 @@
throw new IllegalStateException("Attempt to start a new connection while the old one was still running.");
}
- clearState();
+ clearLobbyState();
changeState(State.CONNECTING);
connection = ThreadedNetConnection.startConnection(appContext, fromNetHandler, name, host, port);
- connection.setFastTickRate(foregroundUsers > 0);
+ connection.setFastTickRate(true);
}
public void sendNick(String nick) {
playerName = nick;
- sendToNet(ThreadedNetConnection.ToNetHandler.MSG_SEND_NICK, nick);
+ sendToNet(MSG_SEND_NICK, nick);
}
- public void sendPassword(String password) { sendToNet(ThreadedNetConnection.ToNetHandler.MSG_SEND_PASSWORD, password); }
- public void sendQuit(String message) { sendToNet(ThreadedNetConnection.ToNetHandler.MSG_SEND_QUIT, message); }
- public void sendRoomlistRequest() { sendToNet(ThreadedNetConnection.ToNetHandler.MSG_SEND_ROOMLIST_REQUEST); }
- public void sendPlayerInfoQuery(String name) { sendToNet(ThreadedNetConnection.ToNetHandler.MSG_SEND_PLAYER_INFO_REQUEST, name); }
- public void sendChat(String s) { sendToNet(ThreadedNetConnection.ToNetHandler.MSG_SEND_CHAT, s); }
- public void sendFollowPlayer(String nick) { sendToNet(ThreadedNetConnection.ToNetHandler.MSG_SEND_FOLLOW_PLAYER, nick); }
- public void sendJoinRoom(String name) { sendToNet(ThreadedNetConnection.ToNetHandler.MSG_SEND_JOIN_ROOM, name); }
- public void sendCreateRoom(String name) { sendToNet(ThreadedNetConnection.ToNetHandler.MSG_SEND_CREATE_ROOM, name); }
- public void sendLeaveRoom(String message) { sendToNet(ThreadedNetConnection.ToNetHandler.MSG_SEND_LEAVE_ROOM, message); }
- public void sendKick(String player) { sendToNet(ThreadedNetConnection.ToNetHandler.MSG_SEND_KICK, player); }
+ public void sendPassword(String password) { sendToNet(MSG_SEND_PASSWORD, password); }
+ public void sendQuit(String message) { sendToNet(MSG_SEND_QUIT, message); }
+ public void sendRoomlistRequest() { sendToNet(MSG_SEND_ROOMLIST_REQUEST); }
+ public void sendPlayerInfoQuery(String name) { sendToNet(MSG_SEND_PLAYER_INFO_REQUEST, name); }
+ public void sendChat(String s) { sendToNet(MSG_SEND_CHAT, s); }
+ public void sendTeamChat(String s) { sendToNet(MSG_SEND_TEAMCHAT, s); }
+ public void sendFollowPlayer(String nick) { sendToNet(MSG_SEND_FOLLOW_PLAYER, nick); }
+ public void sendJoinRoom(String name) { sendToNet(MSG_SEND_JOIN_ROOM, name); }
+ public void sendCreateRoom(String name) { sendToNet(MSG_SEND_CREATE_ROOM, name); }
+ public void sendLeaveRoom(String message) { sendToNet(MSG_SEND_LEAVE_ROOM, message); }
+ public void sendKick(String player) { sendToNet(MSG_SEND_KICK, player); }
public void sendAddTeam(Team newTeam) {
roomRequestedTeams.put(newTeam.name, newTeam);
- sendToNet(ThreadedNetConnection.ToNetHandler.MSG_SEND_ADD_TEAM, newTeam);
+ sendToNet(MSG_SEND_ADD_TEAM, newTeam);
}
- public void sendRemoveTeam(String teamName) { sendToNet(ThreadedNetConnection.ToNetHandler.MSG_SEND_REMOVE_TEAM, teamName); }
- public void sendTeamColorIndex(String teamName, int colorIndex) { sendToNet(ThreadedNetConnection.ToNetHandler.MSG_SEND_TEAM_COLOR_INDEX, colorIndex, teamName); }
- public void sendTeamHogCount(String teamName, int hogCount) { sendToNet(ThreadedNetConnection.ToNetHandler.MSG_SEND_TEAM_HOG_COUNT, hogCount, teamName); }
+ public void sendRemoveTeam(String teamName) { sendToNet(MSG_SEND_REMOVE_TEAM, teamName); }
+ public void sendTeamColorIndex(String teamName, int colorIndex) { sendToNet(MSG_SEND_TEAM_COLOR_INDEX, colorIndex, teamName); }
+ public void sendTeamHogCount(String teamName, int hogCount) { sendToNet(MSG_SEND_TEAM_HOG_COUNT, hogCount, teamName); }
+ public void sendEngineMessage(byte[] engineMessage) { sendToNet(MSG_SEND_ENGINE_MESSAGE, engineMessage); }
+ public void sendRoundFinished(boolean withoutError) { sendToNet(MSG_SEND_ROUND_FINISHED, Boolean.valueOf(withoutError)); }
+ public void sendToggleReady() { sendToNet(MSG_SEND_TOGGLE_READY); }
- public void disconnect() { sendToNet(ThreadedNetConnection.ToNetHandler.MSG_DISCONNECT, "User Quit"); }
+ public void disconnect() { sendToNet(MSG_DISCONNECT, "User Quit"); }
private static Netplay instance;
@@ -179,51 +221,29 @@
}
public boolean isChief() {
- return chief;
+ if(netRoomState != null) {
+ return netRoomState.chief;
+ } else {
+ return false;
+ }
}
public String getPlayerName() {
return playerName;
}
- /**
- * Indicate that you want network messages to be checked regularly (several times per second).
- * As long as nobody requests fast ticks, the network is only checked once every few seconds
- * to conserve battery power.
- * Once you no longer need fast updates, call unrequestFastTicks.
- */
- public void requestFastTicks() {
- if(foregroundUsers == Integer.MAX_VALUE) {
- throw new RuntimeException("Reference counter overflow");
- }
- if(foregroundUsers == 0 && connection != null) {
- connection.setFastTickRate(true);
- }
- foregroundUsers++;
- }
-
- public void unrequestFastTicks() {
- if(foregroundUsers == 0) {
- throw new RuntimeException("Reference counter underflow");
- }
- foregroundUsers--;
- if(foregroundUsers == 0 && connection != null) {
- connection.setFastTickRate(false);
- }
- }
-
- private boolean sendToNet(int what) {
+ boolean sendToNet(ToNetMsgType what) {
return sendToNet(what, 0, null);
}
- private boolean sendToNet(int what, Object obj) {
+ boolean sendToNet(ToNetMsgType what, Object obj) {
return sendToNet(what, 0, obj);
}
- private boolean sendToNet(int what, int arg1, Object obj) {
+ boolean sendToNet(ToNetMsgType what, int arg1, Object obj) {
if(connection != null) {
Handler handler = connection.toNetHandler;
- return handler.sendMessage(handler.obtainMessage(what, arg1, 0, obj));
+ return handler.sendMessage(handler.obtainMessage(what.ordinal(), arg1, 0, obj));
} else {
return false;
}
@@ -237,33 +257,44 @@
}
}
+ public static enum FromNetMsgType {
+ MSG_LOBBY_JOIN,
+ MSG_LOBBY_LEAVE,
+ MSG_ROOM_JOIN,
+ MSG_ROOM_LEAVE,
+ MSG_CHAT,
+ MSG_MESSAGE,
+ MSG_ROOM_ADD,
+ MSG_ROOM_UPDATE,
+ MSG_ROOM_DELETE,
+ MSG_ROOMLIST,
+ MSG_CONNECTED,
+ MSG_DISCONNECTED,
+ MSG_PASSWORD_REQUEST,
+ MSG_ENTER_ROOM_FROM_LOBBY,
+ MSG_LEAVE_ROOM,
+ MSG_READYSTATE,
+ MSG_TEAM_ADDED,
+ MSG_TEAM_DELETED,
+ MSG_TEAM_ACCEPTED,
+ MSG_TEAM_COLOR_CHANGED,
+ MSG_HOG_COUNT_CHANGED,
+ MSG_ENGINE_MESSAGE,
+ MSG_RUN_GAME,
+ MSG_SCHEME_CHANGED,
+ MSG_MAP_CHANGED,
+ MSG_ROOM_CHIEF_STATUS_CHANGED,
+ MSG_SCRIPT_CHANGED,
+ MSG_WEAPONSET_CHANGED;
+
+ static final List<FromNetMsgType> values = Collections.unmodifiableList(Arrays.asList(FromNetMsgType.values()));
+ }
+
/**
* Processes messages from the networking system. Always runs on the main thread.
*/
@SuppressLint("HandlerLeak")
final class FromNetHandler extends Handler {
- public static final int MSG_LOBBY_JOIN = 0;
- public static final int MSG_LOBBY_LEAVE = 1;
- public static final int MSG_ROOM_JOIN = 2;
- public static final int MSG_ROOM_LEAVE = 3;
- public static final int MSG_CHAT = 4;
- public static final int MSG_MESSAGE = 5;
- public static final int MSG_ROOM_ADD = 6;
- public static final int MSG_ROOM_UPDATE = 7;
- public static final int MSG_ROOM_DELETE = 8;
- public static final int MSG_ROOMLIST = 9;
- public static final int MSG_CONNECTED = 10;
- public static final int MSG_DISCONNECTED = 11;
- public static final int MSG_PASSWORD_REQUEST = 12;
- public static final int MSG_ENTER_ROOM_FROM_LOBBY = 13;
- public static final int MSG_LEAVE_ROOM = 14;
- public static final int MSG_READYSTATE = 15;
- public static final int MSG_TEAM_ADDED = 16;
- public static final int MSG_TEAM_DELETED = 17;
- public static final int MSG_TEAM_ACCEPTED = 18;
- public static final int MSG_TEAM_COLOR_CHANGED = 19;
- public static final int MSG_HOG_COUNT_CHANGED = 20;
-
public FromNetHandler() {
super(Looper.getMainLooper());
}
@@ -271,10 +302,10 @@
@SuppressWarnings("unchecked")
@Override
public void handleMessage(Message msg) {
- switch(msg.what) {
+ switch(FromNetMsgType.values.get(msg.what)) {
case MSG_LOBBY_JOIN: {
String name = (String)msg.obj;
- lobbyPlayerlist.addPlayerWithNewId(name);
+ lobbyPlayerlist.put(name, new Player(name, false, false));
lobbyChatlog.appendPlayerJoin(name);
break;
}
@@ -286,7 +317,12 @@
}
case MSG_ROOM_JOIN: {
String name = (String)msg.obj;
- roomPlayerlist.addPlayerWithNewId(name);
+ Player p = lobbyPlayerlist.get(name);
+ if(p==null) {
+ Log.w("Netplay", "Unknown player joined room: "+name);
+ p = new Player(name, false, false);
+ }
+ roomPlayerlist.put(name, new PlayerInRoom(p, false));
roomChatlog.appendPlayerJoin(name);
break;
}
@@ -299,18 +335,25 @@
case MSG_CHAT: {
Pair<String, String> args = (Pair<String, String>)msg.obj;
getCurrentLog().appendChat(args.first, args.second);
+ for(GameMessageListener listener : gameMessageListeners) {
+ listener.onChatMessage(args.first, args.second);
+ }
break;
}
case MSG_MESSAGE: {
getCurrentLog().appendMessage(msg.arg1, (String)msg.obj);
+ for(GameMessageListener listener : gameMessageListeners) {
+ listener.onMessage(1, (String)msg.obj);
+ }
break;
}
case MSG_ROOM_ADD: {
- roomList.addRoomWithNewId((RoomlistRoom)msg.obj);
+ Room room = (Room)msg.obj;
+ roomList.addRoomWithNewId(room);
break;
}
case MSG_ROOM_UPDATE: {
- Pair<String, RoomlistRoom> args = (Pair<String, RoomlistRoom>)msg.obj;
+ Pair<String, Room> args = (Pair<String, Room>)msg.obj;
roomList.updateRoom(args.first, args.second);
break;
}
@@ -319,7 +362,8 @@
break;
}
case MSG_ROOMLIST: {
- roomList.updateList((RoomlistRoom[])msg.obj);
+ Room[] rooms = (Room[])msg.obj;
+ roomList.updateList(rooms);
break;
}
case MSG_CONNECTED: {
@@ -330,6 +374,9 @@
}
case MSG_DISCONNECTED: {
Pair<Boolean, String> args = (Pair<Boolean, String>)msg.obj;
+ for(GameMessageListener listener : gameMessageListeners) {
+ listener.onNetDisconnected();
+ }
changeState(State.NOT_CONNECTED);
connection = null;
Intent intent = new Intent(ACTION_DISCONNECTED);
@@ -345,12 +392,8 @@
break;
}
case MSG_ENTER_ROOM_FROM_LOBBY: {
- roomChatlog.clear();
- roomPlayerlist.clear();
- roomTeamlist.clear();
- roomRequestedTeams.clear();
+ initRoomState((Boolean)msg.obj);
changeState(State.ROOM);
- chief = (Boolean)msg.obj;
Intent intent = new Intent(ACTION_ENTERED_ROOM_FROM_LOBBY);
broadcastManager.sendBroadcastSync(intent);
break;
@@ -365,15 +408,23 @@
}
case MSG_READYSTATE: {
Pair<String, Boolean> args = (Pair<String, Boolean>)msg.obj;
- roomPlayerlist.setReady(args.first, args.second);
+ String name = args.first;
+ Boolean newReadyState = args.second;
+ PlayerInRoom oldEntry = roomPlayerlist.get(name);
+ if(oldEntry==null) {
+ Log.e("Netplay", "Setting readystate for unknown player "+name);
+ } else {
+ roomPlayerlist.put(name, new PlayerInRoom(oldEntry.player, newReadyState));
+ }
break;
}
case MSG_TEAM_ADDED: {
Team newTeam = (Team)msg.obj;
- TeamIngameAttributes attrs = new TeamIngameAttributes(playerName, roomTeamlist.getUnusedOrRandomColorIndex(), TeamIngameAttributes.DEFAULT_HOG_COUNT, false);
+ int colorIndex = TeamInGame.getUnusedOrRandomColorIndex(roomTeamlist.getMap().values());
+ TeamIngameAttributes attrs = new TeamIngameAttributes(playerName, colorIndex, TeamIngameAttributes.DEFAULT_HOG_COUNT, true);
TeamInGame tig = new TeamInGame(newTeam, attrs);
- roomTeamlist.addTeamWithNewId(tig);
- if(chief) {
+ roomTeamlist.put(newTeam.name, tig);
+ if(isChief()) {
sendTeamColorIndex(newTeam.name, attrs.colorIndex);
sendTeamHogCount(newTeam.name, attrs.hogCount);
}
@@ -386,10 +437,11 @@
case MSG_TEAM_ACCEPTED: {
Team requestedTeam = roomRequestedTeams.remove(msg.obj);
if(requestedTeam!=null) {
- TeamIngameAttributes attrs = new TeamIngameAttributes(playerName, roomTeamlist.getUnusedOrRandomColorIndex(), TeamIngameAttributes.DEFAULT_HOG_COUNT, false);
+ int colorIndex = TeamInGame.getUnusedOrRandomColorIndex(roomTeamlist.getMap().values());
+ TeamIngameAttributes attrs = new TeamIngameAttributes(playerName, colorIndex, TeamIngameAttributes.DEFAULT_HOG_COUNT, false);
TeamInGame tig = new TeamInGame(requestedTeam, attrs);
- roomTeamlist.addTeamWithNewId(tig);
- if(chief) {
+ roomTeamlist.put(requestedTeam.name, tig);
+ if(isChief()) {
sendTeamColorIndex(requestedTeam.name, attrs.colorIndex);
sendTeamHogCount(requestedTeam.name, attrs.hogCount);
}
@@ -399,27 +451,59 @@
break;
}
case MSG_TEAM_COLOR_CHANGED: {
- Pair<TeamInGame, Long> oldEntry = roomTeamlist.get((String)msg.obj);
+ TeamInGame oldEntry = roomTeamlist.get((String)msg.obj);
if(oldEntry != null) {
- TeamInGame tig = oldEntry.first;
- TeamIngameAttributes tiga = tig.ingameAttribs.withColorIndex(msg.arg1);
- roomTeamlist.put(tig.team.name, Pair.create(tig.withAttribs(tiga), oldEntry.second));
+ TeamIngameAttributes newAttribs = oldEntry.ingameAttribs.withColorIndex(msg.arg1);
+ roomTeamlist.put(oldEntry.team.name, oldEntry.withAttribs(newAttribs));
} else {
Log.e("Netplay", "Color update for unknown team "+msg.obj);
}
break;
}
case MSG_HOG_COUNT_CHANGED: {
- Pair<TeamInGame, Long> oldEntry = roomTeamlist.get((String)msg.obj);
+ TeamInGame oldEntry = roomTeamlist.get((String)msg.obj);
if(oldEntry != null) {
- TeamInGame tig = oldEntry.first;
- TeamIngameAttributes tiga = tig.ingameAttribs.withHogCount(msg.arg1);
- roomTeamlist.put(tig.team.name, Pair.create(tig.withAttribs(tiga), oldEntry.second));
+ TeamIngameAttributes newAttribs = oldEntry.ingameAttribs.withHogCount(msg.arg1);
+ roomTeamlist.put(oldEntry.team.name, oldEntry.withAttribs(newAttribs));
} else {
Log.e("Netplay", "Hog count update for unknown team "+msg.obj);
}
break;
}
+ case MSG_ENGINE_MESSAGE: {
+ byte[] em = (byte[])msg.obj;
+ for(GameMessageListener listener : gameMessageListeners) {
+ listener.onEngineMessage(em);
+ }
+ break;
+ }
+ case MSG_RUN_GAME: {
+ GameConfig config = (GameConfig)msg.obj;
+ for(RunGameListener listener : runGameListeners) {
+ listener.runGame(config);
+ }
+ break;
+ }
+ case MSG_MAP_CHANGED: {
+ netRoomState.setMapRecipe((MapRecipe)msg.obj);
+ break;
+ }
+ case MSG_ROOM_CHIEF_STATUS_CHANGED: {
+ netRoomState.setChief((Boolean)msg.obj);
+ break;
+ }
+ case MSG_SCHEME_CHANGED: {
+ netRoomState.setScheme((Scheme)msg.obj);
+ break;
+ }
+ case MSG_SCRIPT_CHANGED: {
+ netRoomState.setGameStyle((String)msg.obj);
+ break;
+ }
+ case MSG_WEAPONSET_CHANGED: {
+ netRoomState.setWeaponset((Weaponset)msg.obj);
+ break;
+ }
default: {
Log.e("FromNetHandler", "Unknown message type: "+msg.what);
break;
@@ -427,376 +511,4 @@
}
}
}
-
- /**
- * This class handles the actual communication with the networking library, on a separate thread.
- */
- private static class ThreadedNetConnection {
- private static final long TICK_INTERVAL_FAST = 100;
- private static final long TICK_INTERVAL_SLOW = 5000;
- private static final Frontlib FLIB = Flib.INSTANCE;
-
- public final ToNetHandler toNetHandler;
-
- private final Context appContext;
- private final FromNetHandler fromNetHandler;
- private final TickHandler tickHandler;
-
- /**
- * conn can only be null while connecting (the first thing in the thread), and directly after disconnecting,
- * in the same message (the looper is shut down on disconnect, so there will be no messages after that).
- */
- private NetconnPtr conn;
- private String playerName;
-
- private ThreadedNetConnection(Context appContext, FromNetHandler fromNetHandler) {
- this.appContext = appContext;
- this.fromNetHandler = fromNetHandler;
-
- HandlerThread thread = new HandlerThread("NetThread");
- thread.start();
- toNetHandler = new ToNetHandler(thread.getLooper());
- tickHandler = new TickHandler(thread.getLooper(), TICK_INTERVAL_FAST, tickCb);
- }
-
- private void connect(final String name, final String host, final int port) {
- toNetHandler.post(new Runnable() {
- public void run() {
- playerName = name == null ? "Player" : name;
- MetaschemePtr meta = null;
- File dataPath;
- try {
- dataPath = Utils.getDataPathFile(appContext);
- } catch (FileNotFoundException e) {
- shutdown(true, appContext.getString(R.string.sdcard_not_mounted));
- return;
- }
- String metaschemePath = new File(dataPath, "metasettings.ini").getAbsolutePath();
- meta = FLIB.flib_metascheme_from_ini(metaschemePath);
- if(meta == null) {
- shutdown(true, appContext.getString(R.string.error_unexpected, "Missing metasettings.ini"));
- return;
- }
- conn = FLIB.flib_netconn_create(playerName, meta, dataPath.getAbsolutePath(), host, port);
- if(conn == null) {
- shutdown(true, appContext.getString(R.string.error_connection_failed));
- return;
- }
- FLIB.flib_netconn_onLobbyJoin(conn, lobbyJoinCb, null);
- FLIB.flib_netconn_onLobbyLeave(conn, lobbyLeaveCb, null);
- FLIB.flib_netconn_onRoomJoin(conn, roomJoinCb, null);
- FLIB.flib_netconn_onRoomLeave(conn, roomLeaveCb, null);
- FLIB.flib_netconn_onChat(conn, chatCb, null);
- FLIB.flib_netconn_onMessage(conn, messageCb, null);
- FLIB.flib_netconn_onRoomAdd(conn, roomAddCb, null);
- FLIB.flib_netconn_onRoomUpdate(conn, roomUpdateCb, null);
- FLIB.flib_netconn_onRoomDelete(conn, roomDeleteCb, null);
- FLIB.flib_netconn_onConnected(conn, connectedCb, null);
- FLIB.flib_netconn_onRoomlist(conn, roomlistCb, null);
- FLIB.flib_netconn_onDisconnected(conn, disconnectCb, null);
- FLIB.flib_netconn_onPasswordRequest(conn, passwordRequestCb, null);
- FLIB.flib_netconn_onEnterRoom(conn, enterRoomCb, null);
- FLIB.flib_netconn_onLeaveRoom(conn, leaveRoomCb, null);
- FLIB.flib_netconn_onReadyState(conn, readyStateCb, null);
- FLIB.flib_netconn_onTeamAdd(conn, teamAddedCb, null);
- FLIB.flib_netconn_onTeamDelete(conn, teamDeletedCb, null);
- FLIB.flib_netconn_onTeamAccepted(conn, teamAcceptedCb, null);
- FLIB.flib_netconn_onTeamColorChanged(conn, teamColorChangedCb, null);
- FLIB.flib_netconn_onHogCountChanged(conn, hogCountChangedCb, null);
-
- FLIB.flib_metascheme_release(meta);
- tickHandler.start();
- }
- });
- }
-
- public static ThreadedNetConnection startConnection(Context appContext, FromNetHandler fromNetHandler, String playerName, String host, int port) {
- ThreadedNetConnection result = new ThreadedNetConnection(appContext, fromNetHandler);
- result.connect(playerName, host, port);
- return result;
- }
-
- public void setFastTickRate(boolean fastTickRate) {
- tickHandler.setInterval(fastTickRate ? TICK_INTERVAL_FAST : TICK_INTERVAL_SLOW);
- }
-
- private final Runnable tickCb = new Runnable() {
- public void run() {
- FLIB.flib_netconn_tick(conn);
- }
- };
-
- private final StrCallback lobbyJoinCb = new StrCallback() {
- public void callback(Pointer context, String name) {
- sendFromNet(FromNetHandler.MSG_LOBBY_JOIN, name);
- }
- };
-
- private final StrStrCallback lobbyLeaveCb = new StrStrCallback() {
- public void callback(Pointer context, String name, String msg) {
- sendFromNet(FromNetHandler.MSG_LOBBY_LEAVE, Pair.create(name, msg));
- }
- };
-
- private final StrCallback roomJoinCb = new StrCallback() {
- public void callback(Pointer context, String name) {
- sendFromNet(FromNetHandler.MSG_ROOM_JOIN, name);
- }
- };
- private final StrStrCallback roomLeaveCb = new StrStrCallback() {
- public void callback(Pointer context, String name, String message) {
- sendFromNet(FromNetHandler.MSG_ROOM_LEAVE, Pair.create(name, message));
- }
- };
- private final StrStrCallback chatCb = new StrStrCallback() {
- public void callback(Pointer context, String name, String msg) {
- sendFromNet(FromNetHandler.MSG_CHAT, Pair.create(name, msg));
- }
- };
-
- private final IntStrCallback messageCb = new IntStrCallback() {
- public void callback(Pointer context, int type, String msg) {
- sendFromNet(FromNetHandler.MSG_MESSAGE, type, msg);
- }
- };
-
- private final RoomCallback roomAddCb = new RoomCallback() {
- public void callback(Pointer context, RoomPtr roomPtr) {
- sendFromNet(FromNetHandler.MSG_ROOM_ADD, roomPtr.deref());
- }
- };
-
- private final StrRoomCallback roomUpdateCb = new StrRoomCallback() {
- public void callback(Pointer context, String name, RoomPtr roomPtr) {
- sendFromNet(FromNetHandler.MSG_ROOM_UPDATE, Pair.create(name, roomPtr.deref()));
- }
- };
-
- private final StrCallback roomDeleteCb = new StrCallback() {
- public void callback(Pointer context, final String name) {
- sendFromNet(FromNetHandler.MSG_ROOM_DELETE, name);
- }
- };
-
- private final RoomListCallback roomlistCb = new RoomListCallback() {
- public void callback(Pointer context, RoomArrayPtr arg1, int count) {
- sendFromNet(FromNetHandler.MSG_ROOMLIST, arg1.getRooms(count));
- }
- };
-
- private final VoidCallback connectedCb = new VoidCallback() {
- public void callback(Pointer context) {
- FLIB.flib_netconn_send_request_roomlist(conn);
- playerName = FLIB.flib_netconn_get_playername(conn);
- sendFromNet(FromNetHandler.MSG_CONNECTED, playerName);
- }
- };
-
- private final StrCallback passwordRequestCb = new StrCallback() {
- public void callback(Pointer context, String nickname) {
- sendFromNet(FromNetHandler.MSG_PASSWORD_REQUEST, playerName);
- }
- };
-
- private final BoolCallback enterRoomCb = new BoolCallback() {
- public void callback(Pointer context, boolean isChief) {
- sendFromNet(FromNetHandler.MSG_ENTER_ROOM_FROM_LOBBY, isChief);
- }
- };
-
- private final IntStrCallback leaveRoomCb = new IntStrCallback() {
- public void callback(Pointer context, int reason, String message) {
- sendFromNet(FromNetHandler.MSG_LEAVE_ROOM, reason, message);
- }
- };
-
- private final StrBoolCallback readyStateCb = new StrBoolCallback() {
- public void callback(Pointer context, String player, boolean ready) {
- sendFromNet(FromNetHandler.MSG_READYSTATE, Pair.create(player, ready));
- }
- };
-
- private final TeamCallback teamAddedCb = new TeamCallback() {
- public void callback(Pointer context, TeamPtr team) {
- sendFromNet(FromNetHandler.MSG_TEAM_ADDED, team.deref().team);
- }
- };
-
- private final StrCallback teamDeletedCb = new StrCallback() {
- public void callback(Pointer context, String teamName) {
- sendFromNet(FromNetHandler.MSG_TEAM_DELETED, teamName);
- }
- };
-
- private final StrCallback teamAcceptedCb = new StrCallback() {
- public void callback(Pointer context, String teamName) {
- sendFromNet(FromNetHandler.MSG_TEAM_ACCEPTED, teamName);
- }
- };
-
- private final StrIntCallback teamColorChangedCb = new StrIntCallback() {
- public void callback(Pointer context, String teamName, int colorIndex) {
- sendFromNet(FromNetHandler.MSG_TEAM_COLOR_CHANGED, colorIndex, teamName);
- }
- };
-
- private final StrIntCallback hogCountChangedCb = new StrIntCallback() {
- public void callback(Pointer context, String teamName, int hogCount) {
- sendFromNet(FromNetHandler.MSG_HOG_COUNT_CHANGED, hogCount, teamName);
- }
- };
-
- private void shutdown(boolean error, String message) {
- if(conn != null) {
- FLIB.flib_netconn_destroy(conn);
- conn = null;
- }
- tickHandler.stop();
- toNetHandler.getLooper().quit();
- sendFromNet(FromNetHandler.MSG_DISCONNECTED, Pair.create(error, message));
- }
-
- private final IntStrCallback disconnectCb = new IntStrCallback() {
- public void callback(Pointer context, int reason, String message) {
- Boolean error = reason != Frontlib.NETCONN_DISCONNECT_NORMAL;
- String messageForUser = createDisconnectUserMessage(appContext.getResources(), reason, message);
- shutdown(error, messageForUser);
- }
- };
-
- private static String createDisconnectUserMessage(Resources res, int reason, String message) {
- switch(reason) {
- case Frontlib.NETCONN_DISCONNECT_AUTH_FAILED:
- return res.getString(R.string.error_auth_failed);
- case Frontlib.NETCONN_DISCONNECT_CONNLOST:
- return res.getString(R.string.error_connection_lost);
- case Frontlib.NETCONN_DISCONNECT_INTERNAL_ERROR:
- return res.getString(R.string.error_unexpected, message);
- case Frontlib.NETCONN_DISCONNECT_SERVER_TOO_OLD:
- return res.getString(R.string.error_server_too_old);
- default:
- return message;
- }
- }
-
- private boolean sendFromNet(int what, Object obj) {
- return fromNetHandler.sendMessage(fromNetHandler.obtainMessage(what, obj));
- }
-
- private boolean sendFromNet(int what, int arg1, Object obj) {
- return fromNetHandler.sendMessage(fromNetHandler.obtainMessage(what, arg1, 0, obj));
- }
-
- /**
- * Processes messages to the networking system. Runs on a non-main thread.
- */
- @SuppressLint("HandlerLeak")
- public final class ToNetHandler extends Handler {
- public static final int MSG_SEND_NICK = 0;
- public static final int MSG_SEND_PASSWORD = 1;
- public static final int MSG_SEND_QUIT = 2;
- public static final int MSG_SEND_ROOMLIST_REQUEST = 3;
- public static final int MSG_SEND_PLAYER_INFO_REQUEST = 4;
- public static final int MSG_SEND_CHAT = 5;
- public static final int MSG_SEND_FOLLOW_PLAYER = 6;
- public static final int MSG_SEND_JOIN_ROOM = 7;
- public static final int MSG_SEND_CREATE_ROOM = 8;
- public static final int MSG_SEND_LEAVE_ROOM = 9;
- public static final int MSG_SEND_KICK = 10;
- public static final int MSG_SEND_ADD_TEAM = 11;
- public static final int MSG_SEND_REMOVE_TEAM = 12;
- public static final int MSG_DISCONNECT = 13;
- public static final int MSG_SEND_TEAM_COLOR_INDEX = 14;
- public static final int MSG_SEND_TEAM_HOG_COUNT = 15;
-
- public ToNetHandler(Looper looper) {
- super(looper);
- }
-
- @Override
- public void handleMessage(Message msg) {
- switch(msg.what) {
- case MSG_SEND_NICK: {
- FLIB.flib_netconn_send_nick(conn, (String)msg.obj);
- break;
- }
- case MSG_SEND_PASSWORD: {
- FLIB.flib_netconn_send_password(conn, (String)msg.obj);
- break;
- }
- case MSG_SEND_QUIT: {
- FLIB.flib_netconn_send_quit(conn, (String)msg.obj);
- break;
- }
- case MSG_SEND_ROOMLIST_REQUEST: {
- FLIB.flib_netconn_send_request_roomlist(conn);
- break;
- }
- case MSG_SEND_PLAYER_INFO_REQUEST: {
- FLIB.flib_netconn_send_playerInfo(conn, (String)msg.obj);
- break;
- }
- case MSG_SEND_CHAT: {
- if(FLIB.flib_netconn_send_chat(conn, (String)msg.obj) == 0) {
- sendFromNet(FromNetHandler.MSG_CHAT, Pair.create(playerName, (String)msg.obj));
- }
- break;
- }
- case MSG_SEND_FOLLOW_PLAYER: {
- FLIB.flib_netconn_send_playerFollow(conn, (String)msg.obj);
- break;
- }
- case MSG_SEND_JOIN_ROOM: {
- FLIB.flib_netconn_send_joinRoom(conn, (String)msg.obj);
- break;
- }
- case MSG_SEND_CREATE_ROOM: {
- FLIB.flib_netconn_send_createRoom(conn, (String)msg.obj);
- break;
- }
- case MSG_SEND_LEAVE_ROOM: {
- if(FLIB.flib_netconn_send_leaveRoom(conn, (String)msg.obj) == 0) {
- sendFromNet(FromNetHandler.MSG_LEAVE_ROOM, -1, "");
- }
- break;
- }
- case MSG_SEND_KICK: {
- FLIB.flib_netconn_send_kick(conn, (String)msg.obj);
- break;
- }
- case MSG_SEND_ADD_TEAM: {
- FLIB.flib_netconn_send_addTeam(conn, TeamPtr.createJavaOwned((Team)msg.obj));
- break;
- }
- case MSG_SEND_REMOVE_TEAM: {
- if(FLIB.flib_netconn_send_removeTeam(conn, (String)msg.obj)==0) {
- sendFromNet(FromNetHandler.MSG_TEAM_DELETED, msg.obj);
- }
- break;
- }
- case MSG_DISCONNECT: {
- FLIB.flib_netconn_send_quit(conn, (String)msg.obj);
- shutdown(false, "User quit");
- break;
- }
- case MSG_SEND_TEAM_COLOR_INDEX: {
- if(FLIB.flib_netconn_send_teamColor(conn, (String)msg.obj, msg.arg1)==0) {
- sendFromNet(FromNetHandler.MSG_TEAM_COLOR_CHANGED, msg.arg1, msg.obj);
- }
- break;
- }
- case MSG_SEND_TEAM_HOG_COUNT: {
- if(FLIB.flib_netconn_send_teamHogCount(conn, (String)msg.obj, msg.arg1)==0) {
- sendFromNet(FromNetHandler.MSG_HOG_COUNT_CHANGED, msg.arg1, msg.obj);
- }
- break;
- }
- default: {
- Log.e("ToNetHandler", "Unknown message type: "+msg.what);
- break;
- }
- }
- }
- }
- }
}
--- a/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/netplay/NetplayStateFragment.java Sat Aug 18 00:22:33 2012 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,121 +0,0 @@
-package org.hedgewars.hedgeroid.netplay;
-
-import org.hedgewars.hedgeroid.R;
-import org.hedgewars.hedgeroid.frontlib.Frontlib;
-import org.hedgewars.hedgeroid.netplay.Netplay.State;
-
-import android.app.Activity;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.os.Bundle;
-import android.support.v4.app.Fragment;
-import android.support.v4.content.LocalBroadcastManager;
-import android.widget.Toast;
-
-/**
- * Fragment for use by an activity that depends on the state of the network
- * connection. The activity must implement the NetplayStateListener interface.
- *
- * This fragment manages a few aspects of the netplay connection: Requesting
- * the network system loop to run at high frequency while the activity is in
- * the foreground, and reacting to changes in the networking state by calling
- * a callback method on the activity.
- */
-public class NetplayStateFragment extends Fragment {
- private Netplay netplay;
- private Context appContext;
- private LocalBroadcastManager broadcastManager;
- private NetplayStateListener listener;
- private State knownState;
-
- interface NetplayStateListener {
- /**
- * This is called while the activity is running, and every time during resume, if
- * a change in the networking state is detected. It is also called once
- * with the initial state (which could be called a change from the "unknown" state).
- */
- void onNetplayStateChanged(State newState);
- }
-
- @Override
- public void onAttach(Activity activity) {
- super.onAttach(activity);
- try {
- listener = (NetplayStateListener) activity;
- } catch(ClassCastException e) {
- throw new ClassCastException("Activity " + activity + " must implement NetplayStateListener to use NetplayStateFragment.");
- }
- }
-
- @Override
- public void onDetach() {
- super.onDetach();
- listener = null;
- }
-
- @Override
- public void onCreate(Bundle icicle) {
- super.onCreate(icicle);
- appContext = getActivity().getApplicationContext();
- broadcastManager = LocalBroadcastManager.getInstance(appContext);
- netplay = Netplay.getAppInstance(appContext);
- }
-
- @Override
- public void onResume() {
- super.onResume();
- broadcastManager.registerReceiver(disconnectReceiver, new IntentFilter(Netplay.ACTION_DISCONNECTED));
- broadcastManager.registerReceiver(leaveRoomReceiver, new IntentFilter(Netplay.ACTION_LEFT_ROOM));
- broadcastManager.registerReceiver(stateChangeReceiver, new IntentFilter(Netplay.ACTION_STATE_CHANGED));
- netplay.requestFastTicks();
-
- State newState = netplay.getState();
- if(knownState != newState) {
- listener.onNetplayStateChanged(newState);
- knownState = newState;
- }
- }
-
- @Override
- public void onPause() {
- super.onPause();
- broadcastManager.unregisterReceiver(disconnectReceiver);
- broadcastManager.unregisterReceiver(leaveRoomReceiver);
- broadcastManager.unregisterReceiver(stateChangeReceiver);
- netplay.unrequestFastTicks();
- }
-
- private final BroadcastReceiver disconnectReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- if(intent.getBooleanExtra(Netplay.EXTRA_HAS_ERROR, true)) {
- String message = intent.getStringExtra(Netplay.EXTRA_MESSAGE);
- String toastText = getString(R.string.toast_disconnected, message);
- Toast.makeText(appContext, toastText, Toast.LENGTH_LONG).show();
- }
- }
- };
-
- private final BroadcastReceiver leaveRoomReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- int reason = intent.getIntExtra(Netplay.EXTRA_REASON, -1);
- if(reason == Frontlib.NETCONN_ROOMLEAVE_ABANDONED) {
- Toast.makeText(appContext, R.string.toast_room_abandoned, Toast.LENGTH_LONG).show();
- } else if(reason == Frontlib.NETCONN_ROOMLEAVE_KICKED) {
- Toast.makeText(appContext, R.string.toast_kicked, Toast.LENGTH_LONG).show();
- }
- }
- };
-
- private final BroadcastReceiver stateChangeReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- State newState = netplay.getState();
- listener.onNetplayStateChanged(newState);
- knownState = newState;
- }
- };
-}
--- a/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/netplay/ObservableTreeMap.java Sat Aug 18 00:22:33 2012 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,43 +0,0 @@
-package org.hedgewars.hedgeroid.netplay;
-
-import java.util.Collections;
-import java.util.Map;
-import java.util.TreeMap;
-
-import android.database.DataSetObservable;
-
-public class ObservableTreeMap<K,V> extends DataSetObservable {
- private final Map<K, V> map = new TreeMap<K, V>();
-
- public void replaceContent(Map<? extends K, ? extends V> newMap) {
- map.clear();
- map.putAll(newMap);
- notifyChanged();
- }
-
- public void put(K key, V value) {
- map.put(key, value);
- notifyChanged();
- }
-
- public V get(K key) {
- return map.get(key);
- }
-
- public void remove(K key) {
- if(map.remove(key) != null) {
- notifyChanged();
- }
- }
-
- public void clear() {
- if(!map.isEmpty()) {
- map.clear();
- notifyChanged();
- }
- }
-
- public Map<K, V> getMap() {
- return Collections.unmodifiableMap(map);
- }
-}
--- a/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/netplay/ObservableTreeMapAdapter.java Sat Aug 18 00:22:33 2012 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,62 +0,0 @@
-package org.hedgewars.hedgeroid.netplay;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.List;
-
-import android.database.DataSetObserver;
-import android.widget.BaseAdapter;
-
-public abstract class ObservableTreeMapAdapter<K,V> extends BaseAdapter {
- private boolean sourceChanged = true;
- private List<V> entries = new ArrayList<V>();
- private ObservableTreeMap<K, V> source;
-
- private DataSetObserver observer = new DataSetObserver() {
- @Override
- public void onChanged() {
- sourceChanged = true;
- notifyDataSetChanged();
- }
-
- @Override
- public void onInvalidated() {
- invalidate();
- }
- };
-
- abstract protected Comparator<V> getEntryOrder();
-
- protected List<V> getEntries() {
- if(sourceChanged) {
- entries.clear();
- entries.addAll(source.getMap().values());
- Collections.sort(entries, getEntryOrder());
- sourceChanged = false;
- }
- return entries;
- }
-
- public int getCount() {
- return getEntries().size();
- }
-
- public void setSource(ObservableTreeMap<K,V> source) {
- if(this.source != null) {
- this.source.unregisterObserver(observer);
- }
- this.source = source;
- this.source.registerObserver(observer);
- sourceChanged = true;
- notifyDataSetChanged();
- }
-
- public void invalidate() {
- if(source != null) {
- source.unregisterObserver(observer);
- }
- source = null;
- notifyDataSetInvalidated();
- }
-}
\ No newline at end of file
--- a/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/netplay/OpenConnectionService.java Sat Aug 18 00:22:33 2012 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,13 +0,0 @@
-package org.hedgewars.hedgeroid.netplay;
-
-import android.app.Service;
-import android.content.Intent;
-import android.os.IBinder;
-
-public class OpenConnectionService extends Service {
- @Override
- public IBinder onBind(Intent intent) {
- return null;
- }
-
-}
--- a/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/netplay/RoomActivity.java Sat Aug 18 00:22:33 2012 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,80 +0,0 @@
-package org.hedgewars.hedgeroid.netplay;
-
-import org.hedgewars.hedgeroid.R;
-import org.hedgewars.hedgeroid.Datastructures.Team;
-import org.hedgewars.hedgeroid.netplay.Netplay.State;
-import org.hedgewars.hedgeroid.netplay.NetplayStateFragment.NetplayStateListener;
-
-import android.os.Bundle;
-import android.support.v4.app.FragmentActivity;
-import android.support.v4.app.FragmentTransaction;
-import android.widget.TabHost;
-import android.widget.Toast;
-
-public class RoomActivity extends FragmentActivity implements NetplayStateListener, TeamAddDialog.Listener {
- private TabHost tabHost;
- private Netplay netplay;
-
- @Override
- protected void onCreate(Bundle icicle) {
- super.onCreate(icicle);
- netplay = Netplay.getAppInstance(getApplicationContext());
-
- setContentView(R.layout.activity_netroom);
- ChatFragment chatFragment = (ChatFragment)getSupportFragmentManager().findFragmentById(R.id.chatFragment);
- chatFragment.setInRoom(true);
-
- FragmentTransaction trans = getSupportFragmentManager().beginTransaction();
- trans.add(new NetplayStateFragment(), "netplayFragment");
- trans.commit();
-
- /*tabHost = (TabHost)findViewById(android.R.id.tabhost);
- if(tabHost != null) {
- tabHost.setup();
- tabHost.getTabWidget().setOrientation(LinearLayout.VERTICAL);
-
- //tabHost.addTab(tabHost.newTabSpec("chat").setIndicator(createIndicatorView(tabHost, R.string.lobby_tab_chat, getResources().getDrawable(R.drawable.edit))).setContent(R.id.chatFragment));
- //tabHost.addTab(tabHost.newTabSpec("players").setIndicator(createIndicatorView(tabHost, R.string.lobby_tab_players, getResources().getDrawable(R.drawable.human))).setContent(R.id.playerListFragment));
-
- if (icicle != null) {
- tabHost.setCurrentTabByTag(icicle.getString("currentTab"));
- }
- }*/
- }
-
- @Override
- public void onBackPressed() {
- netplay.sendLeaveRoom(null);
- }
-
- @Override
- protected void onSaveInstanceState(Bundle icicle) {
- super.onSaveInstanceState(icicle);
- if(tabHost != null) {
- icicle.putString("currentTab", tabHost.getCurrentTabTag());
- }
- }
-
- public void onNetplayStateChanged(State newState) {
- switch(newState) {
- case NOT_CONNECTED:
- case CONNECTING:
- case LOBBY:
- finish();
- break;
- case ROOM:
- // Do nothing
- break;
- case INGAME:
- //startActivity(new Intent(getApplicationContext(), RoomActivity.class));
- Toast.makeText(getApplicationContext(), R.string.not_implemented_yet, Toast.LENGTH_SHORT).show();
- break;
- default:
- throw new IllegalStateException("Unknown connection state: "+newState);
- }
- }
-
- public void onTeamAddDialogSubmitted(Team newTeam) {
- netplay.sendAddTeam(newTeam);
- }
-}
--- a/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/netplay/RoomPlayerlist.java Sat Aug 18 00:22:33 2012 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,36 +0,0 @@
-package org.hedgewars.hedgeroid.netplay;
-
-import org.hedgewars.hedgeroid.Datastructures.Player;
-import org.hedgewars.hedgeroid.netplay.RoomPlayerlist.PlayerInRoom;
-
-import android.util.Log;
-
-public class RoomPlayerlist extends ObservableTreeMap<String, PlayerInRoom> {
- private long nextId = 1;
-
- public void addPlayerWithNewId(String name) {
- put(name, new PlayerInRoom(new Player(name), nextId++, false));
- }
-
- public void setReady(String name, boolean ready) {
- PlayerInRoom oldEntry = get(name);
- if(oldEntry==null) {
- Log.e("RoomPlayerlist", "Setting readystate for unknown player "+name);
- } else {
- put(name, new PlayerInRoom(oldEntry.player, oldEntry.id, ready));
- }
- }
-
- // Immutable
- public static class PlayerInRoom {
- public final Player player;
- public final long id;
- public final boolean ready;
-
- public PlayerInRoom(Player player, long id, boolean ready) {
- this.player = player;
- this.id = id;
- this.ready = ready;
- }
- }
-}
--- a/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/netplay/RoomPlayerlistAdapter.java Sat Aug 18 00:22:33 2012 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,59 +0,0 @@
-package org.hedgewars.hedgeroid.netplay;
-
-import java.util.Comparator;
-
-import org.hedgewars.hedgeroid.R;
-import org.hedgewars.hedgeroid.netplay.RoomPlayerlist.PlayerInRoom;
-
-import android.content.Context;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.TextView;
-
-public class RoomPlayerlistAdapter extends ObservableTreeMapAdapter<String, PlayerInRoom> {
- private Context context;
-
- public RoomPlayerlistAdapter(Context context) {
- this.context = context;
- }
-
- @Override
- protected Comparator<PlayerInRoom> getEntryOrder() {
- return AlphabeticalOrderComparator.INSTANCE;
- }
-
- public PlayerInRoom getItem(int position) {
- return getEntries().get(position);
- }
-
- public long getItemId(int position) {
- return getEntries().get(position).id;
- }
-
- public boolean hasStableIds() {
- return true;
- }
-
- public View getView(int position, View convertView, ViewGroup parent) {
- View v = convertView;
- if (v == null) {
- LayoutInflater vi = LayoutInflater.from(context);
- v = vi.inflate(R.layout.listview_player, null);
- }
-
- PlayerInRoom player = getItem(position);
- TextView username = (TextView) v.findViewById(android.R.id.text1);
- username.setText(player.player.name);
- int readyDrawable = player.ready ? R.drawable.lightbulb_on : R.drawable.lightbulb_off;
- username.setCompoundDrawablesWithIntrinsicBounds(readyDrawable, 0, 0, 0);
- return v;
- }
-
- private static final class AlphabeticalOrderComparator implements Comparator<PlayerInRoom> {
- public static final AlphabeticalOrderComparator INSTANCE = new AlphabeticalOrderComparator();
- public int compare(PlayerInRoom lhs, PlayerInRoom rhs) {
- return lhs.player.name.compareToIgnoreCase(rhs.player.name);
- };
- }
-}
\ No newline at end of file
--- a/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/netplay/RoomPlayerlistFragment.java Sat Aug 18 00:22:33 2012 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,79 +0,0 @@
-package org.hedgewars.hedgeroid.netplay;
-
-import org.hedgewars.hedgeroid.R;
-import org.hedgewars.hedgeroid.netplay.RoomPlayerlist.PlayerInRoom;
-
-import android.os.Bundle;
-import android.support.v4.app.ListFragment;
-import android.view.ContextMenu;
-import android.view.ContextMenu.ContextMenuInfo;
-import android.view.LayoutInflater;
-import android.view.MenuInflater;
-import android.view.MenuItem;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.AdapterView.AdapterContextMenuInfo;
-
-public class RoomPlayerlistFragment extends ListFragment {
- private Netplay netplay;
- private RoomPlayerlistAdapter adapter;
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- netplay = Netplay.getAppInstance(getActivity().getApplicationContext());
- adapter = new RoomPlayerlistAdapter(getActivity());
- adapter.setSource(netplay.roomPlayerlist);
- setListAdapter(adapter);
- }
-
- @Override
- public void onDestroy() {
- super.onDestroy();
- adapter.invalidate();
- }
-
- @Override
- public void onActivityCreated(Bundle savedInstanceState) {
- super.onActivityCreated(savedInstanceState);
- registerForContextMenu(getListView());
- }
-
- @Override
- public void onCreateContextMenu(ContextMenu menu, View v,
- ContextMenuInfo menuInfo) {
- super.onCreateContextMenu(menu, v, menuInfo);
- AdapterContextMenuInfo info = (AdapterContextMenuInfo)menuInfo;
- String playerName = adapter.getItem(info.position).player.name;
-
- MenuInflater inflater = getActivity().getMenuInflater();
- inflater.inflate(R.menu.room_playerlist_context, menu);
- if(netplay.isChief() && !playerName.equals(netplay.getPlayerName())) {
- inflater.inflate(R.menu.room_playerlist_chief_context, menu);
- }
- menu.setHeaderIcon(R.drawable.human);
- menu.setHeaderTitle(playerName);
- }
-
- @Override
- public boolean onContextItemSelected(MenuItem item) {
- AdapterContextMenuInfo info = (AdapterContextMenuInfo)item.getMenuInfo();
- PlayerInRoom player = adapter.getItem(info.position);
- switch(item.getItemId()) {
- case R.id.player_info:
- netplay.sendPlayerInfoQuery(player.player.name);
- return true;
- case R.id.player_kick:
- netplay.sendKick(player.player.name);
- return true;
- default:
- return super.onContextItemSelected(item);
- }
- }
-
- @Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container,
- Bundle savedInstanceState) {
- return inflater.inflate(R.layout.fragment_playerlist, container, false);
- }
-}
--- a/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/netplay/Roomlist.java Sat Aug 18 00:22:33 2012 +0200
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/netplay/Roomlist.java Sat Aug 18 00:47:51 2012 +0200
@@ -3,37 +3,37 @@
import java.util.Map;
import java.util.TreeMap;
-import org.hedgewars.hedgeroid.Datastructures.RoomlistRoom;
+import org.hedgewars.hedgeroid.Datastructures.Room;
+import org.hedgewars.hedgeroid.Datastructures.RoomWithId;
+import org.hedgewars.hedgeroid.util.ObservableTreeMap;
-import android.util.Pair;
-
-public class Roomlist extends ObservableTreeMap<String, Pair<RoomlistRoom, Long>> {
+public class Roomlist extends ObservableTreeMap<String, RoomWithId> {
private long nextId = 1;
- public void updateList(RoomlistRoom[] newRooms) {
- Map<String, Pair<RoomlistRoom, Long>> newMap = new TreeMap<String, Pair<RoomlistRoom, Long>>();
- for(RoomlistRoom room : newRooms) {
- Pair<RoomlistRoom, Long> oldEntry = get(room.name);
+ public void updateList(Room[] newRooms) {
+ Map<String, RoomWithId> newMap = new TreeMap<String, RoomWithId>();
+ for(Room room : newRooms) {
+ RoomWithId oldEntry = get(room.name);
if(oldEntry == null) {
- newMap.put(room.name, Pair.create(room, nextId++));
+ newMap.put(room.name, new RoomWithId(room, nextId++));
} else {
- newMap.put(room.name, Pair.create(room, oldEntry.second));
+ newMap.put(room.name, new RoomWithId(room, oldEntry.id));
}
}
replaceContent(newMap);
}
- public void addRoomWithNewId(RoomlistRoom room) {
- put(room.name, Pair.create(room, nextId++));
+ public void addRoomWithNewId(Room room) {
+ put(room.name, new RoomWithId(room, nextId++));
}
- public void updateRoom(String name, RoomlistRoom room) {
- Pair<RoomlistRoom, Long> oldEntry = get(name);
+ public void updateRoom(String name, Room room) {
+ RoomWithId oldEntry = get(name);
if(oldEntry == null) {
addRoomWithNewId(room);
} else {
remove(name);
- put(room.name, Pair.create(room, oldEntry.second));
+ put(room.name, new RoomWithId(room, oldEntry.id));
}
}
}
--- a/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/netplay/RoomlistAdapter.java Sat Aug 18 00:22:33 2012 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,99 +0,0 @@
-package org.hedgewars.hedgeroid.netplay;
-
-import java.util.Comparator;
-
-import org.hedgewars.hedgeroid.R;
-import org.hedgewars.hedgeroid.Datastructures.RoomlistRoom;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.util.Pair;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.TextView;
-
-public class RoomlistAdapter extends ObservableTreeMapAdapter<String, Pair<RoomlistRoom, Long>> {
- private Context context;
-
- public RoomlistAdapter(Context context) {
- this.context = context;
- }
-
- @Override
- protected Comparator<Pair<RoomlistRoom, Long>> getEntryOrder() {
- return RoomAgeComparator.INSTANCE;
- }
-
- public RoomlistRoom getItem(int position) {
- return getEntries().get(position).first;
- }
-
- public long getItemId(int position) {
- return getEntries().get(position).second;
- }
-
- public boolean hasStableIds() {
- return true;
- }
-
- private static CharSequence formatExtra(Resources res, RoomlistRoom room) {
- String ownermsg = res.getString(R.string.roomlist_owner, room.owner);
- String mapmsg = res.getString(R.string.roomlist_map, room.formatMapName(res));
- String scheme = room.scheme.equals(room.weapons) ? room.scheme : room.scheme + " / " + room.weapons;
- String schememsg = res.getString(R.string.roomlist_scheme, scheme);
- return ownermsg + ". " + mapmsg + ", " + schememsg;
- }
-
- public View getView(int position, View convertView, ViewGroup parent) {
- View v = convertView;
- if (v == null) {
- LayoutInflater vi = LayoutInflater.from(context);
- v = vi.inflate(R.layout.listview_room, null);
- }
-
- RoomlistRoom room = getItem(position);
- int iconRes = room.inProgress ? R.drawable.roomlist_ingame : R.drawable.roomlist_preparing;
-
- if(v.findViewById(android.R.id.text1) == null) {
- // Tabular room list
- TextView roomnameView = (TextView)v.findViewById(R.id.roomname);
- TextView playerCountView = (TextView)v.findViewById(R.id.playercount);
- TextView teamCountView = (TextView)v.findViewById(R.id.teamcount);
- TextView ownerView = (TextView)v.findViewById(R.id.owner);
- TextView mapView = (TextView)v.findViewById(R.id.map);
- TextView schemeView = (TextView)v.findViewById(R.id.scheme);
- TextView weaponView = (TextView)v.findViewById(R.id.weapons);
-
- roomnameView.setCompoundDrawablesWithIntrinsicBounds(iconRes, 0, 0, 0);
- roomnameView.setText(room.name);
- if(playerCountView != null) {
- playerCountView.setText(String.valueOf(room.playerCount));
- }
- if(teamCountView != null) {
- teamCountView.setText(String.valueOf(room.teamCount));
- }
- ownerView.setText(room.owner);
- mapView.setText(room.formatMapName(context.getResources()));
- schemeView.setText(room.scheme);
- weaponView.setText(room.weapons);
- } else {
- // Small room list
- TextView v1 = (TextView)v.findViewById(android.R.id.text1);
- TextView v2 = (TextView)v.findViewById(android.R.id.text2);
-
- v1.setCompoundDrawablesWithIntrinsicBounds(iconRes, 0, 0, 0);
- v1.setText(room.name);
- v2.setText(formatExtra(context.getResources(), room));
- }
-
- return v;
- }
-
- private static final class RoomAgeComparator implements Comparator<Pair<RoomlistRoom, Long>> {
- public static final RoomAgeComparator INSTANCE = new RoomAgeComparator();
- public int compare(Pair<RoomlistRoom, Long> lhs, Pair<RoomlistRoom, Long> rhs) {
- return rhs.second.compareTo(lhs.second);
- }
- }
-}
\ No newline at end of file
--- a/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/netplay/RoomlistFragment.java Sat Aug 18 00:22:33 2012 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,71 +0,0 @@
-package org.hedgewars.hedgeroid.netplay;
-
-import org.hedgewars.hedgeroid.R;
-
-import android.os.Bundle;
-import android.os.CountDownTimer;
-import android.support.v4.app.ListFragment;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.AdapterView;
-import android.widget.AdapterView.OnItemClickListener;
-
-public class RoomlistFragment extends ListFragment implements OnItemClickListener {
- private static final int AUTO_REFRESH_INTERVAL_MS = 15000;
-
- private Netplay netplay;
- private RoomlistAdapter adapter;
- private CountDownTimer autoRefreshTimer = new CountDownTimer(Long.MAX_VALUE, AUTO_REFRESH_INTERVAL_MS) {
- @Override
- public void onTick(long millisUntilFinished) {
- netplay.sendRoomlistRequest();
- }
-
- @Override
- public void onFinish() { }
- };
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- netplay = Netplay.getAppInstance(getActivity().getApplicationContext());
- adapter = new RoomlistAdapter(getActivity());
- adapter.setSource(netplay.roomList);
- setListAdapter(adapter);
- }
-
- @Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container,
- Bundle savedInstanceState) {
- return inflater.inflate(R.layout.lobby_rooms_fragment, container, false);
- }
-
- @Override
- public void onActivityCreated(Bundle savedInstanceState) {
- super.onActivityCreated(savedInstanceState);
- getListView().setOnItemClickListener(this);
- }
-
- @Override
- public void onResume() {
- super.onResume();
- autoRefreshTimer.start();
- }
-
- @Override
- public void onPause() {
- super.onPause();
- autoRefreshTimer.cancel();
- }
-
- @Override
- public void onDestroy() {
- super.onDestroy();
- adapter.invalidate();
- }
-
- public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
- netplay.sendJoinRoom(adapter.getItem(position).name);
- }
-}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/netplay/RunGameListener.java Sat Aug 18 00:47:51 2012 +0200
@@ -0,0 +1,7 @@
+package org.hedgewars.hedgeroid.netplay;
+
+import org.hedgewars.hedgeroid.Datastructures.GameConfig;
+
+public interface RunGameListener {
+ void runGame(GameConfig config);
+}
--- a/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/netplay/TeamAddDialog.java Sat Aug 18 00:22:33 2012 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,92 +0,0 @@
-package org.hedgewars.hedgeroid.netplay;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.List;
-
-import org.hedgewars.hedgeroid.R;
-import org.hedgewars.hedgeroid.Datastructures.FrontendDataUtils;
-import org.hedgewars.hedgeroid.Datastructures.Team;
-
-import android.app.Activity;
-import android.app.AlertDialog;
-import android.app.Dialog;
-import android.content.DialogInterface;
-import android.content.DialogInterface.OnClickListener;
-import android.os.Bundle;
-import android.support.v4.app.DialogFragment;
-
-public class TeamAddDialog extends DialogFragment {
- private static final String STATE_TEAMS_ALREADY_IN_GAME = "teamAlreadyInGame";
- private ArrayList<String> teamsAlreadyInGame;
- private List<Team> availableTeams;
- private Listener listener;
-
- public static interface Listener {
- void onTeamAddDialogSubmitted(Team newTeam);
- }
-
- public TeamAddDialog() {
- // Only for reflection-based instantiation by the framework
- }
-
- TeamAddDialog(Collection<String> teamsAlreadyInGame) {
- this.teamsAlreadyInGame = new ArrayList<String>(teamsAlreadyInGame);
- }
-
- @Override
- public void onAttach(Activity activity) {
- super.onAttach(activity);
- try {
- listener = (Listener) activity;
- } catch(ClassCastException e) {
- throw new ClassCastException("Activity " + activity + " must implement TeamAddDialog.Listener to use TeamAddDialog.");
- }
- }
-
- @Override
- public void onDetach() {
- super.onDetach();
- listener = null;
- }
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- if(savedInstanceState != null) {
- teamsAlreadyInGame = savedInstanceState.getStringArrayList(STATE_TEAMS_ALREADY_IN_GAME);
- }
- availableTeams = new ArrayList<Team>();
- List<Team> teams = FrontendDataUtils.getTeams(getActivity());
- for(Team team : teams) {
- if(!teamsAlreadyInGame.contains(team.name)) {
- availableTeams.add(team);
- }
- }
- Collections.sort(availableTeams, Team.NAME_ORDER);
- }
-
- @Override
- public Dialog onCreateDialog(Bundle savedInstanceState) {
- AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
- builder.setTitle(R.string.dialog_addteam_title);
- builder.setIcon(R.drawable.human);
- String[] teamNames = new String[availableTeams.size()];
- for(int i=0; i<availableTeams.size(); i++) {
- teamNames[i] = availableTeams.get(i).name;
- }
- builder.setItems(teamNames, new OnClickListener() {
- public void onClick(DialogInterface dialog, int which) {
- listener.onTeamAddDialogSubmitted(availableTeams.get(which));
- }
- });
- return builder.create();
- }
-
- @Override
- public void onSaveInstanceState(Bundle outState) {
- super.onSaveInstanceState(outState);
- outState.putStringArrayList(STATE_TEAMS_ALREADY_IN_GAME, teamsAlreadyInGame);
- }
-}
--- a/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/netplay/Teamlist.java Sat Aug 18 00:22:33 2012 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,27 +0,0 @@
-package org.hedgewars.hedgeroid.netplay;
-
-import java.util.Collection;
-
-import org.hedgewars.hedgeroid.Datastructures.TeamInGame;
-import org.hedgewars.hedgeroid.Datastructures.TeamIngameAttributes;
-
-import android.util.Pair;
-
-public class Teamlist extends ObservableTreeMap<String, Pair<TeamInGame, Long>> {
- private long nextId = 1;
-
- public void addTeamWithNewId(TeamInGame team) {
- put(team.team.name, Pair.create(team, nextId++));
- }
-
- public int getUnusedOrRandomColorIndex() {
- Collection<Pair<TeamInGame, Long>> teams = getMap().values();
- int[] illegalColors = new int[teams.size()];
- int i=0;
- for(Pair<TeamInGame, Long> item : teams) {
- illegalColors[i] = item.first.ingameAttribs.colorIndex;
- i++;
- }
- return TeamIngameAttributes.randomColorIndex(illegalColors);
- }
-}
--- a/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/netplay/TeamlistAdapter.java Sat Aug 18 00:22:33 2012 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,60 +0,0 @@
-package org.hedgewars.hedgeroid.netplay;
-
-import java.util.Comparator;
-
-import org.hedgewars.hedgeroid.Datastructures.TeamInGame;
-
-import android.content.Context;
-import android.util.Pair;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.TextView;
-
-public class TeamlistAdapter extends ObservableTreeMapAdapter<String, Pair<TeamInGame, Long>> {
- private Context context;
-
- public TeamlistAdapter(Context context) {
- this.context = context;
- }
-
- @Override
- protected Comparator<Pair<TeamInGame, Long>> getEntryOrder() {
- return AlphabeticalOrderComparator.INSTANCE;
- }
-
- public TeamInGame getItem(int position) {
- return getEntries().get(position).first;
- }
-
- public long getItemId(int position) {
- return getEntries().get(position).second;
- }
-
- public boolean hasStableIds() {
- return true;
- }
-
- public View getView(int position, View convertView, ViewGroup parent) {
- View v = convertView;
- if (v == null) {
- LayoutInflater vi = LayoutInflater.from(context);
- v = vi.inflate(android.R.layout.simple_list_item_2, null);
- }
-
- TeamInGame team = getItem(position);
- TextView tv1 = (TextView) v.findViewById(android.R.id.text1);
- TextView tv2 = (TextView) v.findViewById(android.R.id.text2);
-
- tv1.setText(team.team.name);
- tv2.setText("Hogs: "+team.ingameAttribs.hogCount);
- return v;
- }
-
- private static final class AlphabeticalOrderComparator implements Comparator<Pair<TeamInGame, Long>> {
- public static final AlphabeticalOrderComparator INSTANCE = new AlphabeticalOrderComparator();
- public int compare(Pair<TeamInGame, Long> lhs, Pair<TeamInGame, Long> rhs) {
- return lhs.first.team.name.compareToIgnoreCase(rhs.first.team.name);
- };
- }
-}
\ No newline at end of file
--- a/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/netplay/TeamlistFragment.java Sat Aug 18 00:22:33 2012 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,85 +0,0 @@
-package org.hedgewars.hedgeroid.netplay;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.List;
-
-import org.hedgewars.hedgeroid.R;
-import org.hedgewars.hedgeroid.Datastructures.Team;
-import org.hedgewars.hedgeroid.Datastructures.TeamInGame;
-
-import android.database.DataSetObserver;
-import android.os.Bundle;
-import android.support.v4.app.ListFragment;
-import android.util.Pair;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.View.OnClickListener;
-import android.view.ViewGroup;
-import android.widget.AdapterView.OnItemClickListener;
-import android.widget.AdapterView;
-import android.widget.Button;
-
-public class TeamlistFragment extends ListFragment implements OnItemClickListener {
- private Netplay netplay;
- private TeamlistAdapter adapter;
- private Button addTeamButton;
- private DataSetObserver teamlistObserver;
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- netplay = Netplay.getAppInstance(getActivity().getApplicationContext());
- adapter = new TeamlistAdapter(getActivity());
- adapter.setSource(netplay.roomTeamlist);
- setListAdapter(adapter);
- }
-
- @Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container,
- Bundle savedInstanceState) {
- View v = inflater.inflate(R.layout.fragment_teamlist, container, false);
- addTeamButton = (Button)v.findViewById(R.id.addTeamButton);
- addTeamButton.setOnClickListener(new OnClickListener() {
- public void onClick(View v) {
- new TeamAddDialog(getCurrentTeamNames()).show(getFragmentManager(), "team_add_dialog");
- }
- });
-
- teamlistObserver = new DataSetObserver() {
- @Override
- public void onChanged() {
- addTeamButton.setEnabled(netplay.roomTeamlist.getMap().size() < Team.maxNumberOfTeams);
- }
- };
- netplay.roomTeamlist.registerObserver(teamlistObserver);
- teamlistObserver.onChanged();
-
- return v;
- }
-
- @Override
- public void onDestroy() {
- super.onDestroy();
- adapter.invalidate();
- netplay.roomTeamlist.unregisterObserver(teamlistObserver);
- }
-
- @Override
- public void onActivityCreated(Bundle savedInstanceState) {
- super.onActivityCreated(savedInstanceState);
- getListView().setOnItemClickListener(this);
- }
-
- private Collection<String> getCurrentTeamNames() {
- List<String> names = new ArrayList<String>();
- for(Pair<TeamInGame, Long> teamWithId : netplay.roomTeamlist.getMap().values()) {
- names.add(teamWithId.first.team.name);
- }
- return names;
- }
-
- public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
- netplay.sendRemoveTeam(adapter.getItem(position).team.name);
- }
-}
--- a/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/netplay/TextInputDialog.java Sat Aug 18 00:22:33 2012 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,128 +0,0 @@
-package org.hedgewars.hedgeroid.netplay;
-
-import android.app.Activity;
-import android.app.AlertDialog;
-import android.app.Dialog;
-import android.content.DialogInterface;
-import android.os.Bundle;
-import android.support.v4.app.DialogFragment;
-import android.view.KeyEvent;
-import android.view.inputmethod.EditorInfo;
-import android.widget.EditText;
-import android.widget.TextView;
-import android.widget.TextView.OnEditorActionListener;
-
-/**
- * A generic text input dialog with configurable text. The Activity must implement the callback
- * interface TextInputDialogListener, which will be called by the dialog if it is submitted or cancelled.
- */
-public class TextInputDialog extends DialogFragment {
- private static final String BUNDLE_DIALOG_ID = "dialogId";
- private static final String BUNDLE_TITLE_TEXT = "title";
- private static final String BUNDLE_MESSAGE_TEXT = "message";
- private static final String BUNDLE_HINT_TEXT = "hint";
-
- private int dialogId, titleText, messageText, hintText;
- private TextInputDialogListener listener;
-
- public interface TextInputDialogListener {
- void onTextInputDialogSubmitted(int dialogId, String text);
- void onTextInputDialogCancelled(int dialogId);
- }
-
- /**
- * The dialogId is only used for passing back to the callback on the activity, the
- * other parameters are text resource IDs. Pass 0 for any of them to not use this
- * text.
- */
- public TextInputDialog(int dialogId, int titleText, int messageText, int hintText) {
- this.dialogId = dialogId;
- this.titleText = titleText;
- this.messageText = messageText;
- this.hintText = hintText;
- }
-
- public TextInputDialog() {
- // Only for reflection-based instantiation by the framework
- }
-
- @Override
- public void onAttach(Activity activity) {
- super.onAttach(activity);
- try {
- listener = (TextInputDialogListener) activity;
- } catch(ClassCastException e) {
- throw new ClassCastException("Activity " + activity + " must implement TextInputDialogListener to use TextInputDialog.");
- }
- }
-
- @Override
- public void onDetach() {
- super.onDetach();
- listener = null;
- }
-
- @Override
- public Dialog onCreateDialog(Bundle savedInstanceState) {
- if(savedInstanceState != null) {
- dialogId = savedInstanceState.getInt(BUNDLE_DIALOG_ID, dialogId);
- titleText = savedInstanceState.getInt(BUNDLE_TITLE_TEXT, titleText);
- messageText = savedInstanceState.getInt(BUNDLE_MESSAGE_TEXT, messageText);
- hintText = savedInstanceState.getInt(BUNDLE_HINT_TEXT, hintText);
- }
-
- final EditText editText = new EditText(getActivity());
- AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
-
- if(titleText != 0) {
- builder.setTitle(titleText);
- }
- if(messageText != 0) {
- builder.setTitle(messageText);
- }
- if(hintText != 0) {
- editText.setHint(hintText);
- }
-
- editText.setId(android.R.id.text1);
- editText.setImeOptions(EditorInfo.IME_ACTION_DONE);
- editText.setSingleLine();
-
- builder.setView(editText);
- builder.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int which) {
- dialog.cancel();
- }
- });
-
- editText.setOnEditorActionListener(new OnEditorActionListener() {
- public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
- listener.onTextInputDialogSubmitted(dialogId, v.getText().toString());
- return true;
- }
- });
-
- builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int which) {
- listener.onTextInputDialogSubmitted(dialogId, editText.getText().toString());
- }
- });
-
- return builder.create();
- }
-
- @Override
- public void onSaveInstanceState(Bundle icicle) {
- super.onSaveInstanceState(icicle);
- icicle.putInt(BUNDLE_DIALOG_ID, dialogId);
- icicle.putInt(BUNDLE_TITLE_TEXT, titleText);
- icicle.putInt(BUNDLE_MESSAGE_TEXT, messageText);
- icicle.putInt(BUNDLE_HINT_TEXT, hintText);
- }
-
- @Override
- public void onCancel(DialogInterface dialog) {
- super.onCancel(dialog);
- listener.onTextInputDialogCancelled(dialogId);
- }
-}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/netplay/ThreadedNetConnection.java Sat Aug 18 00:47:51 2012 +0200
@@ -0,0 +1,566 @@
+package org.hedgewars.hedgeroid.netplay;
+
+import static org.hedgewars.hedgeroid.netplay.Netplay.FromNetMsgType.*;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+import org.hedgewars.hedgeroid.R;
+import org.hedgewars.hedgeroid.Datastructures.MapRecipe;
+import org.hedgewars.hedgeroid.Datastructures.Scheme;
+import org.hedgewars.hedgeroid.Datastructures.Team;
+import org.hedgewars.hedgeroid.Datastructures.Weaponset;
+import org.hedgewars.hedgeroid.frontlib.Flib;
+import org.hedgewars.hedgeroid.frontlib.Frontlib;
+import org.hedgewars.hedgeroid.frontlib.Frontlib.BoolCallback;
+import org.hedgewars.hedgeroid.frontlib.Frontlib.BytesCallback;
+import org.hedgewars.hedgeroid.frontlib.Frontlib.GameSetupPtr;
+import org.hedgewars.hedgeroid.frontlib.Frontlib.IntStrCallback;
+import org.hedgewars.hedgeroid.frontlib.Frontlib.MapIntCallback;
+import org.hedgewars.hedgeroid.frontlib.Frontlib.MapRecipePtr;
+import org.hedgewars.hedgeroid.frontlib.Frontlib.NetconnPtr;
+import org.hedgewars.hedgeroid.frontlib.Frontlib.RoomArrayPtr;
+import org.hedgewars.hedgeroid.frontlib.Frontlib.RoomCallback;
+import org.hedgewars.hedgeroid.frontlib.Frontlib.RoomListCallback;
+import org.hedgewars.hedgeroid.frontlib.Frontlib.RoomPtr;
+import org.hedgewars.hedgeroid.frontlib.Frontlib.SchemeCallback;
+import org.hedgewars.hedgeroid.frontlib.Frontlib.SchemePtr;
+import org.hedgewars.hedgeroid.frontlib.Frontlib.StrBoolCallback;
+import org.hedgewars.hedgeroid.frontlib.Frontlib.StrCallback;
+import org.hedgewars.hedgeroid.frontlib.Frontlib.StrIntCallback;
+import org.hedgewars.hedgeroid.frontlib.Frontlib.StrRoomCallback;
+import org.hedgewars.hedgeroid.frontlib.Frontlib.StrStrCallback;
+import org.hedgewars.hedgeroid.frontlib.Frontlib.TeamCallback;
+import org.hedgewars.hedgeroid.frontlib.Frontlib.TeamPtr;
+import org.hedgewars.hedgeroid.frontlib.Frontlib.VoidCallback;
+import org.hedgewars.hedgeroid.frontlib.Frontlib.WeaponsetCallback;
+import org.hedgewars.hedgeroid.frontlib.Frontlib.WeaponsetPtr;
+import org.hedgewars.hedgeroid.netplay.Netplay.FromNetHandler;
+import org.hedgewars.hedgeroid.netplay.Netplay.FromNetMsgType;
+import org.hedgewars.hedgeroid.util.FileUtils;
+import org.hedgewars.hedgeroid.util.TickHandler;
+
+import android.annotation.SuppressLint;
+import android.content.Context;
+import android.content.res.Resources;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Looper;
+import android.os.Message;
+import android.util.Log;
+import android.util.Pair;
+
+import com.sun.jna.Memory;
+import com.sun.jna.NativeLong;
+import com.sun.jna.Pointer;
+
+/**
+ * This class handles the actual communication with the networking library, running on a separate thread.
+ *
+ * In order to process net messages, this class regularly runs a tick() function on the frontlib. This
+ * usually happens several times per second, but it can be slowed down a lot if no fast reaction to
+ * events is required (e.g. to conserve battery if the application is in the background).
+ */
+class ThreadedNetConnection {
+ private static final long TICK_INTERVAL_FAST = 100;
+ private static final long TICK_INTERVAL_SLOW = 5000;
+ private static final Frontlib FLIB = Flib.INSTANCE;
+
+ public final ToNetHandler toNetHandler;
+
+ private final Context appContext;
+ private final FromNetHandler fromNetHandler;
+ private final TickHandler tickHandler;
+
+ /**
+ * conn can only be null while connecting (the first thing in the thread), and directly after disconnecting,
+ * in the same message (the looper is shut down on disconnect, so there will be no messages after that).
+ */
+ private NetconnPtr conn;
+ private String playerName;
+
+ private ThreadedNetConnection(Context appContext, FromNetHandler fromNetHandler) {
+ this.appContext = appContext;
+ this.fromNetHandler = fromNetHandler;
+
+ HandlerThread thread = new HandlerThread("NetThread");
+ thread.start();
+ toNetHandler = new ToNetHandler(thread.getLooper());
+ tickHandler = new TickHandler(thread.getLooper(), TICK_INTERVAL_FAST, tickCb);
+ }
+
+ private void connect(final String name, final String host, final int port) {
+ toNetHandler.post(new Runnable() {
+ public void run() {
+ playerName = name == null ? "Player" : name;
+ File dataPath;
+ try {
+ dataPath = FileUtils.getDataPathFile(appContext);
+ } catch (FileNotFoundException e) {
+ shutdown(true, appContext.getString(R.string.sdcard_not_mounted));
+ return;
+ }
+ conn = FLIB.flib_netconn_create(playerName, dataPath.getAbsolutePath()+"/", host, port);
+ if(conn == null) {
+ shutdown(true, appContext.getString(R.string.error_connection_failed));
+ return;
+ }
+
+ //FLIB.flib_netconn_onAdminAccess(conn, adminAccessCb, null)
+ FLIB.flib_netconn_onCfgScheme(conn, cfgSchemeCb, null);
+ FLIB.flib_netconn_onChat(conn, chatCb, null);
+ FLIB.flib_netconn_onConnected(conn, connectedCb, null);
+ FLIB.flib_netconn_onDisconnected(conn, disconnectCb, null);
+ FLIB.flib_netconn_onEngineMessage(conn, engineMessageCb, null);
+ FLIB.flib_netconn_onEnterRoom(conn, enterRoomCb, null);
+ FLIB.flib_netconn_onHogCountChanged(conn, hogCountChangedCb, null);
+ FLIB.flib_netconn_onLeaveRoom(conn, leaveRoomCb, null);
+ FLIB.flib_netconn_onLobbyJoin(conn, lobbyJoinCb, null);
+ FLIB.flib_netconn_onLobbyLeave(conn, lobbyLeaveCb, null);
+ FLIB.flib_netconn_onMapChanged(conn, mapChangedCb, null);
+ FLIB.flib_netconn_onMessage(conn, messageCb, null);
+ FLIB.flib_netconn_onPasswordRequest(conn, passwordRequestCb, null);
+ FLIB.flib_netconn_onReadyState(conn, readyStateCb, null);
+ FLIB.flib_netconn_onRoomAdd(conn, roomAddCb, null);
+ FLIB.flib_netconn_onRoomChiefStatus(conn, roomChiefStatusCb, null);
+ FLIB.flib_netconn_onRoomDelete(conn, roomDeleteCb, null);
+ FLIB.flib_netconn_onRoomJoin(conn, roomJoinCb, null);
+ FLIB.flib_netconn_onRoomLeave(conn, roomLeaveCb, null);
+ FLIB.flib_netconn_onRoomlist(conn, roomlistCb, null);
+ FLIB.flib_netconn_onRoomUpdate(conn, roomUpdateCb, null);
+ FLIB.flib_netconn_onRunGame(conn, runGameCb, null);
+ FLIB.flib_netconn_onScriptChanged(conn, scriptChangedCb, null);
+ // FLIB.flib_netconn_onServerVar(conn, serverVarCb, null);
+ FLIB.flib_netconn_onTeamAccepted(conn, teamAcceptedCb, null);
+ FLIB.flib_netconn_onTeamAdd(conn, teamAddedCb, null);
+ FLIB.flib_netconn_onTeamColorChanged(conn, teamColorChangedCb, null);
+ FLIB.flib_netconn_onTeamDelete(conn, teamDeletedCb, null);
+ FLIB.flib_netconn_onWeaponsetChanged(conn, weaponsetChangedCb, null);
+
+ tickHandler.start();
+ }
+ });
+ }
+
+ public static ThreadedNetConnection startConnection(Context appContext, FromNetHandler fromNetHandler, String playerName, String host, int port) {
+ ThreadedNetConnection result = new ThreadedNetConnection(appContext, fromNetHandler);
+ result.connect(playerName, host, port);
+ return result;
+ }
+
+ public void setFastTickRate(boolean fastTickRate) {
+ tickHandler.setInterval(fastTickRate ? TICK_INTERVAL_FAST : TICK_INTERVAL_SLOW);
+ }
+
+ private final Runnable tickCb = new Runnable() {
+ public void run() {
+ FLIB.flib_netconn_tick(conn);
+ }
+ };
+
+ private final SchemeCallback cfgSchemeCb = new SchemeCallback() {
+ public void callback(Pointer context, SchemePtr schemePtr) {
+ sendFromNet(MSG_SCHEME_CHANGED, schemePtr.deref());
+ }
+ };
+
+ private final MapIntCallback mapChangedCb = new MapIntCallback() {
+ public void callback(Pointer context, MapRecipePtr mapPtr, int updateType) {
+ sendFromNet(MSG_MAP_CHANGED, updateType, mapPtr.deref());
+ }
+ };
+
+ private final BoolCallback roomChiefStatusCb = new BoolCallback() {
+ public void callback(Pointer context, boolean chief) {
+ sendFromNet(MSG_ROOM_CHIEF_STATUS_CHANGED, chief);
+ }
+ };
+
+ private final StrCallback scriptChangedCb = new StrCallback() {
+ public void callback(Pointer context, String script) {
+ sendFromNet(MSG_SCRIPT_CHANGED, script);
+ }
+ };
+
+ private final WeaponsetCallback weaponsetChangedCb = new WeaponsetCallback() {
+ public void callback(Pointer context, WeaponsetPtr weaponsetPtr) {
+ sendFromNet(MSG_WEAPONSET_CHANGED, weaponsetPtr.deref());
+ }
+ };
+
+ private final StrCallback lobbyJoinCb = new StrCallback() {
+ public void callback(Pointer context, String name) {
+ sendFromNet(MSG_LOBBY_JOIN, name);
+ }
+ };
+
+ private final StrStrCallback lobbyLeaveCb = new StrStrCallback() {
+ public void callback(Pointer context, String name, String msg) {
+ sendFromNet(MSG_LOBBY_LEAVE, Pair.create(name, msg));
+ }
+ };
+
+ private final StrCallback roomJoinCb = new StrCallback() {
+ public void callback(Pointer context, String name) {
+ sendFromNet(MSG_ROOM_JOIN, name);
+ }
+ };
+ private final StrStrCallback roomLeaveCb = new StrStrCallback() {
+ public void callback(Pointer context, String name, String message) {
+ sendFromNet(MSG_ROOM_LEAVE, Pair.create(name, message));
+ }
+ };
+ private final StrStrCallback chatCb = new StrStrCallback() {
+ public void callback(Pointer context, String name, String msg) {
+ sendFromNet(MSG_CHAT, Pair.create(name, msg));
+ }
+ };
+
+ private final IntStrCallback messageCb = new IntStrCallback() {
+ public void callback(Pointer context, int type, String msg) {
+ sendFromNet(MSG_MESSAGE, type, msg);
+ }
+ };
+
+ private final RoomCallback roomAddCb = new RoomCallback() {
+ public void callback(Pointer context, RoomPtr roomPtr) {
+ sendFromNet(MSG_ROOM_ADD, roomPtr.deref());
+ }
+ };
+
+ private final StrRoomCallback roomUpdateCb = new StrRoomCallback() {
+ public void callback(Pointer context, String name, RoomPtr roomPtr) {
+ sendFromNet(MSG_ROOM_UPDATE, Pair.create(name, roomPtr.deref()));
+ }
+ };
+
+ private final StrCallback roomDeleteCb = new StrCallback() {
+ public void callback(Pointer context, final String name) {
+ sendFromNet(MSG_ROOM_DELETE, name);
+ }
+ };
+
+ private final RoomListCallback roomlistCb = new RoomListCallback() {
+ public void callback(Pointer context, RoomArrayPtr arg1, int count) {
+ sendFromNet(MSG_ROOMLIST, arg1.getRooms(count));
+ }
+ };
+
+ private final VoidCallback connectedCb = new VoidCallback() {
+ public void callback(Pointer context) {
+ FLIB.flib_netconn_send_request_roomlist(conn);
+ playerName = FLIB.flib_netconn_get_playername(conn);
+ sendFromNet(MSG_CONNECTED, playerName);
+ }
+ };
+
+ private final StrCallback passwordRequestCb = new StrCallback() {
+ public void callback(Pointer context, String nickname) {
+ sendFromNet(MSG_PASSWORD_REQUEST, playerName);
+ }
+ };
+
+ private final BoolCallback enterRoomCb = new BoolCallback() {
+ public void callback(Pointer context, boolean isChief) {
+ sendFromNet(MSG_ENTER_ROOM_FROM_LOBBY, isChief);
+ }
+ };
+
+ private final IntStrCallback leaveRoomCb = new IntStrCallback() {
+ public void callback(Pointer context, int reason, String message) {
+ sendFromNet(MSG_LEAVE_ROOM, reason, message);
+ }
+ };
+
+ private final StrBoolCallback readyStateCb = new StrBoolCallback() {
+ public void callback(Pointer context, String player, boolean ready) {
+ sendFromNet(MSG_READYSTATE, Pair.create(player, ready));
+ }
+ };
+
+ private final TeamCallback teamAddedCb = new TeamCallback() {
+ public void callback(Pointer context, TeamPtr team) {
+ sendFromNet(MSG_TEAM_ADDED, team.deref().team);
+ }
+ };
+
+ private final StrCallback teamDeletedCb = new StrCallback() {
+ public void callback(Pointer context, String teamName) {
+ sendFromNet(MSG_TEAM_DELETED, teamName);
+ }
+ };
+
+ private final StrCallback teamAcceptedCb = new StrCallback() {
+ public void callback(Pointer context, String teamName) {
+ sendFromNet(MSG_TEAM_ACCEPTED, teamName);
+ }
+ };
+
+ private final StrIntCallback teamColorChangedCb = new StrIntCallback() {
+ public void callback(Pointer context, String teamName, int colorIndex) {
+ sendFromNet(MSG_TEAM_COLOR_CHANGED, colorIndex, teamName);
+ }
+ };
+
+ private final StrIntCallback hogCountChangedCb = new StrIntCallback() {
+ public void callback(Pointer context, String teamName, int hogCount) {
+ sendFromNet(MSG_HOG_COUNT_CHANGED, hogCount, teamName);
+ }
+ };
+
+ private final BytesCallback engineMessageCb = new BytesCallback() {
+ public void callback(Pointer context, Pointer buffer, NativeLong size) {
+ sendFromNet(MSG_ENGINE_MESSAGE, buffer.getByteArray(0, size.intValue()));
+ }
+ };
+
+ private final VoidCallback runGameCb = new VoidCallback() {
+ public void callback(Pointer context) {
+ GameSetupPtr configPtr = FLIB.flib_netconn_create_gamesetup(conn);
+ sendFromNet(MSG_RUN_GAME, configPtr.deref());
+ FLIB.flib_gamesetup_destroy(configPtr);
+ }
+ };
+
+ private void shutdown(boolean error, String message) {
+ if(conn != null) {
+ FLIB.flib_netconn_destroy(conn);
+ conn = null;
+ }
+ tickHandler.stop();
+ toNetHandler.getLooper().quit();
+ sendFromNet(MSG_DISCONNECTED, Pair.create(error, message));
+ }
+
+ private final IntStrCallback disconnectCb = new IntStrCallback() {
+ public void callback(Pointer context, int reason, String message) {
+ Boolean error = reason != Frontlib.NETCONN_DISCONNECT_NORMAL;
+ String messageForUser = createDisconnectUserMessage(appContext.getResources(), reason, message);
+ shutdown(error, messageForUser);
+ }
+ };
+
+ private static String createDisconnectUserMessage(Resources res, int reason, String message) {
+ switch(reason) {
+ case Frontlib.NETCONN_DISCONNECT_AUTH_FAILED:
+ return res.getString(R.string.error_auth_failed);
+ case Frontlib.NETCONN_DISCONNECT_CONNLOST:
+ return res.getString(R.string.error_connection_lost);
+ case Frontlib.NETCONN_DISCONNECT_INTERNAL_ERROR:
+ return res.getString(R.string.error_unexpected, message);
+ case Frontlib.NETCONN_DISCONNECT_SERVER_TOO_OLD:
+ return res.getString(R.string.error_server_too_old);
+ default:
+ return message;
+ }
+ }
+
+ private boolean sendFromNet(FromNetMsgType what, Object obj) {
+ return fromNetHandler.sendMessage(fromNetHandler.obtainMessage(what.ordinal(), obj));
+ }
+
+ private boolean sendFromNet(FromNetMsgType what, int arg1, Object obj) {
+ return fromNetHandler.sendMessage(fromNetHandler.obtainMessage(what.ordinal(), arg1, 0, obj));
+ }
+
+ static enum ToNetMsgType {
+ MSG_SEND_NICK,
+ MSG_SEND_PASSWORD,
+ MSG_SEND_QUIT,
+ MSG_SEND_ROOMLIST_REQUEST,
+ MSG_SEND_PLAYER_INFO_REQUEST,
+ MSG_SEND_CHAT,
+ MSG_SEND_TEAMCHAT,
+ MSG_SEND_FOLLOW_PLAYER,
+ MSG_SEND_JOIN_ROOM,
+ MSG_SEND_CREATE_ROOM,
+ MSG_SEND_LEAVE_ROOM,
+ MSG_SEND_KICK,
+ MSG_SEND_ADD_TEAM,
+ MSG_SEND_REMOVE_TEAM,
+ MSG_DISCONNECT,
+ MSG_SEND_TEAM_COLOR_INDEX,
+ MSG_SEND_TEAM_HOG_COUNT,
+ MSG_SEND_ENGINE_MESSAGE,
+ MSG_SEND_ROUND_FINISHED,
+ MSG_SEND_TOGGLE_READY,
+ MSG_SEND_WEAPONSET,
+ MSG_SEND_MAP,
+ MSG_SEND_MAP_NAME,
+ MSG_SEND_MAP_GENERATOR,
+ MSG_SEND_MAP_TEMPLATE,
+ MSG_SEND_MAZE_SIZE,
+ MSG_SEND_MAP_SEED,
+ MSG_SEND_MAP_THEME,
+ MSG_SEND_MAP_DRAWDATA,
+ MSG_SEND_GAMESTYLE,
+ MSG_SEND_SCHEME;
+
+ static final List<ThreadedNetConnection.ToNetMsgType> values = Collections.unmodifiableList(Arrays.asList(ToNetMsgType.values()));
+ }
+
+ /**
+ * Processes messages to the networking system. Runs on a non-main thread.
+ */
+ @SuppressLint("HandlerLeak")
+ public final class ToNetHandler extends Handler {
+
+ public ToNetHandler(Looper looper) {
+ super(looper);
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ switch(ToNetMsgType.values.get(msg.what)) {
+ case MSG_SEND_NICK: {
+ FLIB.flib_netconn_send_nick(conn, (String)msg.obj);
+ break;
+ }
+ case MSG_SEND_PASSWORD: {
+ FLIB.flib_netconn_send_password(conn, (String)msg.obj);
+ break;
+ }
+ case MSG_SEND_QUIT: {
+ FLIB.flib_netconn_send_quit(conn, (String)msg.obj);
+ break;
+ }
+ case MSG_SEND_ROOMLIST_REQUEST: {
+ FLIB.flib_netconn_send_request_roomlist(conn);
+ break;
+ }
+ case MSG_SEND_PLAYER_INFO_REQUEST: {
+ FLIB.flib_netconn_send_playerInfo(conn, (String)msg.obj);
+ break;
+ }
+ case MSG_SEND_CHAT: {
+ if(FLIB.flib_netconn_send_chat(conn, (String)msg.obj) == 0) {
+ sendFromNet(MSG_CHAT, Pair.create(playerName, (String)msg.obj));
+ }
+ break;
+ }
+ case MSG_SEND_TEAMCHAT: {
+ FLIB.flib_netconn_send_teamchat(conn, (String)msg.obj);
+ break;
+ }
+ case MSG_SEND_FOLLOW_PLAYER: {
+ FLIB.flib_netconn_send_playerFollow(conn, (String)msg.obj);
+ break;
+ }
+ case MSG_SEND_JOIN_ROOM: {
+ FLIB.flib_netconn_send_joinRoom(conn, (String)msg.obj);
+ break;
+ }
+ case MSG_SEND_CREATE_ROOM: {
+ FLIB.flib_netconn_send_createRoom(conn, (String)msg.obj);
+ break;
+ }
+ case MSG_SEND_LEAVE_ROOM: {
+ if(FLIB.flib_netconn_send_leaveRoom(conn, (String)msg.obj) == 0) {
+ sendFromNet(MSG_LEAVE_ROOM, -1, "");
+ }
+ break;
+ }
+ case MSG_SEND_KICK: {
+ FLIB.flib_netconn_send_kick(conn, (String)msg.obj);
+ break;
+ }
+ case MSG_SEND_ADD_TEAM: {
+ FLIB.flib_netconn_send_addTeam(conn, TeamPtr.createJavaOwned((Team)msg.obj));
+ break;
+ }
+ case MSG_SEND_REMOVE_TEAM: {
+ if(FLIB.flib_netconn_send_removeTeam(conn, (String)msg.obj)==0) {
+ sendFromNet(MSG_TEAM_DELETED, msg.obj);
+ }
+ break;
+ }
+ case MSG_DISCONNECT: {
+ FLIB.flib_netconn_send_quit(conn, (String)msg.obj);
+ shutdown(false, "User quit");
+ break;
+ }
+ case MSG_SEND_TEAM_COLOR_INDEX: {
+ if(FLIB.flib_netconn_send_teamColor(conn, (String)msg.obj, msg.arg1)==0) {
+ sendFromNet(MSG_TEAM_COLOR_CHANGED, msg.arg1, msg.obj);
+ }
+ break;
+ }
+ case MSG_SEND_TEAM_HOG_COUNT: {
+ if(FLIB.flib_netconn_send_teamHogCount(conn, (String)msg.obj, msg.arg1)==0) {
+ sendFromNet(MSG_HOG_COUNT_CHANGED, msg.arg1, msg.obj);
+ }
+ break;
+ }
+ case MSG_SEND_ENGINE_MESSAGE: {
+ byte[] message = (byte[])msg.obj;
+ Memory mem = new Memory(message.length);
+ mem.write(0, message, 0, message.length);
+ FLIB.flib_netconn_send_engineMessage(conn, mem, new NativeLong(message.length));
+ break;
+ }
+ case MSG_SEND_ROUND_FINISHED: {
+ FLIB.flib_netconn_send_roundfinished(conn, (Boolean)msg.obj);
+ break;
+ }
+ case MSG_SEND_TOGGLE_READY: {
+ FLIB.flib_netconn_send_toggleReady(conn);
+ break;
+ }
+ case MSG_SEND_WEAPONSET: {
+ FLIB.flib_netconn_send_weaponset(conn, WeaponsetPtr.createJavaOwned((Weaponset)msg.obj));
+ break;
+ }
+ case MSG_SEND_MAP: {
+ FLIB.flib_netconn_send_map(conn, MapRecipePtr.createJavaOwned((MapRecipe)msg.obj));
+ break;
+ }
+ case MSG_SEND_MAP_NAME: {
+ FLIB.flib_netconn_send_mapName(conn, (String)msg.obj);
+ break;
+ }
+ case MSG_SEND_MAP_GENERATOR: {
+ FLIB.flib_netconn_send_mapGen(conn, msg.arg1);
+ break;
+ }
+ case MSG_SEND_MAP_TEMPLATE: {
+ FLIB.flib_netconn_send_mapTemplate(conn, msg.arg1);
+ break;
+ }
+ case MSG_SEND_MAZE_SIZE: {
+ FLIB.flib_netconn_send_mapMazeSize(conn, msg.arg1);
+ break;
+ }
+ case MSG_SEND_MAP_SEED: {
+ FLIB.flib_netconn_send_mapSeed(conn, (String) msg.obj);
+ break;
+ }
+ case MSG_SEND_MAP_THEME: {
+ FLIB.flib_netconn_send_mapTheme(conn, (String) msg.obj);
+ break;
+ }
+ case MSG_SEND_MAP_DRAWDATA: {
+ byte[] message = (byte[])msg.obj;
+ Memory mem = new Memory(message.length);
+ mem.write(0, message, 0, message.length);
+ FLIB.flib_netconn_send_mapDrawdata(conn, mem, new NativeLong(message.length));
+ break;
+ }
+ case MSG_SEND_GAMESTYLE: {
+ FLIB.flib_netconn_send_script(conn, (String) msg.obj);
+ break;
+ }
+ case MSG_SEND_SCHEME: {
+ FLIB.flib_netconn_send_scheme(conn, SchemePtr.createJavaOwned((Scheme) msg.obj));
+ break;
+ }
+ default: {
+ Log.e("ToNetHandler", "Unknown message type: "+msg.what);
+ break;
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
--- a/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/netplay/TickHandler.java Sat Aug 18 00:22:33 2012 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,54 +0,0 @@
-package org.hedgewars.hedgeroid.netplay;
-
-import android.os.Handler;
-import android.os.Looper;
-import android.os.Message;
-
-/**
- * This class handles regularly calling a specified runnable
- * on the looper provided in the constructor. The first call
- * occurs without delay (though still via the looper), all
- * following calls are delayed by (approximately) the interval.
- * The interval can be changed at any time, which will cause
- * an immediate execution of the runnable again.
- */
-public class TickHandler extends Handler {
- private final Runnable callback;
- private int messageId;
- private long interval;
- private boolean running;
-
- public TickHandler(Looper looper, long interval, Runnable callback) {
- super(looper);
- this.callback = callback;
- this.interval = interval;
- }
-
- public synchronized void stop() {
- messageId++;
- running = false;
- }
-
- public synchronized void start() {
- messageId++;
- sendMessage(obtainMessage(messageId));
- running = true;
- }
-
- public synchronized void setInterval(long interval) {
- this.interval = interval;
- if(running) {
- start();
- }
- }
-
- @Override
- public synchronized void handleMessage(Message msg) {
- if(msg.what == messageId) {
- callback.run();
- }
- if(msg.what == messageId) {
- sendMessageDelayed(obtainMessage(messageId), interval);
- }
- }
-}
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/util/FileUtils.java Sat Aug 18 00:47:51 2012 +0200
@@ -0,0 +1,265 @@
+/*
+ * Hedgewars for Android. An Android port of Hedgewars, a free turn based strategy game
+ * Copyright (c) 2011-2012 Richard Deurwaarder <xeli@xelification.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+
+package org.hedgewars.hedgeroid.util;
+
+import java.io.ByteArrayOutputStream;
+import java.io.Closeable;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.List;
+
+import android.annotation.TargetApi;
+import android.content.Context;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.os.Build;
+import android.os.Environment;
+import android.util.Log;
+
+public class FileUtils {
+ private static final String ROOT_DIR = "Data";
+ private static final String TAG = FileUtils.class.getSimpleName();
+
+ /**
+ * @return true if the data path is currently available. However, it can vanish at any time so
+ * normally you should just try to use it and rely on the exceptions.
+ */
+ public static boolean isDataPathAvailable() {
+ return Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState());
+ }
+
+ /**
+ * get the path to which we should download all the data files
+ * @param c context
+ * @return The directory
+ * @throws FileNotFoundException if external storage is not available at the moment
+ */
+ public static File getCachePath(Context c) throws FileNotFoundException {
+ File cachePath = null;
+ if(Build.VERSION.SDK_INT < 8){//8 == Build.VERSION_CODES.FROYO
+ cachePath = PreFroyoSDCardDir.getDownloadPath(c);
+ } else {
+ cachePath = FroyoSDCardDir.getDownloadPath(c);
+ }
+ if(cachePath==null) {
+ throw new FileNotFoundException("External storage is currently unavailable");
+ } else {
+ return cachePath;
+ }
+ }
+
+ public static File getDataPathFile(Context c) throws FileNotFoundException {
+ return new File(getCachePath(c), ROOT_DIR);
+ }
+
+ // TODO Several callers are unaware that this may fail, so it throws an RTE now.
+ // Should be handled better though.
+ @Deprecated
+ public static String getDataPath(Context c) {
+ try {
+ return getDataPathFile(c).getAbsolutePath()+"/";
+ } catch(FileNotFoundException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ @TargetApi(8)
+ private static class FroyoSDCardDir{
+ public static File getDownloadPath(Context c){
+ return c.getExternalCacheDir();
+ }
+ }
+
+ private static class PreFroyoSDCardDir{
+ public static File getDownloadPath(Context c){
+ if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){
+ File extStorageDir = Environment.getExternalStorageDirectory();
+ if(extStorageDir != null) {
+ return new File(extStorageDir, "Hedgewars");
+ }
+ }
+ return null;
+ }
+ }
+
+ /**
+ * Return a File array with all the files from dirName
+ * @param c
+ * @param dirName
+ * @return
+ * @throws FileNotFoundException If the sdcard is not available or the subdirectory "dirName" does not exist
+ */
+ public static File[] getFilesFromRelativeDir(Context c, String dirName) throws FileNotFoundException {
+ File f = new File(getDataPathFile(c), dirName);
+
+ if(f.isDirectory()) {
+ return f.listFiles();
+ } else {
+ throw new FileNotFoundException("Directory "+dirName+" does not exist.");
+ }
+ }
+
+ /**
+ * Checks if this directory has a file with suffix suffix
+ * @param f - directory
+ * @return
+ */
+ public static boolean hasFileWithSuffix(File f, String suffix){
+ if(f.isDirectory()){
+ for(String s : f.list()){
+ if(s.endsWith(suffix)) return true;
+ }
+ return false;
+ }else{
+ return false;
+ }
+ }
+
+ /**
+ * Gives back all dirs which contain a file with suffix fileSuffix
+ * @param c
+ * @param path
+ * @param fileSuffix
+ * @return
+ * @throws FileNotFoundException If the sdcard is not available or the subdirectory "path" does not exist
+ */
+ public static List<String> getDirsWithFileSuffix(Context c, String path, String fileSuffix) throws FileNotFoundException{
+ File[] files = getFilesFromRelativeDir(c,path);
+ ArrayList<String> ret = new ArrayList<String>();
+
+ for(File f : files){
+ if(hasFileWithSuffix(f, fileSuffix)) ret.add(f.getName());
+ }
+ return ret;
+ }
+
+ /**
+ * Get all files from directory dir which have the given suffix
+ * @throws FileNotFoundException If the sdcard is not available or the subdirectory "dir" does not exist
+ */
+ public static ArrayList<String> getFileNamesFromDirWithSuffix(Context c, String dir, String suffix, boolean removeSuffix) throws FileNotFoundException{
+ File[] files = FileUtils.getFilesFromRelativeDir(c, dir);
+ ArrayList<String> ret = new ArrayList<String>();
+ for(File file : files){
+ String s = file.getName();
+ if(s.endsWith(suffix)){
+ if(removeSuffix) ret.add(s.substring(0, s.length()-suffix.length()));
+ else ret.add(s);
+ }
+ }
+ return ret;
+ }
+
+ /**
+ * Close a resource (possibly null), ignoring any IOException.
+ */
+ public static void closeQuietly(Closeable c) {
+ if(c!=null) {
+ try {
+ c.close();
+ } catch(IOException e) {
+ Log.w(TAG, e);
+ }
+ }
+ }
+
+ /**
+ * Write all data from the input stream to the file, creating or overwriting it.
+ * The input stream will be closed.
+ *
+ * @throws IOException
+ */
+ public static void writeStreamToFile(InputStream is, File file) throws IOException {
+ OutputStream os = null;
+ byte[] buffer = new byte[8192];
+ try {
+ os = new FileOutputStream(file);
+ int size;
+ while((size=is.read(buffer)) != -1) {
+ os.write(buffer, 0, size);
+ }
+ os.close(); // Important to close this non-quietly, in case of exceptions when flushing
+ } finally {
+ FileUtils.closeQuietly(is);
+ FileUtils.closeQuietly(os);
+ }
+ }
+
+ /**
+ * Moves resources pointed to by sourceResId (from @res/raw/) to the app's private data directory
+ * @param c
+ * @param sourceResId
+ * @param directory
+ */
+ public static void resRawToFilesDir(Context c, int sourceResId, int targetFilenames, String directory) throws IOException {
+ File targetDir = new File(c.getFilesDir(), directory);
+ targetDir.mkdirs();
+
+ //Get an array with the resource files ID
+ Resources resources = c.getResources();
+ TypedArray ta = resources.obtainTypedArray(sourceResId);
+ TypedArray filenames = resources.obtainTypedArray(targetFilenames);
+ for(int i = 0; i < ta.length(); i++){
+ int resId = ta.getResourceId(i, 0);
+ String fileName = filenames.getString(i);
+ File f = new File(targetDir, fileName);
+ writeStreamToFile(resources.openRawResource(resId), f);
+ }
+ }
+
+ public static String readToString(InputStream is) throws IOException {
+ try {
+ ByteArrayOutputStream os = new ByteArrayOutputStream();
+ byte[] buffer = new byte[8192];
+ int size;
+ while((size=is.read(buffer)) != -1) {
+ os.write(buffer, 0, size);
+ }
+ return new String(os.toByteArray());
+ } finally {
+ closeQuietly(is);
+ }
+ }
+
+ private static final char[] badFilenameChars = new char[] { '/', '\\', ':', '*', '?', '\"', '<', '>', '|', '.', '\0' };
+
+ /**
+ * Modify the given String so that it can be used as part of a filename
+ * without causing problems from illegal/special characters.
+ *
+ * The result should be similar to the input, but isn't necessarily
+ * reversible.
+ */
+ public static String replaceBadChars(String name) {
+ if (name == null || name.trim().length()==0) {
+ return "_";
+ }
+ name = name.trim();
+ for (char badChar : badFilenameChars) {
+ name = name.replace(badChar, '_');
+ }
+ return name;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/util/ObservableTreeMap.java Sat Aug 18 00:47:51 2012 +0200
@@ -0,0 +1,43 @@
+package org.hedgewars.hedgeroid.util;
+
+import java.util.Collections;
+import java.util.Map;
+import java.util.TreeMap;
+
+import android.database.DataSetObservable;
+
+public class ObservableTreeMap<K,V> extends DataSetObservable {
+ private final Map<K, V> map = new TreeMap<K, V>();
+
+ public void replaceContent(Map<? extends K, ? extends V> newMap) {
+ map.clear();
+ map.putAll(newMap);
+ notifyChanged();
+ }
+
+ public void put(K key, V value) {
+ map.put(key, value);
+ notifyChanged();
+ }
+
+ public V get(K key) {
+ return map.get(key);
+ }
+
+ public void remove(K key) {
+ if(map.remove(key) != null) {
+ notifyChanged();
+ }
+ }
+
+ public void clear() {
+ if(!map.isEmpty()) {
+ map.clear();
+ notifyChanged();
+ }
+ }
+
+ public Map<K, V> getMap() {
+ return Collections.unmodifiableMap(map);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/util/ObservableTreeMapAdapter.java Sat Aug 18 00:47:51 2012 +0200
@@ -0,0 +1,75 @@
+package org.hedgewars.hedgeroid.util;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+
+import android.database.DataSetObserver;
+import android.widget.BaseAdapter;
+
+public abstract class ObservableTreeMapAdapter<K,V> extends BaseAdapter {
+ private boolean sourceChanged = true;
+ private List<V> entries = new ArrayList<V>();
+ private ObservableTreeMap<K, V> source;
+
+ private DataSetObserver observer = new DataSetObserver() {
+ @Override
+ public void onChanged() {
+ sourceChanged = true;
+ notifyDataSetChanged();
+ }
+
+ @Override
+ public void onInvalidated() {
+ invalidate();
+ }
+ };
+
+ abstract protected Comparator<V> getEntryOrder();
+
+ protected List<V> getEntries() {
+ if(sourceChanged) {
+ entries.clear();
+ entries.addAll(source.getMap().values());
+ Collections.sort(entries, getEntryOrder());
+ sourceChanged = false;
+ }
+ return entries;
+ }
+
+ public int getCount() {
+ return getEntries().size();
+ }
+
+ public V getItem(int position) {
+ return getEntries().get(position);
+ }
+
+ public long getItemId(int position) {
+ return position;
+ }
+
+ @Override
+ public boolean hasStableIds() {
+ return false;
+ }
+
+ public void setSource(ObservableTreeMap<K,V> source) {
+ if(this.source != null) {
+ this.source.unregisterObserver(observer);
+ }
+ this.source = source;
+ this.source.registerObserver(observer);
+ sourceChanged = true;
+ notifyDataSetChanged();
+ }
+
+ public void invalidate() {
+ if(source != null) {
+ source.unregisterObserver(observer);
+ }
+ source = null;
+ notifyDataSetInvalidated();
+ }
+}
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/util/TextInputDialog.java Sat Aug 18 00:47:51 2012 +0200
@@ -0,0 +1,128 @@
+package org.hedgewars.hedgeroid.util;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.content.DialogInterface;
+import android.os.Bundle;
+import android.support.v4.app.DialogFragment;
+import android.view.KeyEvent;
+import android.view.inputmethod.EditorInfo;
+import android.widget.EditText;
+import android.widget.TextView;
+import android.widget.TextView.OnEditorActionListener;
+
+/**
+ * A generic text input dialog with configurable text. The Activity must implement the callback
+ * interface TextInputDialogListener, which will be called by the dialog if it is submitted or cancelled.
+ */
+public class TextInputDialog extends DialogFragment {
+ private static final String BUNDLE_DIALOG_ID = "dialogId";
+ private static final String BUNDLE_TITLE_TEXT = "title";
+ private static final String BUNDLE_MESSAGE_TEXT = "message";
+ private static final String BUNDLE_HINT_TEXT = "hint";
+
+ private int dialogId, titleText, messageText, hintText;
+ private TextInputDialogListener listener;
+
+ public interface TextInputDialogListener {
+ void onTextInputDialogSubmitted(int dialogId, String text);
+ void onTextInputDialogCancelled(int dialogId);
+ }
+
+ /**
+ * The dialogId is only used for passing back to the callback on the activity, the
+ * other parameters are text resource IDs. Pass 0 for any of them to not use this
+ * text.
+ */
+ public TextInputDialog(int dialogId, int titleText, int messageText, int hintText) {
+ this.dialogId = dialogId;
+ this.titleText = titleText;
+ this.messageText = messageText;
+ this.hintText = hintText;
+ }
+
+ public TextInputDialog() {
+ // Only for reflection-based instantiation by the framework
+ }
+
+ @Override
+ public void onAttach(Activity activity) {
+ super.onAttach(activity);
+ try {
+ listener = (TextInputDialogListener) activity;
+ } catch(ClassCastException e) {
+ throw new ClassCastException("Activity " + activity + " must implement TextInputDialogListener to use TextInputDialog.");
+ }
+ }
+
+ @Override
+ public void onDetach() {
+ super.onDetach();
+ listener = null;
+ }
+
+ @Override
+ public Dialog onCreateDialog(Bundle savedInstanceState) {
+ if(savedInstanceState != null) {
+ dialogId = savedInstanceState.getInt(BUNDLE_DIALOG_ID, dialogId);
+ titleText = savedInstanceState.getInt(BUNDLE_TITLE_TEXT, titleText);
+ messageText = savedInstanceState.getInt(BUNDLE_MESSAGE_TEXT, messageText);
+ hintText = savedInstanceState.getInt(BUNDLE_HINT_TEXT, hintText);
+ }
+
+ final EditText editText = new EditText(getActivity());
+ AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
+
+ if(titleText != 0) {
+ builder.setTitle(titleText);
+ }
+ if(messageText != 0) {
+ builder.setTitle(messageText);
+ }
+ if(hintText != 0) {
+ editText.setHint(hintText);
+ }
+
+ editText.setId(android.R.id.text1);
+ editText.setImeOptions(EditorInfo.IME_ACTION_DONE);
+ editText.setSingleLine();
+
+ builder.setView(editText);
+ builder.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int which) {
+ dialog.cancel();
+ }
+ });
+
+ editText.setOnEditorActionListener(new OnEditorActionListener() {
+ public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
+ listener.onTextInputDialogSubmitted(dialogId, v.getText().toString());
+ return true;
+ }
+ });
+
+ builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int which) {
+ listener.onTextInputDialogSubmitted(dialogId, editText.getText().toString());
+ }
+ });
+
+ return builder.create();
+ }
+
+ @Override
+ public void onSaveInstanceState(Bundle icicle) {
+ super.onSaveInstanceState(icicle);
+ icicle.putInt(BUNDLE_DIALOG_ID, dialogId);
+ icicle.putInt(BUNDLE_TITLE_TEXT, titleText);
+ icicle.putInt(BUNDLE_MESSAGE_TEXT, messageText);
+ icicle.putInt(BUNDLE_HINT_TEXT, hintText);
+ }
+
+ @Override
+ public void onCancel(DialogInterface dialog) {
+ super.onCancel(dialog);
+ listener.onTextInputDialogCancelled(dialogId);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/util/TickHandler.java Sat Aug 18 00:47:51 2012 +0200
@@ -0,0 +1,54 @@
+package org.hedgewars.hedgeroid.util;
+
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+
+/**
+ * This class handles regularly calling a specified runnable
+ * on the looper provided in the constructor. The first call
+ * occurs without delay (though still via the looper), all
+ * following calls are delayed by (approximately) the interval.
+ * The interval can be changed at any time, which will cause
+ * an immediate execution of the runnable again.
+ */
+public class TickHandler extends Handler {
+ private final Runnable callback;
+ private int messageId;
+ private long interval;
+ private boolean running;
+
+ public TickHandler(Looper looper, long interval, Runnable callback) {
+ super(looper);
+ this.callback = callback;
+ this.interval = interval;
+ }
+
+ public synchronized void stop() {
+ messageId++;
+ running = false;
+ }
+
+ public synchronized void start() {
+ messageId++;
+ sendMessage(obtainMessage(messageId));
+ running = true;
+ }
+
+ public synchronized void setInterval(long interval) {
+ this.interval = interval;
+ if(running) {
+ start();
+ }
+ }
+
+ @Override
+ public synchronized void handleMessage(Message msg) {
+ if(msg.what == messageId) {
+ callback.run();
+ }
+ if(msg.what == messageId) {
+ sendMessageDelayed(obtainMessage(messageId), interval);
+ }
+ }
+}
\ No newline at end of file