Cannot register PlayBASIC and cannot run final EXE

Started by cybermind, February 10, 2014, 07:43:05 AM

Previous topic - Next topic

cybermind

Hello :-) I have trouble registering PlayBASIC. When I check the about option it says newest version (1.64O) and Not registred. I tried uninstalling PlayBASIC, re-installing with upgrade, press compile (it did not ask me to register). Uninstalling and re-installing version 1.64L, press compile (still did not ask me to register). And the About option tells me that it is not registered.

I also have trouble with my compiled exe files, they seem to be running in task manager but it does not show up on screen. When I compile it says "Compiler TIMED OUT waiting for linker". I can run my program pressing F5 without any troubles.

I am a bit stuck here.


kevin

#1

QuoteI can run my program pressing F5 without any troubles.

  Then your already registered, you don't have enter the serial every time you upgrade.  

  See-> FAQ

   See-> How to activate PlayBasic.

   

QuoteWhen I compile it says "Compiler TIMED OUT waiting for linker"

   It happens, but it's basically meaningless...  Did you check if the file is in the folder ?



cybermind

#2
I am still having trouble with compiled EXE :-( I tried shaving away some code for an easy readable forum version but then the compiled EXE worked fine so there is of course something wrong with my code but funny thing is that pressing F5 runs the program without any troubles at all :-( I am lost now, can there be too much code for an compiled EXE to work correctly? Or perhaps to many documents (tabs with code)??

EDIT: Removing some of the pages made the compiled EXE run. The removed code should have no effect on the beginning of program, only when performing certain things during the game. I will try and merge some pages together and see if it still runs.

EDIT 2: The amount of code seems to be the problem. I tried removing different parts of the code and then the compiled EXE runs fine, no matter which part of the code I remove. Just removing a lot of code seems to remedy situation.

kevin

  Depending upon the version, there's definitely limits to the size of the compiled byte code module and internal data stacks (Variables / Arrays etc).   Merging source codes into single files won't help,  as the IDE does this anyway.  So the compiler is looking at one big blob of input source, regardless of how many includes in the original project. 

  It's always possible there's some functionality differences between the compiler and runtime virtual machines, which could make the byte code behavior different in places, leading to a direct crash or a breadcrumb styled crash, where some unexpected situation occurs prior, but the boom doesn't happen till later.   It's an easy conclusion to jump too,  but it's actually been quite rare. 

    * How big is the source code ?

    * How many functions ? 

    * How Many Types,  How many fields in the types
   
    * How much media..

    * etc etc

    Without seeing the project there's really nothing I can help you with.. I suggest zipping it up and emailing it me provided it's small.


cybermind

How can I see how big the source code is? It spans several files. I counted 18 functions. I counted 3 types with a 18 fields combined. (One with 11 fields, one with 4 fields and one with 3 fields. I assume fields means variables declared in each type, is that correct?). There is no media included in the project, the game loads them on demand. There is a ton of variables! Where can I send you the code? I have shaved the zip file down to 1.3 megabyte with needed media.

kevin

 Use the Email Form and wait for a reply..  Better hurry :)

or if its only 1.5 meg attach it..

cybermind

#6
Here is the project. I removed the exe, music and most of the maps. I must admit that my code is messy :-P Oh, going all the way to the right will probarbly crash the game as it is missing the next map :-P

kevin


  Thanks for the posting the project, had a look and it seems the loader could get out of alignment in V1.64O (and I'd say all older version).     Tweaked up and it seems to work.  So try the  PlayBASIC V1.64O2 - Runtime Only Upgrades

  Been have a bit of pick through the code and it looks pretty much like most ported code fragments really,   sort of ambiguous, so you could definitively tweak it up somewhat.   




cybermind

Thank you! Now I can continue making a prototype version for playtesting :-) And yes, it was ported many months back from DarkBASIC Professionel to PlayBASIC. How could you see that I ported it?? I have not ported it from another language though.

kevin

#9
    It's generally fairly easy to spot code that's been passed around a bit since it tends not adopt the best practices in PlayBASIC.  Some commons ones are operator usages,  Math -> String -> Array functions / passing etc through to emulations of built in behaviors.
 
   The following is an example of a fragment that could be better expressed with PlayBASIC string functions, namely the Digit$() and Mid() functions.

PlayBASIC Code: [Select]
      digit_sell_amount_string$ = str$(final_sell_amount)
if len(digit_sell_amount_string$) = 1 then digit_sell_amount_string$ = "000" + digit_sell_amount_string$
if len(digit_sell_amount_string$) = 2 then digit_sell_amount_string$ = "00" + digit_sell_amount_string$
if len(digit_sell_amount_string$) = 3 then digit_sell_amount_string$ = "0" + digit_sell_amount_string$
digit_sell_amount(2) = val(mid$(digit_sell_amount_string$,1,1))
digit_sell_amount(3) = val(mid$(digit_sell_amount_string$,2,1))
digit_sell_amount(4) = val(mid$(digit_sell_amount_string$,3,1))
digit_sell_amount(5) = val(mid$(digit_sell_amount_string$,4,1))




    The above really should be more like this in PlayBASIC,

PlayBASIC Code: [Select]
      digit_sell_amount_string$ = digits$(final_sell_amount,4)
digit_sell_amount(2) = mid(digit_sell_amount_string$,1)
digit_sell_amount(3) = mid(digit_sell_amount_string$,2)
digit_sell_amount(4) = mid(digit_sell_amount_string$,3)
digit_sell_amount(5) = mid(digit_sell_amount_string$,4)



    There's a functional difference in that the MID() function returns the ASCII character from a string at a position, so you'd need to subtract asc("0") pulling the value into a 0-9 range.

   
PlayBASIC Code: [Select]
   Stuff$=Digits$(1234,4)

Print Stuff$
print mid(Stuff$,1)-asc("0")
print mid(Stuff$,2)-asc("0")
print mid(Stuff$,3)-asc("0")
print mid(Stuff$,4)-asc("0")

Sync
waitkey




      The compilers pre-evaluation will resolve the literal asc() statements out at compile time, making it nothing more than and integer subtraction.  

       Benchmark:

PlayBASIC Code: [Select]
   Stuff$=Digits$(1234,4)

Print Stuff$


max=10000


Do
cls

frames++

t=timer()
For lp =0 to max
d1=val(mid$(Stuff$,1,1))
d2=val(mid$(Stuff$,2,1))
d3=val(mid$(Stuff$,3,1))
d4=val(mid$(Stuff$,4,1))
next
tt1#+=timer()-t
print tt1#/frames


t=timer()
For lp =0 to max
d1=mid(Stuff$,1)-asc("0")
d2=mid(Stuff$,2)-asc("0")
d3=mid(Stuff$,3)-asc("0")
d4=mid(Stuff$,4)-asc("0")
next
tt2#+=timer()-t
print tt2#/frames


Sync
loop





  Initiate Menus

    Split to array can be used to take lists of string fragments and cut->write them into a passed array.


PlayBASIC Code: [Select]
dim in_game_menu$(10)
`in_game_menu_top

in_game_menu$(1) = "Inventory"
in_game_menu$(2) = "Equipped items"
in_game_menu$(3) = "Change ammo"
in_game_menu$(4) = "Stats"
in_game_menu$(5) = "Skills"
in_game_menu$(6) = "Quests"
in_game_menu$(7) = "Options"

print make$("--",100)
For lp =1 to 10
print in_game_menu$(lp)
next


dim in_game_menu$(10)
s$ = "Inventory,Equipped items,Change ammo,Stats,Skills,Quests,Options"
Count=SplitToArray( s$,",",in_game_menu$(),1)

print make$("--",100)
For lp =1 to 10
print in_game_menu$(lp)
next

sync
waitkey






    Disk/File Access  

        The following code is fairly typical conversion Result = Val(ReadString$() ) when reading from files, but it's not actually needed in PB since there's a ReadValue() functions, ie  Result = ReadValue()


        So the point of using the high level operators is they do multiple operations at once.  Generally Less functions calls ='s better performance.   The same goes for solving redundancy in a program.  

         In the Initiate Arrays include there's a lot of string thrashing and disc nibbling.  A better practice is to pulling the entire file into memory in one hit, then split out the fields form.  

         A Crash Course In BASIC program Optimization



    Controlling the Screen For Debugging  

           I see this in a too many PB examples, making it impossible debug.   The debugger works more like a monitor, letting the user view the current (global) state of the program..  Variables->Array/Lists/Scope Contents -> Media -> Memory consumption etc.

          From the IDE, we run as F7, this will run with partial debug hooks.  #break ->#Print etc to halt execution and debug to console..  


          This compile time logic, check what debug mode (it any) then parses the code according to the that. So in normal F5 mode, the DeskTop Width/Height are uses, then in debug mode a custom size is used.  

PlayBASIC Code: [Select]
//  Get the Desk top width/height
#if pbdebugmode=0
dtw=GetDesktopWidth()
dth=GetDesktopHeight()
#else
;set the size to some smaller size , so the debugger window and game can appear on screen together
dtw=800 ;
dth=600
#endif






    Redundant Calculations  

        Most programs (BASIC or otherwise) generally include calculations that are effectively redundant, by that I mean, they compute some expression where the result never changes.

        In the following  the code falls through 5 comparisons where the inner part of the expression is redundant string operation   val(inventory_list$(current_selected_inventory_item,2)).  
       
PlayBASIC Code: [Select]
         `handle stat modifiers
if item_stats(val(inventory_list$(current_selected_inventory_item,2)),18) > 0 then body_stats(current_character,1,2) = body_stats(current_character,1,2) + item_stats(val(inventory_list$(current_selected_inventory_item,2)),18)
if item_stats(val(inventory_list$(current_selected_inventory_item,2)),19) > 0 then body_stats(current_character,2,2) = body_stats(current_character,2,2) + item_stats(val(inventory_list$(current_selected_inventory_item,2)),19)
if item_stats(val(inventory_list$(current_selected_inventory_item,2)),20) > 0 then body_stats(current_character,3,2) = body_stats(current_character,3,2) + item_stats(val(inventory_list$(current_selected_inventory_item,2)),20)
if item_stats(val(inventory_list$(current_selected_inventory_item,2)),21) > 0 then body_stats(current_character,4,2) = body_stats(current_character,4,2) + item_stats(val(inventory_list$(current_selected_inventory_item,2)),21)
if item_stats(val(inventory_list$(current_selected_inventory_item,2)),22) > 0 then body_stats(current_character,5,2) = body_stats(current_character,5,2) + item_stats(val(inventory_list$(current_selected_inventory_item,2)),22)







PlayBASIC Code: [Select]
       index =val(inventory_list$(current_selected_inventory_item,2))

`handle stat modifiers
if item_stats(Index,18) > 0 then body_stats(current_character,1,2) = body_stats(current_character,1,2) + item_stats(Index,18)
if item_stats(Index,19) > 0 then body_stats(current_character,2,2) = body_stats(current_character,2,2) + item_stats(Index,19)
if item_stats(Index,20) > 0 then body_stats(current_character,3,2) = body_stats(current_character,3,2) + item_stats(Index,20)
if item_stats(Index,21) > 0 then body_stats(current_character,4,2) = body_stats(current_character,4,2) + item_stats(Index,21)
if item_stats(Index,22) > 0 then body_stats(current_character,5,2) = body_stats(current_character,5,2) + item_stats(Index,22)




     So we've stripped 9 redundant computations of the index from the code, making it execute faster and far less error prone.

PlayBASIC Code: [Select]
       index =val(inventory_list$(current_selected_inventory_item,2))

`handle stat modifiers
if item_stats(Index,18) > 0 then body_stats(current_character,1,2) += item_stats(Index,18)
if item_stats(Index,19) > 0 then body_stats(current_character,2,2) += item_stats(Index,19)
if item_stats(Index,20) > 0 then body_stats(current_character,3,2) += item_stats(Index,20)
if item_stats(Index,21) > 0 then body_stats(current_character,4,2) += item_stats(Index,21)
if item_stats(Index,22) > 0 then body_stats(current_character,5,2) += item_stats(Index,22)





      This can be further improved by using the += operator in place of going Thing=Thing+Something  



cybermind

WOW!!!!!!!!!! YOU ARE AWESOME!!!!!!!!! I will study this post in depth before I continue! So much good stuff! Thank you very much Kevin! If you would like to see some more of the project I will gladly post a more playable version soon :-) (There have been several playable versions but I scrap them from time to time to try out new things)

cybermind

I have a couple of questions.

1. I would like to read the files in one go instead of line by line, but I saved the files from arrays in DarkBASIC line by line (the editors are made in DBPRO). Can I, and how do I, read the file now stored in memory in my PlayBasic program line by line from memory?

2. I have some troubles with the benchmarking, I added the benchmarking method you used in your examples but I get a number that keeps counting down. I will add source code with the benchmarking commands.


kevin

#12
1) The link above shows you a bunch of methods.  Basically you either use ReadMemory / ReadCHR$

   Bellow the code loads a file (text or otherwise into a string).   I generally use this method and SplitToArray to split the lines of text into an array.  

PlayBASIC Code: [Select]
      result$=LoadFIleToString("C:\SOME TEXT FILE.txt")

#print result$

print "Done"
Sync
waitkey



Function LoadFIleToString(Filename$)
if Fileexist(filename$)
Size=FileSize(Filename$)
fh=ReadNewFile(Filename$)
if fh
result$=readchr$(fh,size)
closefile Fh
endif
else
result$="File Not Found"
endif
EndFunction Result$





2) The method shown above is retuning the average performance over time.  Useful for loops where it's behavior is fixed, but not really that useful for wrapping around a game.  

   In regards to timing your making something of a potential logical error calling the 'Timer()' function through out the program.  It's unnecessary and potential error prone.    All you need is the time at the start of the frame, then everything is relative to that.


PlayBASIC Code: [Select]
   Do

; Start of frame, we get the time this frame started
CurrentTime = Timer()

; mock up of some event trapped loop based upon time
For lp=0 to Events

EventTime=GetEvent(lp)
if CurrentTime=>EventTime
; call the routine for this action. etc

endif

next

Sync
loop







       This is because each timer() call pulls the current millisecond from the system, so the result can vary between calls, which can make loops inaccurate.  

PlayBASIC Code: [Select]
   sync
repeat
Count++
until Timer()<>Timer()
print Count

sync
waitkey





       Really the same applies to reading  input devices like mouse/keys/joysticks etc...  Read them once up front and then use those states through out the program.  

       Example..

PlayBASIC Code: [Select]
    ; Two lines like this..
if leftkey() = 1 or keystate(left) = 1 or joyleft(joystick_device_chosen) = 1 then move_left = 1
if leftkey() = 0 and keystate(left) = 0 and joyleft(joystick_device_chosen) = 0 then move_left = 0


; Could just be
MoveLeft=(leftkey() = 1) or (keystate(left) = 1) or (joyleft(joystick_device_chosen) = 1)


; or even this
MoveLeft=leftkey() or keystate(left) or joyleft(joystick_device_chosen)







cybermind

#13
I have read a file with bytes into memory and read the bytes from memory, but I am having difficulties with a file containing strings. Here is what I did, and I think the problem is that I use "write string" in Darkbasic where each string is ended with the standard carriage return ASCII characters (13)+(10) instead of null terminated. I dont think I can null terminate those strings in Darkbasic.

openfile tile_filenames_file$,1
size = filesize(tile_filenames_file$)
createbank 2,size
readmemory 1,getbankptr(2),size
CloseFile 1
adress = 0
For x=1 To work_map_info(1)
For y=1 To work_map_info(2)
For layer=1 to 10
    work_map_filenames$(x,y,layer) = readstring(2,adress,0)
adress += len(work_map_filenames$(x,y,layer))
Next layer
Next y
Next x


QuoteAll you need is the time at the start of the frame, then everything is relative to that.

Yes, I actually been meaning to do that for some time, I just never got around to finishing it yet. Today I will do it! [EDIT: Done!]

QuoteReally the same applies to reading  input devices like mouse/keys/joysticks etc...  Read them once up front and then use those states through out the program. 

I have already done that :-)

EDIT: I am thinking about nibbling through the strings in the file in memory until it reaches an ascii carriage return, setting the start of the next string nibbling.

kevin

#14
  The data files don't seem to be anything special to me, if they were mixed data (binary & text) then you'd have to peek / poke them.. But you can load them into a string, strip the characters you don't want and then split it array.   The example bellow takes about 100 milliseconds to load the item_action_stats.bca (219k) data file as string, and about 1/4 of time as integers.    Since If the data is numeric, split to array can translate the strings to integers/floats for you.  


PlayBASIC Code: [Select]
      ; temp buffers
Dim Lines(10000)
Dim Lines$(10000)

filename$="E:\Downloads\Shanki Moon-2014-02-28\Shanki Moon\Data\item_action_stats.bca"

t=timer()

// Load this file and split it into this string array()
Count=LoadFileToStringArray(Filename$,Lines$())

print Count
print timer()-t


t=timer()
// Load this file and split it into this Integer array()
Count=LoadFileToIntegerArray(Filename$,Lines())

print Count

print timer()-t

print "Loading Done"
Sync
waitkey




Function LoadFileToStringArray(Filename$,Lines$())

s$=LoadFIleToString(Filename$)

; strip chr 13 from string
s$=replace$(s$,chr$(13),"")

Count=SplitToArray(s$,chr$(10),Lines$(),0)

EndFUnction Count


Function LoadFileToIntegerArray(Filename$,Lines())

s$=LoadFIleToString(Filename$)

; strip chr 13 from string
s$=replace$(s$,chr$(13),"")

Count=SplitToArray(s$,chr$(10),Lines(),0)

EndFUnction Count



Function LoadFIleToString(Filename$)
if Fileexist(filename$)
Size=FileSize(Filename$)
fh=ReadNewFile(Filename$)
if fh
result$=readchr$(fh,size)
closefile Fh
endif
else
result$="File Not Found"
endif
EndFunction Result$




 Load TextFiles To String Array



QuoteI have already done that :-)

    erm in Main it's reading the input devices multiple times.. 

PlayBASIC Code: [Select]
   `check move keys/controllers
if leftkey() = 1 or keystate(left) = 1 or joyleft(joystick_device_chosen) = 1 then move_left = 1
if leftkey() = 0 and keystate(left) = 0 and joyleft(joystick_device_chosen) = 0 then move_left = 0

if rightkey() = 1 or keystate(right) = 1 or joyright(joystick_device_chosen) = 1 then move_right = 1
if rightkey() = 0 and keystate(right) = 0 and joyright(joystick_device_chosen) = 0 then move_right = 0

if upkey() = 1 or keystate(up) = 1 or joyup(joystick_device_chosen) = 1 then move_up = 1
if upkey() = 0 and keystate(up) = 0 and joyup(joystick_device_chosen) = 0 then move_up = 0

if downkey() = 1 or keystate(down) = 1 or joydown(joystick_device_chosen) = 1 then move_down = 1
if downkey() = 0 and keystate(down) = 0 and joydown(joystick_device_chosen) = 0 then move_down = 0

if keystate(44) = 1 or keystate(action) = 1 or joybutton(joystick_device_chosen,joy_action) = 1 then action_activated = 1
if keystate(44) = 0 and keystate(action) = 0 and joybutton(joystick_device_chosen,joy_action) = 0 then action_activated = 0
if keystate(45) = 1 or keystate(cancel) = 1 or joybutton(joystick_device_chosen,joy_cancel) = 1 then cancel_activated = 1
if keystate(45) = 0 and keystate(cancel) = 0 and joybutton(joystick_device_chosen,joy_cancel) = 0 then cancel_activated = 0





      Should just be,


PlayBASIC Code: [Select]
   `check move keys/controllers
move_left = leftkey() or keystate(left) or joyleft(joystick_device_chosen)
move_right = rightkey() or keystate(right) or joyright(joystick_device_chosen)
move_up = upkey() or keystate(up) or joyup(joystick_device_chosen)
move_down = downkey() or keystate(down) or joydown(joystick_device_chosen)

action_activated = keystate(44) or keystate(action) or joybutton(joystick_device_chosen,joy_action)
cancel_activated = keystate(45) or keystate(cancel) or joybutton(joystick_device_chosen,joy_cancel)






     DIM creates a fresh clean/empty array in PB.  REDIM preserves the contents.

        So in BattleMain this type of stuff is unnecessary.

PlayBASIC Code: [Select]
dim player_action_available(12)
dim monster_in_sorted_array_list(6)
monster_in_sorted_array_list(3) = 0
monster_in_sorted_array_list(4) = 0
monster_in_sorted_array_list(5) = 0
dim monster_in_unsorted_stats_array(6)
monster_in_unsorted_stats_array(4) = 0
monster_in_unsorted_stats_array(5) = 0
monster_in_unsorted_stats_array(6) = 0
dim monster_current_hp(6)
monster_current_hp(4) = 0
monster_current_hp(5) = 0
monster_current_hp(6) = 0
dim damage_recieved(6)
damage_recieved(1) = 0
damage_recieved(2) = 0
damage_recieved(3) = 0
damage_recieved(4) = 0
damage_recieved(5) = 0
damage_recieved(6) = 0
dim needs_heal_repair(6)
needs_heal_repair(1) = 0
needs_heal_repair(2) = 0
needs_heal_repair(3) = 0
needs_heal_repair(4) = 0
needs_heal_repair(5) = 0
needs_heal_repair(6) = 0
dim character_poisoned(6,2)
character_poisoned(1,1) = 0
character_poisoned(1,2) = 0
character_poisoned(2,1) = 0
character_poisoned(2,2) = 0
character_poisoned(3,1) = 0
character_poisoned(3,2) = 0
character_poisoned(4,1) = 0
character_poisoned(4,2) = 0
character_poisoned(5,1) = 0
character_poisoned(5,2) = 0
character_poisoned(6,1) = 0
character_poisoned(6,2) = 0
dim poison_damage(6)
poison_damage(1) = 0
poison_damage(2) = 0
poison_damage(3) = 0
poison_damage(4) = 0
poison_damage(5) = 0
poison_damage(6) = 0
dim armor_added(6)
armor_added(1) = 0
armor_added(2) = 0
armor_added(3) = 0
armor_added(4) = 0
armor_added(5) = 0
armor_added(6) = 0




     becomes,

PlayBASIC Code: [Select]
dim player_action_available(12)
dim monster_in_sorted_array_list(6)
dim monster_in_unsorted_stats_array(6)
dim monster_current_hp(6)
dim damage_recieved(6)
dim needs_heal_repair(6)
dim character_poisoned(6,2)
dim poison_damage(6)
dim armor_added(6)