Commit 287dd26c authored by mercury233's avatar mercury233

Merge branch 'master' into patch-skip-confirm

parents b05c44a7 6b81a1af
name: Automated Test Build
on:
push:
branches: [ "master" ]
pull_request:
branches: [ "master" ]
jobs:
build-windows:
runs-on: windows-2022
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Download lua
id: lua
uses: mercury233/action-cache-download-file@v1.0.0
with:
url: https://www.lua.org/ftp/lua-5.4.8.tar.gz
- name: Lua
run: |
tar -xzf ${{ steps.lua.outputs.filepath }}
move lua-5.4.8 lua
- name: Download premake
id: premake
uses: mercury233/action-cache-download-file@v1.0.0
with:
url: https://github.com/premake/premake-core/releases/download/v5.0.0-beta7/premake-5.0.0-beta7-windows.zip
- name: Premake
run: |
mkdir premake-5
tar -C premake-5 -xzf ${{ steps.premake.outputs.filepath }}
copy premake\lua.lua lua\premake5.lua
copy premake\dll.lua dll.lua
.\premake-5\premake5.exe vs2022 --file=dll.lua
- name: Add msbuild to PATH
uses: microsoft/setup-msbuild@v2
- name: Build x32
run: |
msbuild build\ocgcoredll.sln /t:Build /p:"Configuration=Release;Platform=Win32"
- name: Build x64
run: |
msbuild build\ocgcoredll.sln /t:Build /p:"Configuration=Release;Platform=x64"
- name: Upload build artifacts
uses: actions/upload-artifact@v4
with:
name: ocgcore-windows
path: |
build\bin\x32\Release\ocgcore.dll
build\bin\x64\Release\ocgcore.dll
- name: GitHub Release
if: github.event_name == 'push'
uses: salix5/action-automatic-releases@node20
with:
repo_token: "${{ secrets.GITHUB_TOKEN }}"
automatic_release_tag: "latest"
prerelease: true
title: "Development Build"
files: |
build/bin/x64/Release/ocgcore.dll
build-linux:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Install Dependencies
run: |
sudo apt-get update
sudo apt-get install -y gcc-multilib g++-multilib
- name: Download lua
id: lua
uses: mercury233/action-cache-download-file@v1.0.0
with:
url: https://www.lua.org/ftp/lua-5.4.8.tar.gz
- name: Lua
run: |
tar -xzf ${{ steps.lua.outputs.filepath }}
mv lua-5.4.8 lua
- name: Download premake
id: premake
uses: mercury233/action-cache-download-file@v1.0.0
with:
url: https://github.com/premake/premake-core/releases/download/v5.0.0-beta7/premake-5.0.0-beta7-linux.tar.gz
- name: Premake
run: |
mkdir premake-5
tar -C premake-5 -xzf ${{ steps.premake.outputs.filepath }}
cp premake/lua.lua lua/premake5.lua
cp premake/dll.lua dll.lua
chmod +x premake-5/premake5
./premake-5/premake5 gmake --file=dll.lua
- name: Build x32
run: |
cd build
make -j 4 config=release_x32
cd ..
- name: Build x64
run: |
cd build
make -j 4 config=release_x64
cd ..
- name: Upload build artifacts
uses: actions/upload-artifact@v4
with:
name: ocgcore-linux
path: |
build/bin/x32/Release/libocgcore.so
build/bin/x64/Release/libocgcore.so
/.vscode/
/build/
/lua/
/temp/
/premake-5/
/premake5.exe
......@@ -4,64 +4,71 @@
The core logic and lua script processor of YGOPro. This library can be made external of the project and used to power server technologies. It maintains a state engine that is manipulated by Lua scripts using manipulation functions it exposes.
## Compiling
### 1.) Download Fluorohydride/ygopro
Start by downloading the most parent of the source code. The team developing this project are the defacto edge and experts in our community. The most upto date `ocgcore` is a compiled dll version of the `Fluorohydride/ygopro/ocgcore` folders project.
In most cases, what you want to compile is the main program of YGOPro. You should refer to the main YGOPro project's [wiki](https://github.com/Fluorohydride/ygopro/wiki).
If you want to compile the dynamic link library of this repository (ocgcore.dll), you can refer to [this script](https://github.com/Fluorohydride/ygopro-core/blob/master/.github/workflows/build.yml).
### 2.) Install Premake4 and Visual Studio 2010 (or later).
Download premake4.exe, put it in `c:\windows` or a similar folder that is globally accessible via `cmd` or PowerShell. Install Visual Studio 2010, it is the system used for the guide because other parts of the project use C# and most the development team are Windows users.
## Exposed Functions
### 3.) Download dependencies
Dependencies are absent from the main project. There is information on how to build them but the easiest thing to do is to download the following folders from a [soarqin/ygopro](https://github.com/soarqin/ygopro) fork and simply copy them into the `Fluorohydride/ygopro` folder.
The 3 functions need to be provided to the core so it can get card and database information.
- `void set_script_reader(script_reader f);`
Interface provided returns scripts based on number that corresponds to a lua file, send in a string.
* event
* freetype
* irrlicht
* lua
* sqlite3
- `void set_card_reader(card_reader f);`
Interface provided function that provides database information from the `data` table of `cards.cdb`.
### 4.) Create the project files
Run the following commands from the command line in the `Fluorohydride/ygopro` folder.
- `void set_message_handler(message_handler f);`
Interface provided function that handles error messages.
` premake4 /help `
` premake4 vs2010 `
These functions create the game itself and then manipulate it.
- `intptr_t create_duel(uint_fast32_t seed);`
Create a the instance of the duel with a PRNG seed.
If you are not using Visual Studio 2010 or higher, make the needed adjustments. In the file system open `Fluorohydride/ygopro/build` folder open the `ygo` project.
- `void start_duel(intptr_t pduel, uint32_t options);`
Start the duel.
### 5.) Build the system
Make sure the code actually compiles. Compile them in the following order one by one:
- `void end_duel(intptr_t pduel);`
End the duel.
* lua
* sqlite3
* ocgcore
- `void set_player_info(intptr_t pduel, int32_t playerid, int32_t lp, int32_t startcount, int32_t drawcount);`
Set up the duel information.
This should provide you with `ocgcore.lib` in the build output folder. `YGOCore` requires a `*.dll`; in `ocgcore` project properties change it to a dynamically linked library. Recompile, it should fail with an error indicating missing dependencies. Right click the project, add an existing file. Add `lua.lib` from the build folder to the project. It should now compile.
- `void get_log_message(intptr_t pduel, char* buf);`
## Exposed Functions
- `int32_t get_message(intptr_t pduel, byte* buf);`
These three function need to be provided to the core so it can get card and database information.
- `void set_script_reader(script_reader f);` : Interface provided returns scripts based on number that corresponds to a lua file, send in a string.
- `int32_t process(intptr_t pduel);`
Do a game tick.
- `void set_card_reader(card_reader f);` : Interface provided function that provides database information from the `data` table of `cards.cdb`.
- `void new_card(intptr_t pduel, uint32_t code, uint8_t owner, uint8_t playerid, uint8_t location, uint8_t sequence, uint8_t position);`
Add a card to the duel state.
- `void set_message_handler(message_handler f);` : Interface provided function that handles errors
- `void new_tag_card(intptr_t pduel, uint32_t code, uint8_t owner, uint8_t location);`
Add a new card to the tag pool.
These functions create the game itself and then manipulate it.
- `ptr create_duel(uint32 seed);` : Create a the instance of the duel using a random number.
- `void start_duel(ptr pduel, int32 options);` : Starts the duel
- `void end_duel(ptr pduel);` : ends the duel
- `void set_player_info(ptr pduel, int32 playerid, int32 lp, int32 startcount, int32 drawcount);` sets the duel up
- `void get_log_message(ptr pduel, byte* buf);`
- `int32 get_message(ptr pduel, byte* buf);`
- `int32 process(ptr pduel);` : do a game tick
- `void new_card(ptr pduel, uint32 code, uint8 owner, uint8 playerid, uint8 location, uint8 sequence, uint8 position);` : add a card to the duel state.
- `void new_tag_card(ptr pduel, uint32 code, uint8 owner, uint8 location);` : add a new card to the tag pool.
- `int32 query_card(ptr pduel, uint8 playerid, uint8 location, uint8 sequence, int32 query_flag, byte* buf, int32 use_cache);` : find out about a card in a specific spot.
- `int32 query_field_count(ptr pduel, uint8 playerid, uint8 location);` : Get the number of cards in a specific field/zone.
- `int32 query_field_card(ptr pduel, uint8 playerid, uint8 location, int32 query_flag, byte* buf, int32 use_cache);`
- `int32 query_field_info(ptr pduel, byte* buf);`
- `void set_responsei(ptr pduel, int32 value);`
- `void set_responseb(ptr pduel, byte* buf);`
- `int32 preload_script(ptr pduel, char* script, int32 len);`
- `int32_t query_field_card(intptr_t pduel, uint8_t playerid, uint8_t location, uint32_t query_flag, byte* buf, int32_t use_cache);`
Get a card in a specific location.
- `int32_t query_field_count(intptr_t pduel, uint8_t playerid, uint8_t location);`
Get the number of cards in a specific location.
- `int32_t query_field_card(intptr_t pduel, uint8_t playerid, uint8_t location, uint32_t query_flag, byte* buf, int32_t use_cache);`
Get all cards in some location.
- `int32_t query_field_info(intptr_t pduel, byte* buf);`
- `void set_responsei(intptr_t pduel, int32_t value);`
- `void set_responseb(intptr_t pduel, byte* buf);`
- `int32_t preload_script(intptr_t pduel, const char* script_name);`
- `byte* default_script_reader(const char* script_name, int* len);`
The default script reader using `fread`.
# Lua functions
`interpreter.cpp`
- `libcard.cpp`
- `libdebug.cpp`
- `libduel.cpp`
- `libeffect.cpp`
- `libgroup.cpp`
#ifndef CORE_BUFFER_H
#define CORE_BUFFER_H
#include <cstdio>
#include <cstring>
#include <vector>
inline void buffer_read_block(unsigned char*& p, void* dest, size_t size) {
std::memcpy(dest, p, size);
p += size;
}
template<typename T>
inline T buffer_read(unsigned char*& p) {
T ret{};
std::memcpy(&ret, p, sizeof(T));
p += sizeof(T);
return ret;
}
inline void buffer_write_block(unsigned char*& p, const void* src, size_t size) {
std::memcpy(p, src, size);
p += size;
}
template<typename T>
inline void buffer_write(unsigned char*& p, T value) {
std::memcpy(p, &value, sizeof(T));
p += sizeof(T);
}
inline void vector_write_block(std::vector<unsigned char>& buffer, const void* src, size_t size) {
const auto len = buffer.size();
buffer.resize(len + size);
std::memcpy(&buffer[len], src, size);
}
template<typename T>
inline void vector_write(std::vector<unsigned char>& buffer, T value) {
vector_write_block(buffer, &value, sizeof(T));
}
inline void vector_fread(std::vector<unsigned char>& buffer, FILE* fp) {
unsigned char temp[4096]{};
while (size_t len = std::fread(temp, 1, sizeof temp, fp))
vector_write_block(buffer, temp, len);
std::fclose(fp);
}
#endif // !CORE_BUFFER_H
This source diff could not be displayed because it is too large. You can view the blob instead.
This diff is collapsed.
#ifndef CARD_DATA_H_
#define CARD_DATA_H_
#include <cstring>
#include <unordered_map>
#include "common.h"
constexpr int CARD_ARTWORK_VERSIONS_OFFSET = 20;
constexpr int SIZE_SETCODE = 16;
constexpr uint32_t CARD_BLACK_LUSTER_SOLDIER2 = 5405695;
//double name
constexpr uint32_t CARD_MARINE_DOLPHIN = 78734254;
constexpr uint32_t CARD_TWINKLE_MOSS = 13857930;
constexpr uint32_t CARD_TIMAEUS = 1784686;
constexpr uint32_t CARD_CRITIAS = 11082056;
constexpr uint32_t CARD_HERMOS = 46232525;
const std::unordered_map<uint32_t, uint32_t> second_code = {
{CARD_MARINE_DOLPHIN, 17955766u},
{CARD_TWINKLE_MOSS, 17732278u},
{CARD_TIMAEUS, 10000050u},
{CARD_CRITIAS, 10000060u},
{CARD_HERMOS, 10000070u},
};
struct card_data {
uint32_t code{};
uint32_t alias{};
uint16_t setcode[SIZE_SETCODE]{};
uint32_t type{};
uint32_t level{};
uint32_t attribute{};
uint32_t race{};
int32_t attack{};
int32_t defense{};
uint32_t lscale{};
uint32_t rscale{};
uint32_t link_marker{};
void clear() {
std::memset(this, 0, sizeof(card_data));
}
bool is_setcode(uint32_t value) const {
const uint16_t settype = value & 0x0fff;
const uint16_t setsubtype = value & 0xf000;
for (auto& x : setcode) {
if ((x & 0x0fff) == settype && (x & setsubtype) == setsubtype)
return true;
if (!x)
return false;
}
return false;
}
bool is_alternative() const {
if (code == CARD_BLACK_LUSTER_SOLDIER2)
return false;
return alias && (alias < code + CARD_ARTWORK_VERSIONS_OFFSET) && (code < alias + CARD_ARTWORK_VERSIONS_OFFSET);
}
void set_setcode(uint64_t value) {
int ctr = 0;
while (value) {
if (value & 0xffff) {
setcode[ctr] = value & 0xffff;
++ctr;
}
value >>= 16;
}
if (ctr < SIZE_SETCODE)
std::memset(setcode + ctr, 0, (SIZE_SETCODE - ctr) * sizeof(uint16_t));
}
uint32_t get_original_code() const {
return is_alternative() ? alias : code;
}
};
#endif /* CARD_DATA_H_ */
......@@ -9,16 +9,12 @@
#define COMMON_H_
#include <stdint.h>
typedef unsigned long long uint64;
typedef unsigned int uint32;
typedef unsigned short uint16;
typedef unsigned char uint8;
#include <assert.h>
typedef unsigned char byte;
typedef long long int64;
typedef int int32;
typedef short int16;
typedef signed char int8;
typedef int BOOL;
inline bool check_playerid(int32_t playerid) {
return playerid >= 0 && playerid <= 1;
}
#define MATCH_ALL(x,y) (((x)&(y))==(y))
#define MATCH_ANY(x,y) ((x)&(y))
......@@ -30,25 +26,35 @@ typedef int BOOL;
#define OPERATION_CANCELED -1
#define TRUE 1
#define FALSE 0
#ifndef NULL
#define NULL 0
#endif
struct card_sort {
bool operator()(void* const & c1, void* const & c2) const;
};
#define SIZE_MESSAGE_BUFFER 0x2000
#define SIZE_RETURN_VALUE 512
#define SIZE_AI_NAME 128
#define SIZE_HINT_MSG 1024
#define PROCESSOR_BUFFER_LEN 0x0fffffff
#define PROCESSOR_FLAG 0xf0000000
#define PROCESSOR_NONE 0
#define PROCESSOR_WAITING 0x10000000
#define PROCESSOR_END 0x20000000
#define MASTER_RULE3 3 //Master Rule 3 (2014)
#define NEW_MASTER_RULE 4 //New Master Rule (2017)
#define MASTER_RULE_2020 5 //Master Rule 2020
#define CURRENT_RULE 5
//Locations
#define LOCATION_DECK 0x01 //
#define LOCATION_HAND 0x02 //
#define LOCATION_MZONE 0x04 //
#define LOCATION_SZONE 0x08 //
#define LOCATION_GRAVE 0x10 //
#define LOCATION_REMOVED 0x20 //
#define LOCATION_EXTRA 0x40 //
#define LOCATION_OVERLAY 0x80 //
#define LOCATION_ONFIELD 0x0c //
#define LOCATION_FZONE 0x100 //
#define LOCATION_PZONE 0x200 //
#define LOCATION_DECK 0x01U
#define LOCATION_HAND 0x02U
#define LOCATION_MZONE 0x04U
#define LOCATION_SZONE 0x08U
#define LOCATION_GRAVE 0x10U
#define LOCATION_REMOVED 0x20U
#define LOCATION_EXTRA 0x40U
#define LOCATION_OVERLAY 0x80U
#define LOCATION_ONFIELD (LOCATION_MZONE | LOCATION_SZONE)
#define LOCATION_FZONE 0x100U
#define LOCATION_PZONE 0x200U
//For redirect
#define LOCATION_DECKBOT 0x10001 //Return to deck bottom
#define LOCATION_DECKSHF 0x20001 //Return to deck and shuffle
......@@ -69,6 +75,10 @@ struct card_sort {
//Flip effect flags
#define NO_FLIP_EFFECT 0x10000
//Move to field flags
#define RETURN_TEMP_REMOVE_TO_FIELD 1
#define RETURN_TRAP_MONSTER_TO_SZONE 2
//Types
#define TYPE_MONSTER 0x1 //
#define TYPE_SPELL 0x2 //
......@@ -96,7 +106,11 @@ struct card_sort {
#define TYPE_SPSUMMON 0x2000000 //
#define TYPE_LINK 0x4000000 //
#define TYPES_EXTRA_DECK (TYPE_FUSION | TYPE_SYNCHRO | TYPE_XYZ | TYPE_LINK)
//Attributes
#define ATTRIBUTES_COUNT 7
#define ATTRIBUTE_ALL 0x7f //
#define ATTRIBUTE_EARTH 0x01 //
#define ATTRIBUTE_WATER 0x02 //
#define ATTRIBUTE_FIRE 0x04 //
......@@ -106,6 +120,8 @@ struct card_sort {
#define ATTRIBUTE_DEVINE 0x40 //
//Races
#define RACES_COUNT 26
#define RACE_ALL 0x3ffffff
#define RACE_WARRIOR 0x1 //
#define RACE_SPELLCASTER 0x2 //
#define RACE_FAIRY 0x4 //
......@@ -131,6 +147,7 @@ struct card_sort {
#define RACE_CREATORGOD 0x400000 //
#define RACE_WYRM 0x800000 //
#define RACE_CYBERSE 0x1000000 //
#define RACE_ILLUSION 0x2000000 //
//Reason
#define REASON_DESTROY 0x1 //
......@@ -161,29 +178,33 @@ struct card_sort {
#define REASON_REVEAL 0x8000000 //
#define REASON_LINK 0x10000000 //
#define REASON_LOST_OVERLAY 0x20000000 //
#define REASON_MAINTENANCE 0x40000000 //
#define REASON_ACTION 0x80000000 //
#define REASONS_PROCEDURE (REASON_SYNCHRO | REASON_XYZ | REASON_LINK)
//Status
#define STATUS_DISABLED 0x0001 //
#define STATUS_TO_ENABLE 0x0002 //
#define STATUS_TO_DISABLE 0x0004 //
#define STATUS_PROC_COMPLETE 0x0008 //
#define STATUS_SET_TURN 0x0010 //
#define STATUS_NO_LEVEL 0x0020 //
#define STATUS_BATTLE_RESULT 0x0040 //
#define STATUS_SPSUMMON_STEP 0x0080 //
#define STATUS_FORM_CHANGED 0x0100 //
#define STATUS_SUMMONING 0x0200 //
#define STATUS_EFFECT_ENABLED 0x0400 //
#define STATUS_SUMMON_TURN 0x0800 //
#define STATUS_DESTROY_CONFIRMED 0x1000 //
#define STATUS_LEAVE_CONFIRMED 0x2000 //
#define STATUS_BATTLE_DESTROYED 0x4000 //
#define STATUS_COPYING_EFFECT 0x8000 //
#define STATUS_CHAINING 0x10000 //
#define STATUS_SUMMON_DISABLED 0x20000 //
#define STATUS_ACTIVATE_DISABLED 0x40000 //
#define STATUS_DISABLED 0x0001
#define STATUS_TO_ENABLE 0x0002
#define STATUS_TO_DISABLE 0x0004
#define STATUS_PROC_COMPLETE 0x0008
#define STATUS_SET_TURN 0x0010
#define STATUS_NO_LEVEL 0x0020
#define STATUS_BATTLE_RESULT 0x0040
#define STATUS_SPSUMMON_STEP 0x0080
#define STATUS_CANNOT_CHANGE_FORM 0x0100
#define STATUS_SUMMONING 0x0200
#define STATUS_EFFECT_ENABLED 0x0400
#define STATUS_SUMMON_TURN 0x0800
#define STATUS_DESTROY_CONFIRMED 0x1000
#define STATUS_LEAVE_CONFIRMED 0x2000
#define STATUS_BATTLE_DESTROYED 0x4000
#define STATUS_COPYING_EFFECT 0x8000
#define STATUS_CHAINING 0x10000
#define STATUS_SUMMON_DISABLED 0x20000
#define STATUS_ACTIVATE_DISABLED 0x40000
#define STATUS_EFFECT_REPLACED 0x80000
#define STATUS_FUTURE_FUSION 0x100000
#define STATUS_FLIP_SUMMONING 0x100000
#define STATUS_ATTACK_CANCELED 0x200000
#define STATUS_INITIALIZING 0x400000
#define STATUS_TO_HAND_WITHOUT_CONFIRM 0x800000
......@@ -194,6 +215,7 @@ struct card_sort {
#define STATUS_OPPO_BATTLE 0x10000000
#define STATUS_FLIP_SUMMON_TURN 0x20000000
#define STATUS_SPSUMMON_TURN 0x40000000
#define STATUS_FLIP_SUMMON_DISABLED 0x80000000
//Query list
#define QUERY_CODE 0x1
......@@ -233,12 +255,12 @@ struct card_sort {
//Messages
#define MSG_RETRY 1
#define MSG_HINT 2
#define MSG_WAITING 3
#define MSG_START 4
//#define MSG_WAITING 3
//#define MSG_START 4
#define MSG_WIN 5
#define MSG_UPDATE_DATA 6
#define MSG_UPDATE_CARD 7
#define MSG_REQUEST_DECK 8
//#define MSG_UPDATE_DATA 6
//#define MSG_UPDATE_CARD 7
//#define MSG_REQUEST_DECK 8
#define MSG_SELECT_BATTLECMD 10
#define MSG_SELECT_IDLECMD 11
#define MSG_SELECT_EFFECTYN 12
......@@ -249,7 +271,6 @@ struct card_sort {
#define MSG_SELECT_PLACE 18
#define MSG_SELECT_POSITION 19
#define MSG_SELECT_TRIBUTE 20
//#define MSG_SORT_CHAIN 21
#define MSG_SELECT_COUNTER 22
#define MSG_SELECT_SUM 23
#define MSG_SELECT_DISFIELD 24
......@@ -259,7 +280,7 @@ struct card_sort {
#define MSG_CONFIRM_CARDS 31
#define MSG_SHUFFLE_DECK 32
#define MSG_SHUFFLE_HAND 33
#define MSG_REFRESH_DECK 34
//#define MSG_REFRESH_DECK 34
#define MSG_SWAP_GRAVE_DECK 35
#define MSG_SHUFFLE_SET_CARD 36
#define MSG_REVERSE_DECK 37
......@@ -286,7 +307,7 @@ struct card_sort {
#define MSG_CHAIN_END 74
#define MSG_CHAIN_NEGATED 75
#define MSG_CHAIN_DISABLED 76
#define MSG_CARD_SELECTED 80
//#define MSG_CARD_SELECTED 80
#define MSG_RANDOM_SELECTED 81
#define MSG_BECOME_TARGET 83
#define MSG_DRAW 90
......@@ -294,7 +315,7 @@ struct card_sort {
#define MSG_RECOVER 92
#define MSG_EQUIP 93
#define MSG_LPUPDATE 94
#define MSG_UNEQUIP 95
//#define MSG_UNEQUIP 95
#define MSG_CARD_TARGET 96
#define MSG_CANCEL_TARGET 97
#define MSG_PAY_LPCOST 100
......@@ -306,9 +327,9 @@ struct card_sort {
#define MSG_DAMAGE_STEP_START 113
#define MSG_DAMAGE_STEP_END 114
#define MSG_MISSED_EFFECT 120
#define MSG_BE_CHAIN_TARGET 121
#define MSG_CREATE_RELATION 122
#define MSG_RELEASE_RELATION 123
//#define MSG_BE_CHAIN_TARGET 121
//#define MSG_CREATE_RELATION 122
//#define MSG_RELEASE_RELATION 123
#define MSG_TOSS_COIN 130
#define MSG_TOSS_DICE 131
#define MSG_ROCK_PAPER_SCISSORS 132
......@@ -319,9 +340,9 @@ struct card_sort {
#define MSG_ANNOUNCE_NUMBER 143
#define MSG_CARD_HINT 160
#define MSG_TAG_SWAP 161
#define MSG_RELOAD_FIELD 162 // Debug.ReloadFieldEnd()
#define MSG_AI_NAME 163
#define MSG_SHOW_HINT 164
#define MSG_RELOAD_FIELD 162 // Debug.ReloadFieldEnd() or query_field_info()
#define MSG_AI_NAME 163 // Debug.AIName()
#define MSG_SHOW_HINT 164 // Debug.ShowHint()
#define MSG_PLAYER_HINT 165
#define MSG_MATCH_KILL 170
#define MSG_CUSTOM_MSG 180
......@@ -388,12 +409,13 @@ struct card_sort {
//Options
#define DUEL_TEST_MODE 0x01
#define DUEL_ATTACK_FIRST_TURN 0x02
#define DUEL_OLD_REPLAY 0x04
//#define DUEL_OLD_REPLAY 0x04
#define DUEL_OBSOLETE_RULING 0x08
#define DUEL_PSEUDO_SHUFFLE 0x10
#define DUEL_TAG_MODE 0x20
#define DUEL_SIMPLE_AI 0x40
#define DUEL_RETURN_DECK_TOP 0x80
#define DUEL_REVEAL_DECK_SEQ 0x100
//Activity
#define ACTIVITY_SUMMON 1
......
......@@ -5,6 +5,7 @@
* Author: Argon
*/
#include <cstring>
#include "duel.h"
#include "interpreter.h"
#include "field.h"
......@@ -12,12 +13,16 @@
#include "effect.h"
#include "group.h"
#include "ocgapi.h"
#include "buffer.h"
duel::duel() {
lua = new interpreter(this);
game_field = new field(this);
game_field->temp_card = new_card(0);
clear_buffer();
game_field->temp_card = new_card(TEMP_CARD_ID);
message_buffer.reserve(SIZE_MESSAGE_BUFFER);
#ifdef _WIN32
_set_error_mode(_OUT_TO_MSGBOX);
#endif // _WIN32
}
duel::~duel() {
for(auto& pcard : cards)
......@@ -40,16 +45,17 @@ void duel::clear() {
cards.clear();
groups.clear();
effects.clear();
assumes.clear();
sgroups.clear();
uncopy.clear();
game_field = new field(this);
game_field->temp_card = new_card(0);
game_field->temp_card = new_card(TEMP_CARD_ID);
}
card* duel::new_card(uint32 code) {
card* duel::new_card(uint32_t code) {
card* pcard = new card(this);
cards.insert(pcard);
if(code)
if (code != TEMP_CARD_ID)
::read_card(code, &(pcard->data));
else
pcard->data.clear();
pcard->data.code = code;
lua->register_card(pcard);
return pcard;
......@@ -94,13 +100,15 @@ void duel::delete_effect(effect* peffect) {
effects.erase(peffect);
delete peffect;
}
int32 duel::read_buffer(byte* buf) {
std::memcpy(buf, buffer, bufferlen);
return bufferlen;
int32_t duel::read_buffer(byte* buf) {
auto size = buffer_size();
if (size)
std::memcpy(buf, message_buffer.data(), size);
return (int32_t)size;
}
void duel::release_script_group() {
for(auto& pgroup : sgroups) {
if(pgroup->is_readonly == 0) {
if(pgroup->is_readonly == GTYPE_DEFAULT) {
lua->unregister_group(pgroup);
groups.erase(pgroup);
delete pgroup;
......@@ -113,36 +121,29 @@ void duel::restore_assumes() {
pcard->assume_type = 0;
assumes.clear();
}
void duel::write_buffer32(uint32 value) {
std::memcpy(bufferp, &value, sizeof(value));
bufferp += 4;
bufferlen += 4;
void duel::write_buffer(const void* data, int size) {
vector_write_block(message_buffer, data, size);
}
void duel::write_buffer32(uint32_t value) {
vector_write<uint32_t>(message_buffer, value);
}
void duel::write_buffer16(uint16 value) {
std::memcpy(bufferp, &value, sizeof(value));
bufferp += 2;
bufferlen += 2;
void duel::write_buffer16(uint16_t value) {
vector_write<uint16_t>(message_buffer, value);
}
void duel::write_buffer8(uint8 value) {
std::memcpy(bufferp, &value, sizeof(value));
bufferp += 1;
bufferlen += 1;
void duel::write_buffer8(uint8_t value) {
vector_write<unsigned char>(message_buffer, value);
}
void duel::clear_buffer() {
bufferlen = 0;
bufferp = buffer;
message_buffer.clear();
}
void duel::set_responsei(uint32 resp) {
void duel::set_responsei(uint32_t resp) {
game_field->returns.ivalue[0] = resp;
}
void duel::set_responseb(byte* resp) {
std::memcpy(game_field->returns.bvalue, resp, 64);
std::memcpy(game_field->returns.bvalue, resp, SIZE_RETURN_VALUE);
}
int32 duel::get_next_integer(int32 l, int32 h) {
if (game_field->core.duel_options & DUEL_OLD_REPLAY) {
return random.get_random_integer_old(l, h);
}
else {
return random.get_random_integer(l, h);
}
int32_t duel::get_next_integer(int32_t l, int32_t h) {
if (rng_version == 1)
return random.get_random_integer_v1(l, h);
return random.get_random_integer_v2(l, h);
}
......@@ -9,9 +9,11 @@
#define DUEL_H_
#include "common.h"
#include "sort.h"
#include "mtrandom.h"
#include <set>
#include <unordered_set>
#include <vector>
class card;
class group;
......@@ -19,16 +21,17 @@ class effect;
class field;
class interpreter;
using card_set = std::set<card*, card_sort>;
class duel {
public:
using card_set = std::set<card*, card_sort>;
char strbuffer[256];
byte buffer[0x1000];
uint32 bufferlen;
byte* bufferp;
char strbuffer[256]{};
int32_t rng_version{ 2 };
interpreter* lua;
field* game_field;
mt19937 random;
mtrandom random;
std::vector<byte> message_buffer;
std::unordered_set<card*> cards;
std::unordered_set<card*> assumes;
std::unordered_set<group*> groups;
......@@ -40,7 +43,10 @@ public:
~duel();
void clear();
card* new_card(uint32 code);
uint32_t buffer_size() const {
return (uint32_t)message_buffer.size() & PROCESSOR_BUFFER_LEN;
}
card* new_card(uint32_t code);
group* new_group();
group* new_group(card* pcard);
group* new_group(const card_set& cset);
......@@ -50,14 +56,15 @@ public:
void delete_effect(effect* peffect);
void release_script_group();
void restore_assumes();
int32 read_buffer(byte* buf);
void write_buffer32(uint32 value);
void write_buffer16(uint16 value);
void write_buffer8(uint8 value);
int32_t read_buffer(byte* buf);
void write_buffer(const void* data, int size);
void write_buffer32(uint32_t value);
void write_buffer16(uint16_t value);
void write_buffer8(uint8_t value);
void clear_buffer();
void set_responsei(uint32 resp);
void set_responsei(uint32_t resp);
void set_responseb(byte* resp);
int32 get_next_integer(int32 l, int32 h);
int32_t get_next_integer(int32_t l, int32_t h);
private:
group* register_group(group* pgroup);
};
......
This diff is collapsed.
This diff is collapsed.
......@@ -8,8 +8,6 @@
#ifndef EFFECTSET_H_
#define EFFECTSET_H_
#include <stdlib.h>
#include <array>
#include <vector>
#include <algorithm>
......@@ -17,100 +15,7 @@ class effect;
bool effect_sort_id(const effect* e1, const effect* e2);
struct effect_set {
effect_set()
: count(0), container{ nullptr } {}
void add_item(effect* peffect) {
if(count >= 64) return;
container[count++] = peffect;
}
void remove_item(int index) {
if(index >= count)
return;
if(index == count - 1) {
count--;
return;
}
for(int i = index; i < count - 1; ++i)
container[i] = container[i + 1];
count--;
}
void clear() {
count = 0;
}
int size() const {
return count;
}
void sort() {
if(count < 2)
return;
std::sort(container.begin(), container.begin() + count, effect_sort_id);
}
effect* const& get_last() const {
return container[count - 1];
}
effect*& get_last() {
return container[count - 1];
}
effect* const& operator[] (int index) const {
return container[index];
}
effect*& operator[] (int index) {
return container[index];
}
effect* const& at(int index) const {
return container[index];
}
effect*& at(int index) {
return container[index];
}
private:
std::array<effect*, 64> container;
int count;
};
struct effect_set_v {
effect_set_v() {}
void add_item(effect* peffect) {
container.push_back(peffect);
}
void remove_item(int index) {
if(index >= (int)container.size())
return;
container.erase(container.begin() + index);
}
void clear() {
container.clear();
}
int size() const {
return (int)container.size();
}
void sort() {
int count = (int)container.size();
if(count < 2)
return;
std::sort(container.begin(), container.begin() + count, effect_sort_id);
}
effect* const& get_last() const {
return container.back();
}
effect*& get_last() {
return container.back();
}
effect* const& operator[] (int index) const {
return container[index];
}
effect*& operator[] (int index) {
return container[index];
}
effect* const& at(int index) const {
return container[index];
}
effect*& at(int index) {
return container[index];
}
private:
std::vector<effect*> container;
};
using effect_set = std::vector<effect*>;
using effect_set_v = effect_set;
#endif //EFFECTSET_H_
This diff is collapsed.
This diff is collapsed.
......@@ -10,21 +10,15 @@
#include "duel.h"
group::group(duel* pd) {
ref_handle = 0;
pduel = pd;
is_readonly = FALSE;
it = container.begin();
}
group::group(duel* pd, card* pcard) {
container.insert(pcard);
ref_handle = 0;
pduel = pd;
is_readonly = FALSE;
it = container.begin();
}
group::group(duel* pd, const card_set& cset): container(cset) {
ref_handle = 0;
pduel = pd;
is_readonly = FALSE;
it = container.begin();
}
......@@ -9,22 +9,29 @@
#define GROUP_H_
#include "common.h"
#include "sort.h"
#include <set>
#include <list>
class card;
class duel;
class group {
using card_set = std::set<card*, card_sort>;
constexpr uint32_t GTYPE_DEFAULT = 0;
constexpr uint32_t GTYPE_READ_ONLY = 1;
constexpr uint32_t GTYPE_KEEP_ALIVE = 2;
class alignas(8) group {
public:
using card_set = std::set<card*, card_sort>;
int32 ref_handle;
int32_t ref_handle{ 0 };
uint32_t is_readonly{ GTYPE_DEFAULT };
duel* pduel;
card_set container;
card_set::iterator it;
uint32 is_readonly;
bool is_iterator_dirty{ true };
inline bool has_card(card* c) {
bool has_card(card* c) {
return container.find(c) != container.end();
}
......
This diff is collapsed.
......@@ -8,25 +8,40 @@
#ifndef INTERPRETER_H_
#define INTERPRETER_H_
#include "lua.h"
#include "lauxlib.h"
#include "lualib.h"
#include <lua.h>
#include <lauxlib.h>
#include <lualib.h>
#include "common.h"
#include <unordered_map>
#include <list>
#include <vector>
#include <cstdio>
#include <cstring>
class card;
struct card_data;
class effect;
class group;
class duel;
enum LuaParamType : int32_t {
PARAM_TYPE_INT = 0x01,
PARAM_TYPE_STRING = 0x02,
PARAM_TYPE_CARD = 0x04,
PARAM_TYPE_GROUP = 0x08,
PARAM_TYPE_EFFECT = 0x10,
PARAM_TYPE_FUNCTION = 0x20,
PARAM_TYPE_BOOLEAN = 0x40,
PARAM_TYPE_INDEX = 0x80,
};
class interpreter {
public:
using coroutine_map = std::unordered_map<int32, lua_State*>;
using param_list = std::list<std::pair<void*, uint32>>;
union lua_param {
void* ptr;
int32_t integer;
};
using coroutine_map = std::unordered_map<int32_t, std::pair<lua_State*, int32_t>>;
using param_list = std::list<std::pair<lua_param, LuaParamType>>;
duel* pduel;
char msgbuf[64];
......@@ -35,41 +50,42 @@ public:
param_list params;
param_list resumes;
coroutine_map coroutines;
int32 no_action;
int32 call_depth;
int32_t no_action;
int32_t call_depth;
explicit interpreter(duel* pd);
~interpreter();
int32 register_card(card* pcard);
void register_card(card* pcard);
void register_effect(effect* peffect);
void unregister_effect(effect* peffect);
void register_group(group* pgroup);
void unregister_group(group* pgroup);
int32 load_script(const char* script_name);
int32 load_card_script(uint32 code);
void add_param(void* param, int32 type, bool front = false);
void add_param(int32 param, int32 type, bool front = false);
int32_t load_script(const char* script_name);
int32_t load_card_script(uint32_t code);
void add_param(void* param, LuaParamType type, bool front = false);
void add_param(int32_t param, LuaParamType type, bool front = false);
void push_param(lua_State* L, bool is_coroutine = false);
int32 call_function(int32 f, uint32 param_count, int32 ret_count);
int32 call_card_function(card* pcard, const char* f, uint32 param_count, int32 ret_count);
int32 call_code_function(uint32 code, const char* f, uint32 param_count, int32 ret_count);
int32 check_condition(int32 f, uint32 param_count);
int32 check_matching(card* pcard, int32 findex, int32 extraargs);
int32 get_operation_value(card* pcard, int32 findex, int32 extraargs);
int32 get_function_value(int32 f, uint32 param_count);
int32 get_function_value(int32 f, uint32 param_count, std::vector<int32>* result);
int32 call_coroutine(int32 f, uint32 param_count, uint32* yield_value, uint16 step);
int32 clone_function_ref(int32 func_ref);
void* get_ref_object(int32 ref_handler);
int32_t call_function(int32_t f, uint32_t param_count, int32_t ret_count);
int32_t call_card_function(card* pcard, const char* f, uint32_t param_count, int32_t ret_count);
int32_t call_code_function(uint32_t code, const char* f, uint32_t param_count, int32_t ret_count);
int32_t check_condition(int32_t f, uint32_t param_count);
int32_t check_filter(lua_State* L, card* pcard, int32_t findex, int32_t extraargs);
int32_t get_operation_value(card* pcard, int32_t findex, int32_t extraargs);
int32_t get_function_value(int32_t f, uint32_t param_count);
int32_t get_function_value(int32_t f, uint32_t param_count, std::vector<lua_Integer>& result);
int32_t call_coroutine(int32_t f, uint32_t param_count, int32_t* yield_value, uint16_t step);
int32_t clone_function_ref(int32_t func_ref);
void* get_ref_object(int32_t ref_handler);
static void card2value(lua_State* L, card* pcard);
static void group2value(lua_State* L, group* pgroup);
static void effect2value(lua_State* L, effect* peffect);
static void function2value(lua_State* L, int32 pointer);
static int32 get_function_handle(lua_State* L, int32 index);
static void function2value(lua_State* L, int32_t func_ref);
static int32_t get_function_handle(lua_State* L, int32_t index);
static duel* get_duel_info(lua_State* L);
static bool is_load_script(const card_data& data);
template <size_t N, typename... TR>
static int sprintf(char (&buffer)[N], const char* format, TR... args) {
......@@ -77,15 +93,6 @@ public:
}
};
#define PARAM_TYPE_INT 0x01
#define PARAM_TYPE_STRING 0x02
#define PARAM_TYPE_CARD 0x04
#define PARAM_TYPE_GROUP 0x08
#define PARAM_TYPE_EFFECT 0x10
#define PARAM_TYPE_FUNCTION 0x20
#define PARAM_TYPE_BOOLEAN 0x40
#define PARAM_TYPE_INDEX 0x80
#define COROUTINE_FINISH 1
#define COROUTINE_YIELD 2
#define COROUTINE_ERROR 3
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -9,61 +9,77 @@
#define MTRANDOM_H_
#include <random>
#include <vector>
#include <utility>
class mt19937 {
class mtrandom {
public:
const unsigned int rand_max;
const unsigned int rand_max{ std::mt19937::max() };
mt19937() :
rng(), rand_max((rng.max)()) {}
explicit mt19937(unsigned int seed) :
rng(seed), rand_max((rng.max)()) {}
mtrandom() :
rng() {}
mtrandom(uint32_t seq[], size_t len) {
std::seed_seq q(seq, seq + len);
rng.seed(q);
}
explicit mtrandom(uint_fast32_t value) :
rng(value) {}
mtrandom(std::seed_seq& q) :
rng(q) {}
mtrandom(const mtrandom& other) = delete;
void operator=(const mtrandom& other) = delete;
// mersenne_twister_engine
void reset(unsigned int seed) {
rng.seed(seed);
void seed(uint32_t seq[], size_t len) {
std::seed_seq q(seq, seq + len);
rng.seed(q);
}
void seed(uint_fast32_t value) {
rng.seed(value);
}
unsigned int rand() {
void seed(std::seed_seq& q) {
rng.seed(q);
}
uint_fast32_t rand() {
return rng();
}
void discard(unsigned long long z) {
rng.discard(z);
}
// uniform_int_distribution
int get_random_integer(int l, int h) {
unsigned int range = (unsigned int)(h - l + 1);
unsigned int secureMax = rand_max - rand_max % range;
unsigned int x;
// old vesion, discard too many numbers
int get_random_integer_v1(int l, int h) {
uint32_t range = (h - l + 1);
uint32_t secureMax = rand_max - rand_max % range;
uint_fast32_t x;
do {
x = rng();
} while (x >= secureMax);
return (int)(l + x % range);
}
int get_random_integer_old(int l, int h) {
int result = (int)((double)rng() / rand_max * ((double)h - l + 1)) + l;
if (result > h)
result = h;
return result;
return l + (int)(x % range);
}
// Fisher-Yates shuffle v[a]~v[b]
template<typename T>
void shuffle_vector(std::vector<T>& v, int a = -1, int b = -1) {
if (a < 0)
a = 0;
if (b < 0)
b = (int)v.size() - 1;
for (int i = a; i < b; ++i) {
int r = get_random_integer(i, b);
std::swap(v[i], v[r]);
// N % k == (N - k) % k, discard the leftmost numbers
int get_random_integer_v2(int l, int h) {
uint32_t range = (h - l + 1);
uint32_t bound = -range % range;
auto x = rng();
while (x < bound) {
x = rng();
}
return l + (int)(x % range);
}
// Fisher-Yates shuffle [first, last)
template<typename T>
void shuffle_vector_old(std::vector<T>& v, int a = -1, int b = -1) {
if (a < 0)
a = 0;
if (b < 0)
b = (int)v.size() - 1;
for (int i = a; i < b; ++i) {
int r = get_random_integer_old(i, b);
void shuffle_vector(std::vector<T>& v, int first = 0, int last = INT32_MAX, int version = 2) {
if ((size_t)last > v.size())
last = v.size();
auto distribution = &mtrandom::get_random_integer_v2;
if (version == 1)
distribution = &mtrandom::get_random_integer_v1;
for (int i = first; i < last - 1; ++i) {
int r = (this->*distribution)(i, last - 1);
std::swap(v[i], v[r]);
}
}
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
newoption { trigger = "lua-dir", description = "", value = "PATH", default = "./lua" }
function GetParam(param)
return _OPTIONS[param] or os.getenv(string.upper(string.gsub(param,"-","_")))
end
LUA_DIR=GetParam("lua-dir")
if not os.isdir(LUA_DIR) then
LUA_DIR="../lua"
end
workspace "ocgcoredll"
location "build"
language "C++"
cppdialect "C++14"
configurations { "Release", "Debug" }
platforms { "x32", "x64" }
filter "platforms:x32"
architecture "x32"
filter "platforms:x64"
architecture "x64"
filter "configurations:Release"
optimize "Speed"
filter "configurations:Debug"
symbols "On"
defines "_DEBUG"
filter "system:windows"
systemversion "latest"
startproject "ocgcore"
filter { "configurations:Release", "action:vs*" }
linktimeoptimization "On"
staticruntime "On"
disablewarnings { "4146", "4334" }
filter "action:vs*"
cdialect "C11"
conformancemode "On"
buildoptions { "/utf-8" }
defines { "_CRT_SECURE_NO_WARNINGS" }
filter "system:bsd"
defines { "LUA_USE_POSIX" }
filter "system:macosx"
defines { "LUA_USE_MACOSX" }
filter "system:linux"
defines { "LUA_USE_LINUX" }
pic "On"
filter {}
include(LUA_DIR)
project "ocgcore"
kind "SharedLib"
cppdialect "C++14"
files { "*.cpp", "*.h" }
links { "lua" }
includedirs { LUA_DIR .. "/src" }
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment